Hold a wake lock during playback to reduce background playback stops - #5491
Hold a wake lock during playback to reduce background playback stops#5491joashrajin wants to merge 4 commits into
Conversation
Set a source-aware ExoPlayer wake mode (WAKE_MODE_LOCAL for downloaded, WAKE_MODE_NETWORK for streams) in SimplePlayer.prepare() so the player holds a wake lock for the duration of playback instead of the Media3 default WAKE_MODE_NONE. Without a wake lock the system can suspend the CPU / drop Wi-Fi and aggressively freeze or reclaim the foreground-service process during long uninterrupted background playback. This re-introduces only the setWakeMode line, decoupled from the audio offload code it was previously bundled with (added in #5059, reverted in #5105). The WAKE_LOCK permission is already declared. Related to PCDROID-555.
|
Claude finished @joashrajin's task in 1m 6s —— View job Code ReviewI reviewed the single-line change to
AssessmentThe change adds Correctness ✅
Permissions ✅ (with one thing to confirm)
Minor observations (non-blocking)
Testing History context Nice, focused change. The only thing I'd actively suggest before merge is confirming the |
|
Claude finished @joashrajin's task in 1m 44s —— View job Code Review
Reviewed the change in Correctness ✅
Minor considerations (non-blocking)
TestingAgree with the PR's stance that this isn't meaningfully unit-testable ( No changes requested — looks good to merge once on-device verification and |
SimplePlayer's ExoPlayer wake mode needs WAKE_LOCK. It already merged in transitively (via the analytics/localization modules), but declaring it in the module that actually uses it makes the requirement self-documenting and guarantees coverage for the app, wear, and automotive builds. Related to PCDROID-555.
|
Claude finished @joashrajin's task in 39s —— View job Code Review
This update addresses the one actionable item from the previous reviews: Looks correct and ready to merge (pending the on-device verification the PR description lays out). Correctness ✅
Manifest declaration ✅
Minor, unchanged from prior reviews (non-blocking)
TestingAgree this isn't meaningfully unit-testable ( No changes requested. |
Project manifest changes for automotiveThe following changes in the --- ./build/reports/diff_manifest/automotive/release/base_manifest.txt 2026-07-20 17:00:52.237010291 +0000
+++ ./build/reports/diff_manifest/automotive/release/head_manifest.txt 2026-07-20 17:00:53.529656831 +0000
@@ -61,8 +61,14 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- <uses-permission android:name="android.permission.INTERNET" />
+ <!--
+ Required by ExoPlayer's wake mode (SimplePlayer) to hold a wake lock
+ during background playback. Declared here, in the module that uses it,
+ so every consumer (app, wear, automotive) gets it without relying on
+ transitive merge from unrelated modules.
+ -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" />Go to https://buildkite.com/automattic/pocket-casts-android/builds/17738/canvas?sid=019f8077-cc16-4b8c-95d2-ad27a137edf8, click on the |
✅ On-device verificationBuilt this branch as a debug APK and drove it through the full wake-lock matrix on hardware. Device: Samsung SM-G990E (Galaxy S21 FE), Android 16 / SDK 36 — chosen deliberately because it hits both risk surfaces at once: PCDROID-555 reproduced on Android 16, and the reverted #5105 regression was Samsung-specific. Evidence captured via
Source-aware branch confirmed live: streaming took a partial wake lock + a Wi-Fi lock ( Clean acquire/release lifecycle, no leaked locks: Screen-off (Test 5) is the direct PCDROID-555 scenario: with the screen off and the process backgrounded, the partial wake lock stays held and playback keeps advancing — the CPU-suspend path is closed. Not covered here (needs a long soak)Two items from the Testing list require a multi-hour real-world session and were not exercised (I ran short episodes):
Everything mechanically assertable — lock acquisition, source-aware mode selection, release-on-pause, screen-off persistence, and absence of the #5105 regression on a Samsung — checks out. |
# Conflicts: # CHANGELOG.md # modules/services/repositories/src/main/AndroidManifest.xml
|
Claude finished @joashrajin's task in 51s —— View job Code Review
Re-reviewed now that the PR is out of draft and the on-device verification is in. This is correct, minimal, and ready to merge. The change re-introduces only the standard Media3 Correctness ✅
Manifest declaration ✅
Minor, non-blocking (unchanged from prior reviews)
TestingAgree this isn't meaningfully unit-testable ( The one honest caveat, already called out in the PR: the long multi-hour soak (full ~45-min uninterrupted playthrough + No changes requested. ✅ |
|
Version |
Description
Background playback of a long local Files episode can silently stop on its own (Pixel 6 / Android 16). The logs in PCDROID-555 show the system SIGKILLing the Pocket Casts foreground-service process mid-playback (
reason=2 SIGNALED status=9,importance=125), with frequentFREEZER/cached-app activity on surrounding days — not an internal pause or audio-focus loss.Root cause (closed gap): the background-audio
ExoPlayeris built with no wake mode set, so it defaults toWAKE_MODE_NONEand holds no wake lock during playback. That's the missing standard configuration for background audio — without a wake lock the system is free to suspend the CPU / drop Wi-Fi and aggressively freeze/reclaim the process during long uninterrupted playback.This sets a source-aware wake mode on the one background-audio player (
SimplePlayer, shared by both the Media3 and legacy service paths):WAKE_MODE_LOCAL(partial CPU wake lock) for downloaded/local episodes, andWAKE_MODE_NETWORK(partial wake lock + Wi-Fi lock) for streams.isStreamingis known at build time, theWAKE_LOCKpermission is already declared, and Media3 ties the lock to the playing state (it's released automatically on pause/stop), so there's no paused-but-locked battery drain.Changes
SimplePlayer.prepare()— add.setWakeMode(if (isStreaming) C.WAKE_MODE_NETWORK else C.WAKE_MODE_LOCAL)to theExoPlayer.Builderchain, with an explanatory comment. No manifest, import, or permission changes needed (Calready imported;WAKE_LOCKalready declared).Testing Instructions
adb shell dumpsys power | grep -i wakeshows a lock held by the package during playback.adb shell dumpsys wifi | grep -i lock).adb shell dumpsys activity exit-info <pkg>and confirm theSIGKILLduring playback no longer recurs (or recurs less often). If it still recurs, the residual cause is likely memory pressure — see follow-ups below.Not easily unit-testable: this is
ExoPlayer.Builderconfiguration that the Media3 API doesn't expose for assertion. Behaviour is validated on-device. Follow-ups if the kill persists after verification:onTrimMemoryhandling in the playback service and moving episode-metadata decode off the player thread (tracked separately, lower confidence).Screenshots or Screencast
n/a — no UI changes.
Checklist
./gradlew spotlessApplyto automatically apply formatting/linting)modules/services/localization/src/main/res/values/strings.xml— n/a (no strings)I have tested any UI changes...
n/a — this PR contains no UI changes.