ExoPlayer
ExoPlayer copied to clipboard
Crash in OfflineLicenseHelper
ExoPlayer Version
2.17.1
Devices that reproduce the issue
Any. devices.
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Yes
Reproduction steps
- In Widevine DASH (MP4, H264) -> HD (cenc) in
media.exolist.json, modify thedrm_license_uritohttps://proxy.uat.widevine.com/1234567890proxy?video_id=2015_tears&provider=widevine_testto force to receive 404 not found error. - Launch the demo app.
- Click the download button of Widevine DASH (MP4, H264) -> HD (cenc) in
media.exolist.json. - Do something (play other videos, seek video, download other media...)
- Repeat step 3 and 4.
Just call
OfflineLicenseHelper.downloadLicense()many times at the same time.
Expected result
offline license failure
Actual result
The app crashes with an NPE rarely (under 5%).
2022-06-10 20:53:52.899 30707-31080/com.google.android.exoplayer2.demo E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #11
Process: com.google.android.exoplayer2.demo, PID: 30707
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:415)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.NullPointerException
at com.google.android.exoplayer2.util.Assertions.checkNotNull(Assertions.java:154)
at com.google.android.exoplayer2.drm.OfflineLicenseHelper.blockingKeyRequest(OfflineLicenseHelper.java:277)
at com.google.android.exoplayer2.drm.OfflineLicenseHelper.downloadLicense(OfflineLicenseHelper.java:193)
at com.google.android.exoplayer2.demo.DownloadTracker$WidevineOfflineLicenseFetchTask.doInBackground(DownloadTracker.java:392)
at com.google.android.exoplayer2.demo.DownloadTracker$WidevineOfflineLicenseFetchTask.doInBackground(DownloadTracker.java:357)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
DefaultDrmSession.onError() changes its state after dispatching the error event and getError() returns null if the state is not STATE_ERROR.
public final DrmSessionException getError() {
return state == STATE_ERROR ? lastException : null;
}
private void onError(Exception e, @DrmUtil.ErrorSource int errorSource) {
lastException =
new DrmSessionException(e, DrmUtil.getErrorCodeForMediaDrmException(e, errorSource));
Log.e(TAG, "DRM session error", e);
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
if (state != STATE_OPENED_WITH_KEYS) {
state = STATE_ERROR;
}
}
In OfflineLicenseHelper.blockingKeyRequest(), both drmSession.getError() and drmSession.getOfflineKeySetId() returns null at the same time with a low probability.
DrmSessionException error = drmSession.getError();
byte[] keySetId = drmSession.getOfflineLicenseKeySetId();
// error == null && keySetId == null
Media
Widevine DASH (MP4, H264) -> HD (cenc) , modify the widevine license URL. (https://proxy.uat.widevine.com/pppppproxy?video_id=2015_tears&provider=widevine_test)
Bug Report
- [ ] You will email the zip file produced by
adb bugreportto [email protected] after filing this issue.
Thanks for reporting - I think this is a result of OfflineLicenseHelper constructing a Looper internally and passing that as the playbackLooper to DefaultDrmSessionManager#setPlayer. DefaultDrmSessionManager then expects every subsequent interaction to happen on this thread. OfflineLicenseHelper breaks this expectation when it directly calls DefaultDrmSessionManager#getError from whatever thread the OfflineLicenseHelper#downloadLicense is called from.
I'll have a think about the best way to resolve this.
Hi @icbaker We too have observed this crash. When and which version this fix is targeted?