From ab07288ba037d22872eebd9215a4c4ece1550af5 Mon Sep 17 00:00:00 2001 From: zvonimir Date: Tue, 17 Jun 2025 17:25:34 +0200 Subject: [PATCH] fix: timeoutMap being deadlocked --- .../engine/packages/PackageBridge.kt | 39 ++++++++----------- .../views/video/FutoVideoPlayerBase.kt | 2 +- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBridge.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBridge.kt index 858b020b..72bdf34f 100644 --- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBridge.kt +++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBridge.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import java.util.concurrent.ConcurrentHashMap class PackageBridge : V8Package { @Transient @@ -110,7 +111,7 @@ class PackageBridge : V8Package { } var timeoutCounter = 0; - var timeoutMap = HashSet(); + var timeoutMap = ConcurrentHashMap(); @V8Function fun setTimeout(func: V8ValueFunction, timeout: Long): Int { val id = timeoutCounter++; @@ -118,47 +119,39 @@ class PackageBridge : V8Package { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { delay(timeout); - if(_plugin.isStopped) + if (_plugin.isStopped) return@launch; - synchronized(timeoutMap) { - if(!timeoutMap.contains(id)) { - _plugin.busy { - if(!_plugin.isStopped) - JavetResourceUtils.safeClose(funcClone); - } - return@launch; + if (!timeoutMap.containsKey(id)) { + _plugin.busy { + if (!_plugin.isStopped) + JavetResourceUtils.safeClose(funcClone); } - timeoutMap.remove(id); + return@launch; } + timeoutMap.remove(id); try { _plugin.busy { - if(!_plugin.isStopped) + if (!_plugin.isStopped) funcClone.callVoid(null, arrayOf()); } - } - catch(ex: Throwable) { + } catch (ex: Throwable) { Logger.e(TAG, "Failed timeout callback", ex); - } - finally { + } finally { _plugin.busy { - if(!_plugin.isStopped) + if (!_plugin.isStopped) JavetResourceUtils.safeClose(funcClone); } //_plugin.whenNotBusy { //} } }; - synchronized(timeoutMap) { - timeoutMap.add(id); - } + timeoutMap.put(id, true); return id; } @V8Function fun clearTimeout(id: Int) { - synchronized(timeoutMap) { - if(timeoutMap.contains(id)) - timeoutMap.remove(id); - } + if (timeoutMap.containsKey(id)) + timeoutMap.remove(id); } @V8Function fun sleep(length: Int) { diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 6bd66ccb..43ed541d 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -580,7 +580,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); if(dataSource is JSHttpDataSource.Factory && videoSource is JSDashManifestMergingRawSource) - dataSource.setRequestExecutor2(videoSource.audio.getRequestExecutor()); + dataSource.setRequestExecutor2(withContext(Dispatchers.IO){videoSource.audio.getRequestExecutor()}); _lastVideoMediaSource = DashMediaSource.Factory(dataSource) .createMediaSource( DashManifestParser().parse(