The provisioning request and its response now run on the handler thread that resumes the pending session
operations, instead of on AsyncTask's shared executor followed by a post to the main thread. Resuming the
pending sessions stops when one of them restarts provisioning, so that the new request can run on the same
thread. A response arriving after release() is still dropped.
Details
- Reviewers
jolin jonalmeida - Group Reviewers
geckoview-reviewers - Commits
- rFIREFOXAUTOLAND5d688f0dd0f5: Bug 2079863 - Replace the deprecated AsyncTask in GeckoMediaDrmBridge. r=jolin…
- Bugzilla Bug ID
- 2079863
Diff Detail
- Repository
- rFIREFOXAUTOLAND firefox-autoland
Event Timeline
(Reviewing Diff 1400988)
The patch looks sound: I found nothing to flag. Responses still arrive on the main thread and are still dropped after release(), as before. The ThreadUtils.postToUiThread handoff also makes mResponseBody safely visible on the main thread. AsyncTask.cancel(true) also did nothing to stop an HttpURLConnection request already in flight, so losing the thread interrupt doesn't change behavior in practice. A dedicated thread is also an improvement: a stalled request no longer blocks the app-wide serial AsyncTask executor.
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 555 | cancel() now only sets a flag, so after release() the in-flight provisioning POST keeps running until it finishes or times out. During that time the worker thread keeps holding the bridge, because PostRequestTask is still a non-static inner class. The old cancel(true) at least interrupted the thread. To actually abort the request, save the HttpURLConnection in a volatile field and call disconnect() on it from cancel(). Also check mCancelled in run() before posting to the UI thread. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 555 | Keeping this as is: cancel(true) interrupted the thread, but an interrupt doesn't abort blocking HttpURLConnection I/O, so the old task also ran the POST to completion or timeout. The posted result checks mCancelled before touching the bridge. | |
Happy to re-review if the comment makes sense.
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 726 | We don't need a new thread that later creates a separate thread to resume tasks (resumePendingOperations). Can we re-purpose our existing handler so that we can provision first (making sure that mHandler has a thread created first, before resumePendingOperations? | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 726 | To clarify, my understanding is that the provisioning task is dependant on the pending operations task, so we can make them sequential on the same thread without creating a second one. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 726 | Provisioning now runs on mHandler's thread, and the pending operations follow it there. Because they share that thread now, resuming the pending sessions stops when one of them restarts provisioning, so the new provisioning request isn't stuck behind them. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 609–611 | There is a check-then-act race between this mCancelled check and release(). release() runs on another thread, the caller's binder thread via RemoteMediaDrmBridgeStub/MediaDrmProxy, not on PendingSessionOpsThread. If it runs after the check passes, onProvisionResponse() keeps going while the bridge is torn down:
Fix by making delivery and teardown mutually exclusive. Either run release()'s teardown on the handler thread, or guard the mCancelled check plus onProvisionResponse() and the cancel/teardown in release() with the same lock. Also make getHandler() refuse to recreate the thread once released. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 609–611 | Worth doing, but adding it as a third patch on the stack rather than scope-creeping this one more. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 609–611 | There is a check-then-act race here. release() gets called on the binder thread (RemoteMediaDrmBridgeStub.release()), while this code runs on PendingSessionOpsThread. If release() runs after the mCancelled check but before or during onProvisionResponse(), two things can go wrong:
The volatile flag doesn't give the "late response is ignored" guarantee. Make the cancel and the delivery atomic: for example, guard both release() and this check-and-deliver block with the same lock, or recheck mDrm/cancellation under that lock inside onProvisionResponse(). Also make getHandler() refuse to recreate the thread after release. | |
| mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridge.java | ||
|---|---|---|
| 609–611 | Same reply as the last time you brought this up. | |