commit 759840bd10a9f468b15bf14149dbe4f5bbe76640
parent d79610e29ec623e17880811960995c6b85f07843
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sat,  3 Feb 2024 18:47:41 +0100

fix(core): BridgeClient safe calls

Diffstat:
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 66 insertions(+), 29 deletions(-)

diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/bridge/BridgeClient.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.Build +import android.os.DeadObjectException import android.os.Handler import android.os.HandlerThread import android.os.IBinder @@ -105,66 +106,102 @@ class BridgeClient( exitProcess(0) } - fun broadcastLog(tag: String, level: String, message: String) = service.broadcastLog(tag, level, message) + private fun <T> safeServiceCall(block: () -> T): T { + return runCatching { + block() + }.getOrElse { + context.log.error("failed to call service", it) + if (it is DeadObjectException) { + context.softRestartApp() + } + throw it + } + } + + fun broadcastLog(tag: String, level: String, message: String) { + safeServiceCall { service.broadcastLog(tag, level, message) } + } //TODO: use interfaces instead of direct file access fun createAndReadFile( fileType: BridgeFileType, defaultContent: ByteArray - ): ByteArray = service.fileOperation(FileActionType.CREATE_AND_READ.ordinal, fileType.value, defaultContent) + ): ByteArray = safeServiceCall { + service.fileOperation(FileActionType.CREATE_AND_READ.ordinal, fileType.value, defaultContent) + } - fun readFile(fileType: BridgeFileType): ByteArray = service.fileOperation(FileActionType.READ.ordinal, fileType.value, null) + fun readFile(fileType: BridgeFileType): ByteArray = safeServiceCall { service.fileOperation(FileActionType.READ.ordinal, fileType.value, null) } fun writeFile( fileType: BridgeFileType, content: ByteArray? - ) { service.fileOperation(FileActionType.WRITE.ordinal, fileType.value, content) } + ): ByteArray = safeServiceCall { + service.fileOperation(FileActionType.WRITE.ordinal, fileType.value, content) + } - fun deleteFile(fileType: BridgeFileType) { service.fileOperation(FileActionType.DELETE.ordinal, fileType.value, null) } + fun deleteFile(fileType: BridgeFileType) { + safeServiceCall { + service.fileOperation(FileActionType.DELETE.ordinal, fileType.value, null) + } + } - fun isFileExists(fileType: BridgeFileType) = service.fileOperation(FileActionType.EXISTS.ordinal, fileType.value, null).isNotEmpty() + fun isFileExists(fileType: BridgeFileType) = safeServiceCall { + service.fileOperation(FileActionType.EXISTS.ordinal, fileType.value, null).isNotEmpty() + } - fun fetchLocales(userLocale: String) = service.fetchLocales(userLocale).map { - LocalePair(it.key, it.value) + fun fetchLocales(userLocale: String) = safeServiceCall { + service.fetchLocales(userLocale).map { + LocalePair(it.key, it.value) + } } - fun getApplicationApkPath(): String = service.getApplicationApkPath() + fun getApplicationApkPath(): String = safeServiceCall { service.getApplicationApkPath() } - fun enqueueDownload(intent: Intent, callback: DownloadCallback) = service.enqueueDownload(intent, callback) + fun enqueueDownload(intent: Intent, callback: DownloadCallback) = safeServiceCall { + service.enqueueDownload(intent, callback) + } fun sync(callback: SyncCallback) { if (!context.database.hasMain()) return - service.sync(callback) + safeServiceCall { + service.sync(callback) + } } - fun triggerSync(scope: SocialScope, id: String) = service.triggerSync(scope.key, id) + fun triggerSync(scope: SocialScope, id: String) = safeServiceCall { + service.triggerSync(scope.key, id) + } - fun passGroupsAndFriends(groups: List<MessagingGroupInfo>, friends: List<MessagingFriendInfo>) = service.passGroupsAndFriends( - groups.mapNotNull { it.toSerialized() }, - friends.mapNotNull { it.toSerialized() } - ) + fun passGroupsAndFriends(groups: List<MessagingGroupInfo>, friends: List<MessagingFriendInfo>) = + safeServiceCall { + service.passGroupsAndFriends( + groups.mapNotNull { it.toSerialized() }, + friends.mapNotNull { it.toSerialized() } + ) + } - fun getRules(targetUuid: String): List<MessagingRuleType> { - return service.getRules(targetUuid).mapNotNull { MessagingRuleType.getByName(it) } + fun getRules(targetUuid: String): List<MessagingRuleType> = safeServiceCall { + service.getRules(targetUuid).mapNotNull { MessagingRuleType.getByName(it) } } - fun getRuleIds(ruleType: MessagingRuleType): List<String> { - return service.getRuleIds(ruleType.key) + fun getRuleIds(ruleType: MessagingRuleType): List<String> = safeServiceCall { + service.getRuleIds(ruleType.key) } - fun setRule(targetUuid: String, type: MessagingRuleType, state: Boolean) - = service.setRule(targetUuid, type.key, state) + fun setRule(targetUuid: String, type: MessagingRuleType, state: Boolean) = safeServiceCall { + service.setRule(targetUuid, type.key, state) + } - fun getScriptingInterface(): IScripting = service.getScriptingInterface() + fun getScriptingInterface(): IScripting = safeServiceCall { service.getScriptingInterface() } - fun getE2eeInterface(): E2eeInterface = service.getE2eeInterface() + fun getE2eeInterface(): E2eeInterface = safeServiceCall { service.getE2eeInterface() } - fun getMessageLogger(): MessageLoggerInterface = service.messageLogger + fun getMessageLogger(): MessageLoggerInterface = safeServiceCall { service.messageLogger } - fun registerMessagingBridge(bridge: MessagingBridge) = service.registerMessagingBridge(bridge) + fun registerMessagingBridge(bridge: MessagingBridge) = safeServiceCall { service.registerMessagingBridge(bridge) } - fun openSettingsOverlay() = service.openSettingsOverlay() - fun closeSettingsOverlay() = service.closeSettingsOverlay() + fun openSettingsOverlay() = safeServiceCall { service.openSettingsOverlay() } + fun closeSettingsOverlay() = safeServiceCall { service.closeSettingsOverlay() } - fun registerConfigStateListener(listener: ConfigStateListener) = service.registerConfigStateListener(listener) + fun registerConfigStateListener(listener: ConfigStateListener) = safeServiceCall { service.registerConfigStateListener(listener) } }