The Race condition in HlsDownloader leading to ConcurrentModificationException & NPE ocurred after update from v2.6.4 to v2.6.9.
Currently, the HlsDownloader#createDownloadTasks function can be called from 2 places which are run in 2 separate Threads.
- On track selection from
TrackSelectorImp.apply, which uses AsyncTasks sDefaultExecutor.
- Download services after metadata completes, which uses a
ThreadPoolExecutor to invoke HlsDownloader#createDownloadTasks further down the stack via AbrDownloader#apply call.
The race condition appeared after metadata fetching was moved to a dedicated ThreadPoolExecutor from AsyncTasks sDefaultExecutor which was reused reusing the same Thread for both calls.
Steps to reproduce
- Start download.
- Change track selection at the time when metadata loading finishes.
Expected Results
The download should start.
Actual Results
The following exceptions are thrown from dtg:
Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.kaltura.dtg.hls.HlsDownloader.createDownloadTasks(HlsDownloader.java:88)
at com.kaltura.dtg.AbrDownloader.applyInitialTrackSelection(AbrDownloader.java:122)
at com.kaltura.dtg.hls.HlsDownloader.applyInitialTrackSelection(HlsDownloader.java:297)
at com.kaltura.dtg.AbrDownloader.apply(AbrDownloader.java:235)
at com.kaltura.dtg.TrackSelectorImp.lambda$apply$0(TrackSelectorImp.java:39)
at com.kaltura.dtg.TrackSelectorImp.lambda$apply$0$TrackSelectorImp(TrackSelectorImp.java)
at com.kaltura.dtg.-$$Lambda$TrackSelectorImp$nlSaArBap0OhKxA2tNBRIKRHnbY.run(-.java:4)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
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:919)
Fatal Exception: java.lang.NullPointerException: Attempt to read from field 'int i.n.b.b1.a$b.a' on a null object reference
at com.kaltura.dtg.hls.HlsDownloader.createDownloadTasks(HlsDownloader.java:90)
at com.kaltura.dtg.AbrDownloader.applyInitialTrackSelection(AbrDownloader.java:122)
at com.kaltura.dtg.hls.HlsDownloader.applyInitialTrackSelection(HlsDownloader.java:297)
at com.kaltura.dtg.AbrDownloader.apply(AbrDownloader.java:235)
at com.kaltura.dtg.TrackSelectorImp.lambda$apply$0(TrackSelectorImp.java:39)
at com.kaltura.dtg.TrackSelectorImp.lambda$apply$0$TrackSelectorImp(TrackSelectorImp.java)
at com.kaltura.dtg.-$$Lambda$TrackSelectorImp$nlSaArBap0OhKxA2tNBRIKRHnbY.run(-.java:4)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
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:919)
The Race condition in HlsDownloader leading to ConcurrentModificationException & NPE ocurred after update from v2.6.4 to v2.6.9.
Currently, the
HlsDownloader#createDownloadTasksfunction can be called from 2 places which are run in 2 separate Threads.TrackSelectorImp.apply, which uses AsyncTaskssDefaultExecutor.playkit-dtg-android/dtglib/src/main/java/com/kaltura/dtg/TrackSelectorImp.java
Line 39 in d92e41e
ThreadPoolExecutorto invokeHlsDownloader#createDownloadTasksfurther down the stack viaAbrDownloader#applycall.playkit-dtg-android/dtglib/src/main/java/com/kaltura/dtg/DownloadService.java
Line 395 in d92e41e
playkit-dtg-android/dtglib/src/main/java/com/kaltura/dtg/AbrDownloader.java
Line 93 in d92e41e
The race condition appeared after metadata fetching was moved to a dedicated
ThreadPoolExecutorfrom AsyncTaskssDefaultExecutorwhich was reused reusing the same Thread for both calls.Steps to reproduce
Expected Results
The download should start.
Actual Results
The following exceptions are thrown from dtg: