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

Verified Commit 1deeb458 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

EN: Make database access suspendable, add migration routine for oversized databases

parent c4b480c5
Loading
Loading
Loading
Loading
+20 −17
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ package org.microg.gms.nearby.core.ui
import android.content.Intent
import android.os.Bundle
import android.text.format.DateUtils
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import org.json.JSONObject
@@ -48,7 +49,8 @@ class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {

    fun updateContent() {
        packageName?.let { packageName ->
            ExposureDatabase.with(requireContext()) { database ->
            lifecycleScope.launchWhenResumed {
                checks.summary = ExposureDatabase.with(requireContext()) { database ->
                    var str = getString(R.string.pref_exposure_app_checks_summary, database.countMethodCalls(packageName, "provideDiagnosisKeys"))
                    val lastCheckTime = database.lastMethodCall(packageName, "provideDiagnosisKeys")
                    if (lastCheckTime != null && lastCheckTime != 0L) {
@@ -67,7 +69,8 @@ class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {
                        } catch (ignored: Exception) {
                        }
                    }
                checks.summary = str
                    str
                }
            }
        }
    }
+18 −20
Original line number Diff line number Diff line
@@ -74,8 +74,7 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
        lifecycleScope.launchWhenResumed {
            handler.postDelayed(updateContentRunnable, UPDATE_CONTENT_INTERVAL)
            val context = requireContext()
            val (apps, lastHourKeys, currentId) = withContext(Dispatchers.IO) {
                ExposureDatabase.with(context) { database ->
            val (apps, lastHourKeys, currentId) = ExposureDatabase.with(context) { database ->
                val apps = database.appList.map { packageName ->
                    context.packageManager.getApplicationInfoIfExists(packageName)
                }.filterNotNull().mapIndexed { idx, applicationInfo ->
@@ -96,7 +95,6 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
                val currentId = database.currentRpiId
                Triple(apps, lastHourKeys, currentId)
            }
            }
            collectedRpis.summary = getString(R.string.pref_exposure_collected_rpis_summary, lastHourKeys)
            if (currentId != null) {
                advertisingId.isVisible = true
+23 −24
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ import kotlinx.coroutines.withContext
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
import java.util.*
import kotlin.math.roundToInt
import kotlin.math.roundToLong

@TargetApi(21)
class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
@@ -39,10 +40,9 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {

    fun updateChart() {
        lifecycleScope.launchWhenResumed {
            val (totalRpiCount, rpiHistogram) = withContext(Dispatchers.IO) {
                ExposureDatabase.with(requireContext()) { database ->
            val (totalRpiCount, rpiHistogram) = ExposureDatabase.with(requireContext()) { database ->
                val map = linkedMapOf<String, Float>()
                    val lowestDate = Math.round((System.currentTimeMillis() / 24 / 60 / 60 / 1000 - 13).toDouble()) * 24 * 60 * 60 * 1000
                val lowestDate = (System.currentTimeMillis() / 24 / 60 / 60 / 1000 - 13).toDouble().roundToLong() * 24 * 60 * 60 * 1000
                for (i in 0..13) {
                    val date = Calendar.getInstance().apply { this.time = Date(lowestDate + i * 24 * 60 * 60 * 1000) }.get(Calendar.DAY_OF_MONTH)
                    val str = when (i) {
@@ -66,7 +66,6 @@ class ExposureNotificationsRpisFragment : PreferenceFragmentCompat() {
                val totalRpiCount = database.totalRpiCount
                totalRpiCount to map
            }
            }
            histogramCategory.title = getString(R.string.prefcat_exposure_rpis_histogram_title, totalRpiCount)
            histogram.labelsFormatter = { it.roundToInt().toString() }
            histogram.scale = Scale(0f, rpiHistogram.values.max()?.coerceAtLeast(0.1f) ?: 0.1f)
+69 −57
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.*
import android.util.Log
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.microg.gms.common.ForegroundServiceContext
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -27,7 +31,7 @@ import java.nio.ByteBuffer
import java.util.*

@TargetApi(21)
class AdvertiserService : Service() {
class AdvertiserService : LifecycleService() {
    private val version = VERSION_1_0
    private var advertising = false
    private var wantStartAdvertising = false
@@ -84,13 +88,13 @@ class AdvertiserService : Service() {
        handler.removeCallbacks(startLaterRunnable)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    fun startAdvertisingIfNeeded() {
    private fun startAdvertisingIfNeeded() {
        if (ExposurePreferences(this).enabled) {
            lifecycleScope.launchWhenStarted {
                withContext(Dispatchers.IO) {
                    startAdvertising()
                }
            }
        } else {
            stopSelf()
        }
@@ -98,12 +102,17 @@ class AdvertiserService : Service() {

    private var lastStartTime = System.currentTimeMillis()
    private var sendingBytes = ByteArray(0)
    private var starting = false

    @Synchronized
    fun startAdvertising() {
        if (advertising) return
    private suspend fun startAdvertising() {
        val advertiser = synchronized(this) {
            if (advertising || starting) return
            val advertiser = advertiser ?: return
            wantStartAdvertising = false
            starting = true
            advertiser
        }
        try {
            val aemBytes = when (version) {
                VERSION_1_0 -> byteArrayOf(
                        version, // Version and flags
@@ -145,10 +154,13 @@ class AdvertiserService : Service() {
                        .build()
                advertiser.startAdvertising(settings, data, callback)
            }
        advertising = true
            synchronized(this) { advertising = true }
            sendingBytes = payload
            lastStartTime = System.currentTimeMillis()
            scheduleRestartAdvertising(nextSend)
        } finally {
            synchronized(this) { starting = false }
        }
    }

    override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
@@ -182,7 +194,7 @@ class AdvertiserService : Service() {
    }

    @Synchronized
    fun stopOrRestartAdvertising() {
    private fun stopOrRestartAdvertising() {
        if (!advertising) return
        val (uuid, _) = ByteBuffer.wrap(sendingBytes).let { UUID(it.long, it.long) to it.int }
        Log.i(TAG, "Stopping advertiser for RPI $uuid")
+2 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.microg.gms.common.ForegroundServiceContext

class CleanupService : LifecycleService() {
@@ -22,7 +23,7 @@ class CleanupService : LifecycleService() {
        super.onStartCommand(intent, flags, startId)
        if (isNeeded(this)) {
            lifecycleScope.launchWhenStarted {
                launch(Dispatchers.IO) {
                withContext(Dispatchers.IO) {
                    var workPending = true
                    while (workPending) {
                        ExposureDatabase.with(this@CleanupService) {
Loading