android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,36 @@
|
||||
The session, the player, the notification provider, the audio-focus request
|
||||
and the becoming-noisy receiver all live in `MediaHub` for the life of the
|
||||
**process**, and `MediaService.onCreate` allocates and registers nothing. That
|
||||
is not tidiness, it is androidx/media
|
||||
[#3158](https://github.com/androidx/media/issues/3158) — open since
|
||||
2026-04-03, still open, reproduced on media3 1.11.0: a host that binds a
|
||||
`MediaLibraryService` while nothing is playing can put the service into an
|
||||
`onCreate → onBind → onGetSession → onConnect → onDestroy` loop at about
|
||||
thirty cycles a second, and it is 100% reproducible after a force-stop with
|
||||
no existing binding, which is exactly how Android Auto and
|
||||
`tools/auto-prober/` connect. The loop is Android Auto's to fix and media3
|
||||
has said it will not act first, so it cannot be fixed from here — only made
|
||||
harmless, by making a cycle cost nothing. Round forty-eight's
|
||||
`onCreate`/`onDestroy` would have built a platform session and a legacy
|
||||
browser stub thirty times a second, registered and unregistered a broadcast
|
||||
receiver sixty times a second, and abandoned audio focus thirty times a
|
||||
second *while music was playing*.
|
||||
|
||||
Three consequences, and each is a trap for the next round. `onDestroy`
|
||||
calls `removeSession`, never `release()`: `removeSession` drops the session
|
||||
from that instance's map and clears its listener, which is what stops a
|
||||
destroyed service being called back, while `SoulStreamPlayer.markReleased()`
|
||||
would latch `released = true` and leave a process-lifetime player that never
|
||||
updates the card again. The session is built with
|
||||
`MediaLibrarySession.Builder(applicationContext, …)` and not the
|
||||
`(MediaLibraryService, …)` overload, because
|
||||
`MediaSessionServiceLegacyStub.initialize()` does
|
||||
`attachToBaseContext(sessionImpl.getContext())` — a session built against the
|
||||
Service pins a destroyed Service as the base context of a live
|
||||
`MediaBrowserServiceCompat`. And nothing releases the session at all any
|
||||
more, so it and its platform `MediaSessionCompat` live until the process
|
||||
dies; the walk's `one-session` check is what keeps that honest.
|
||||
|
||||
`MediaService.onCreate` logs `auto service created n=…` and `onDestroy` logs
|
||||
`auto service destroyed`. Those two lines are the only way to count the loop
|
||||
on a real phone — see "### The Auto prober".
|
||||
Reference in new issue
Block a user