Crash in OfflineLicenseHelper
- Dominant language
- Java
- Stars
- 21.9k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
### 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
1. In _Widevine DASH (MP4, H264)_ -> _HD (cenc)_ in `media.exolist.json`, modify the `drm_license_uri` to `https://proxy.uat.widevine.com/1234567890proxy?video_id=2015_tears&provider=widevine_test` to force to receive 404 not found error.
2. Launch the demo app.
3. Click the download button of _Widevine DASH (MP4, H264)_ -> _HD (cenc)_ in `media.exolist.json`.
4. Do something (play other videos, seek video, download other media...)
5. 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.
``` java
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.
``` java
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 bugreport` to dev.exoplayer@gmail.com after filing this issue.
Contributor guide
Assessment
This issue has not been assessed yet.