Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit 91c8e43a authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

EN: Make service more robust against exceptions while processing app input

parent 45d4dffb
Loading
Loading
Loading
Loading
+36 −27
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ import android.content.*
import android.os.*
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.common.api.Status
@@ -19,6 +20,8 @@ import com.google.android.gms.nearby.exposurenotification.*
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.*
import com.google.android.gms.nearby.exposurenotification.internal.*
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.withTimeout
import org.json.JSONArray
import org.json.JSONObject
@@ -37,6 +40,8 @@ import kotlin.random.Random

class ExposureNotificationServiceImpl(private val context: Context, private val lifecycle: Lifecycle, private val packageName: String) : INearbyExposureNotificationService.Stub(), LifecycleOwner {

    private fun LifecycleCoroutineScope.launchSafely(block: suspend CoroutineScope.() -> Unit): Job = launchWhenStarted { try { block() } catch (e: Exception) { Log.w(TAG, "Error in coroutine", e) } }

    override fun getLifecycle(): Lifecycle = lifecycle

    private fun pendingConfirm(permission: String): PendingIntent {
@@ -102,7 +107,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun start(params: StartParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val isAuthorized = ExposureDatabase.with(context) { it.isAppAuthorized(packageName) }
            val adapter = BluetoothAdapter.getDefaultAdapter()
            val status = if (isAuthorized && ExposurePreferences(context).enabled) {
@@ -131,7 +136,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun stop(params: StopParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val isAuthorized = ExposureDatabase.with(context) { database ->
                database.isAppAuthorized(packageName).also {
                    if (it) database.noteAppAction(packageName, "stop")
@@ -149,7 +154,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun isEnabled(params: IsEnabledParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val isAuthorized = ExposureDatabase.with(context) { database ->
                database.isAppAuthorized(packageName)
            }
@@ -162,7 +167,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getTemporaryExposureKeyHistory(params: GetTemporaryExposureKeyHistoryParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val status = confirmPermission(CONFIRM_ACTION_KEYS)
            val response = when {
                status.isSuccess -> ExposureDatabase.with(context) { database ->
@@ -243,7 +248,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    override fun provideDiagnosisKeys(params: ProvideDiagnosisKeysParams) {
        val token = params.token ?: TOKEN_A
        Log.w(TAG, "provideDiagnosisKeys() with $packageName/$token")
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val tid = ExposureDatabase.with(context) { database ->
                val configuration = params.configuration
                if (configuration != null) {
@@ -259,7 +264,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
                } catch (e: Exception) {
                    Log.w(TAG, "Callback failed", e)
                }
                return@launchWhenStarted
                return@launchSafely
            }
            ExposureDatabase.with(context) { database ->
                val start = System.currentTimeMillis()
@@ -289,6 +294,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
                }
                params.keyFileSupplier?.let { keyFileSupplier ->
                    Log.d(TAG, "Using key file supplier")
                    try {
                        while (keyFileSupplier.isAvailable && keyFileSupplier.hasNext()) {
                            try {
                                val cacheFile = File(context.cacheDir, "en-keyfile-${System.currentTimeMillis()}-${Random.nextInt()}.zip")
@@ -305,6 +311,9 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
                                Log.w(TAG, "Failed parsing file", e)
                            }
                        }
                    } catch (e: Exception) {
                        Log.w(TAG, "Disconnected from key file supplier", e)
                    }
                }

                if (todoKeyFiles.size > 0) {
@@ -389,7 +398,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getExposureSummary(params: GetExposureSummaryParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val response = buildExposureSummary(params.token)

            ExposureDatabase.with(context) { database ->
@@ -413,7 +422,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getExposureInformation(params: GetExposureInformationParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            ExposureDatabase.with(context) { database ->
                val pair = database.loadConfiguration(packageName, params.token)
                val response = if (pair != null && database.isAppAuthorized(packageName)) {
@@ -494,7 +503,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getExposureWindows(params: GetExposureWindowsParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val response = getExposureWindowsInternal(params.token ?: TOKEN_A)

            ExposureDatabase.with(context) { database ->
@@ -529,7 +538,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getDailySummaries(params: GetDailySummariesParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val response = getExposureWindowsInternal().groupBy { it.dateMillisSinceEpoch }.map {
                val map = arrayListOf<DailySummary.ExposureSummaryData>()
                for (i in 0 until ReportType.VALUES) {
@@ -564,7 +573,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun setDiagnosisKeysDataMapping(params: SetDiagnosisKeysDataMappingParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            ExposureDatabase.with(context) { database ->
                database.storeConfiguration(packageName, TOKEN_A, params.mapping)
                database.noteAppAction(packageName, "setDiagnosisKeysDataMapping")
@@ -578,7 +587,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
    }

    override fun getDiagnosisKeysDataMapping(params: GetDiagnosisKeysDataMappingParams) {
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            val mapping = ExposureDatabase.with(context) { database ->
                val triple = database.loadConfiguration(packageName, TOKEN_A)
                database.noteAppAction(packageName, "getDiagnosisKeysDataMapping")
@@ -594,7 +603,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val

    override fun getPackageConfiguration(params: GetPackageConfigurationParams) {
        Log.w(TAG, "Not yet implemented: getPackageConfiguration")
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            ExposureDatabase.with(context) { database ->
                database.noteAppAction(packageName, "getPackageConfiguration")
            }
@@ -608,7 +617,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val

    override fun getStatus(params: GetStatusParams) {
        Log.w(TAG, "Not yet implemented: getStatus")
        lifecycleScope.launchWhenStarted {
        lifecycleScope.launchSafely {
            ExposureDatabase.with(context) { database ->
                database.noteAppAction(packageName, "getStatus")
            }