mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-11-16 16:25:12 +00:00
EN: Improve database performance
This commit is contained in:
parent
d6b9d2e44c
commit
f48298b1f6
2 changed files with 79 additions and 43 deletions
|
@ -33,6 +33,11 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
setWriteAheadLoggingEnabled(true)
|
setWriteAheadLoggingEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onConfigure(db: SQLiteDatabase) {
|
||||||
|
super.onConfigure(db)
|
||||||
|
db.setForeignKeyConstraintsEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(db: SQLiteDatabase) {
|
override fun onCreate(db: SQLiteDatabase) {
|
||||||
onUpgrade(db, 0, DB_VERSION)
|
onUpgrade(db, 0, DB_VERSION)
|
||||||
}
|
}
|
||||||
|
@ -66,6 +71,8 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dailyCleanup() = writableDatabase.run {
|
fun dailyCleanup() = writableDatabase.run {
|
||||||
|
beginTransaction()
|
||||||
|
try {
|
||||||
val rollingStartTime = currentRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
|
val rollingStartTime = currentRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
|
||||||
val advertisements = delete(TABLE_ADVERTISEMENTS, "timestamp < ?", longArrayOf(rollingStartTime))
|
val advertisements = delete(TABLE_ADVERTISEMENTS, "timestamp < ?", longArrayOf(rollingStartTime))
|
||||||
val appLogEntries = delete(TABLE_APP_LOG, "timestamp < ?", longArrayOf(rollingStartTime))
|
val appLogEntries = delete(TABLE_APP_LOG, "timestamp < ?", longArrayOf(rollingStartTime))
|
||||||
|
@ -73,6 +80,10 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
val checkedTemporaryExposureKeys = delete(TABLE_TEK_CHECK, "(rollingStartNumber + rollingPeriod) < ?", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS))
|
val checkedTemporaryExposureKeys = delete(TABLE_TEK_CHECK, "(rollingStartNumber + rollingPeriod) < ?", longArrayOf(rollingStartTime / ROLLING_WINDOW_LENGTH_MS))
|
||||||
val appPerms = delete(TABLE_APP_PERMS, "timestamp < ?", longArrayOf(System.currentTimeMillis() - CONFIRM_PERMISSION_VALIDITY))
|
val appPerms = delete(TABLE_APP_PERMS, "timestamp < ?", longArrayOf(System.currentTimeMillis() - CONFIRM_PERMISSION_VALIDITY))
|
||||||
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv, $appLogEntries applogs, $temporaryExposureKeys teks, $checkedTemporaryExposureKeys cteks, $appPerms perms")
|
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv, $appLogEntries applogs, $temporaryExposureKeys teks, $checkedTemporaryExposureKeys cteks, $appPerms perms")
|
||||||
|
setTransactionSuccessful()
|
||||||
|
} finally {
|
||||||
|
endTransaction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun grantPermission(packageName: String, signatureDigest: String, permission: String, timestamp: Long = System.currentTimeMillis()) = writableDatabase.run {
|
fun grantPermission(packageName: String, signatureDigest: String, permission: String, timestamp: Long = System.currentTimeMillis()) = writableDatabase.run {
|
||||||
|
@ -129,16 +140,15 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun storeOwnKey(key: TemporaryExposureKey): TemporaryExposureKey = writableDatabase.run {
|
private fun storeOwnKey(key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
insert(TABLE_TEK, "NULL", ContentValues().apply {
|
insert(TABLE_TEK, "NULL", ContentValues().apply {
|
||||||
put("keyData", key.keyData)
|
put("keyData", key.keyData)
|
||||||
put("rollingStartNumber", key.rollingStartIntervalNumber)
|
put("rollingStartNumber", key.rollingStartIntervalNumber)
|
||||||
put("rollingPeriod", key.rollingPeriod)
|
put("rollingPeriod", key.rollingPeriod)
|
||||||
})
|
})
|
||||||
key
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTekCheckId(key: TemporaryExposureKey, mayInsert: Boolean = false): Long? = (if (mayInsert) writableDatabase else readableDatabase).run {
|
private fun getTekCheckId(key: TemporaryExposureKey, mayInsert: Boolean = false, database: SQLiteDatabase = if (mayInsert) writableDatabase else readableDatabase): Long? = database.run {
|
||||||
if (mayInsert) {
|
if (mayInsert) {
|
||||||
insertWithOnConflict(TABLE_TEK_CHECK, "NULL", ContentValues().apply {
|
insertWithOnConflict(TABLE_TEK_CHECK, "NULL", ContentValues().apply {
|
||||||
put("keyData", key.keyData)
|
put("keyData", key.keyData)
|
||||||
|
@ -154,8 +164,8 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun storeDiagnosisKey(packageName: String, token: String, key: TemporaryExposureKey) = writableDatabase.run {
|
fun storeDiagnosisKey(packageName: String, token: String, key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
val tcid = getTekCheckId(key, true)
|
val tcid = getTekCheckId(key, true, database)
|
||||||
insert(TABLE_DIAGNOSIS, "NULL", ContentValues().apply {
|
insert(TABLE_DIAGNOSIS, "NULL", ContentValues().apply {
|
||||||
put("package", packageName)
|
put("package", packageName)
|
||||||
put("token", token)
|
put("token", token)
|
||||||
|
@ -164,8 +174,18 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDiagnosisKey(packageName: String, token: String, key: TemporaryExposureKey) = writableDatabase.run {
|
fun batchStoreDiagnosisKey(packageName: String, token: String, keys: List<TemporaryExposureKey>, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
val tcid = getTekCheckId(key) ?: return 0
|
beginTransaction()
|
||||||
|
try {
|
||||||
|
keys.forEach { storeDiagnosisKey(packageName, token, it, database) }
|
||||||
|
setTransactionSuccessful()
|
||||||
|
} finally {
|
||||||
|
endTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDiagnosisKey(packageName: String, token: String, key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
|
val tcid = getTekCheckId(key, false, database) ?: return 0
|
||||||
compileStatement("UPDATE $TABLE_DIAGNOSIS SET transmissionRiskLevel = ? WHERE package = ? AND token = ? AND tcid = ?;").use {
|
compileStatement("UPDATE $TABLE_DIAGNOSIS SET transmissionRiskLevel = ? WHERE package = ? AND token = ? AND tcid = ?;").use {
|
||||||
it.bindLong(1, key.transmissionRiskLevel.toLong())
|
it.bindLong(1, key.transmissionRiskLevel.toLong())
|
||||||
it.bindString(2, packageName)
|
it.bindString(2, packageName)
|
||||||
|
@ -175,7 +195,17 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun listDiagnosisKeysPendingSearch(packageName: String, token: String) = readableDatabase.run {
|
fun batchUpdateDiagnosisKey(packageName: String, token: String, keys: List<TemporaryExposureKey>, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
|
beginTransaction()
|
||||||
|
try {
|
||||||
|
keys.forEach { updateDiagnosisKey(packageName, token, it, database) }
|
||||||
|
setTransactionSuccessful()
|
||||||
|
} finally {
|
||||||
|
endTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listDiagnosisKeysPendingSearch(packageName: String, token: String, database: SQLiteDatabase = readableDatabase) = database.run {
|
||||||
rawQuery("""
|
rawQuery("""
|
||||||
SELECT $TABLE_TEK_CHECK.keyData, $TABLE_TEK_CHECK.rollingStartNumber, $TABLE_TEK_CHECK.rollingPeriod
|
SELECT $TABLE_TEK_CHECK.keyData, $TABLE_TEK_CHECK.rollingStartNumber, $TABLE_TEK_CHECK.rollingPeriod
|
||||||
FROM $TABLE_DIAGNOSIS
|
FROM $TABLE_DIAGNOSIS
|
||||||
|
@ -197,7 +227,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyDiagnosisKeySearchResult(key: TemporaryExposureKey, matched: Boolean) = writableDatabase.run {
|
private fun applyDiagnosisKeySearchResult(key: TemporaryExposureKey, matched: Boolean, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||||
compileStatement("UPDATE $TABLE_TEK_CHECK SET matched = ? WHERE keyData = ? AND rollingStartNumber = ? AND rollingPeriod = ?;").use {
|
compileStatement("UPDATE $TABLE_TEK_CHECK SET matched = ? WHERE keyData = ? AND rollingStartNumber = ? AND rollingPeriod = ?;").use {
|
||||||
it.bindLong(1, if (matched) 1 else 0)
|
it.bindLong(1, if (matched) 1 else 0)
|
||||||
it.bindBlob(2, key.keyData)
|
it.bindBlob(2, key.keyData)
|
||||||
|
@ -207,7 +237,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun listMatchedDiagnosisKeys(packageName: String, token: String) = readableDatabase.run {
|
private fun listMatchedDiagnosisKeys(packageName: String, token: String, database: SQLiteDatabase = readableDatabase) = database.run {
|
||||||
rawQuery("""
|
rawQuery("""
|
||||||
SELECT $TABLE_TEK_CHECK.keyData, $TABLE_TEK_CHECK.rollingStartNumber, $TABLE_TEK_CHECK.rollingPeriod, $TABLE_DIAGNOSIS.transmissionRiskLevel
|
SELECT $TABLE_TEK_CHECK.keyData, $TABLE_TEK_CHECK.rollingStartNumber, $TABLE_TEK_CHECK.rollingPeriod, $TABLE_DIAGNOSIS.transmissionRiskLevel
|
||||||
FROM $TABLE_DIAGNOSIS
|
FROM $TABLE_DIAGNOSIS
|
||||||
|
@ -230,21 +260,21 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finishMatching(packageName: String, token: String) {
|
fun finishMatching(packageName: String, token: String, database: SQLiteDatabase = writableDatabase) {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
val workQueue = LinkedBlockingQueue<Runnable>()
|
val workQueue = LinkedBlockingQueue<Runnable>()
|
||||||
val poolSize = Runtime.getRuntime().availableProcessors()
|
val poolSize = Runtime.getRuntime().availableProcessors()
|
||||||
val executor = ThreadPoolExecutor(poolSize, poolSize, 1, TimeUnit.SECONDS, workQueue)
|
val executor = ThreadPoolExecutor(poolSize, poolSize, 1, TimeUnit.SECONDS, workQueue)
|
||||||
val futures = arrayListOf<Future<*>>()
|
val futures = arrayListOf<Future<*>>()
|
||||||
val keys = listDiagnosisKeysPendingSearch(packageName, token)
|
val keys = listDiagnosisKeysPendingSearch(packageName, token, database)
|
||||||
val oldestRpi = oldestRpi
|
val oldestRpi = oldestRpi
|
||||||
for (key in keys) {
|
for (key in keys) {
|
||||||
if (oldestRpi == null || (key.rollingStartIntervalNumber + key.rollingPeriod) * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS < oldestRpi) {
|
if (oldestRpi == null || (key.rollingStartIntervalNumber + key.rollingPeriod) * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS < oldestRpi) {
|
||||||
// Early ignore because key is older than since we started scanning.
|
// Early ignore because key is older than since we started scanning.
|
||||||
applyDiagnosisKeySearchResult(key, false)
|
applyDiagnosisKeySearchResult(key, false, database)
|
||||||
} else {
|
} else {
|
||||||
futures.add(executor.submit {
|
futures.add(executor.submit {
|
||||||
applyDiagnosisKeySearchResult(key, findMeasuredExposures(key).isNotEmpty())
|
applyDiagnosisKeySearchResult(key, findMeasuredExposures(key).isNotEmpty(), database)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,21 +286,17 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
Log.d(TAG, "Processed ${keys.size} new keys in ${time}s -> ${(keys.size.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s")
|
Log.d(TAG, "Processed ${keys.size} new keys in ${time}s -> ${(keys.size.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findAllMeasuredExposures(packageName: String, token: String): List<MeasuredExposure> {
|
fun findAllMeasuredExposures(packageName: String, token: String, database: SQLiteDatabase = readableDatabase): List<MeasuredExposure> {
|
||||||
val list = arrayListOf<MeasuredExposure>()
|
return listMatchedDiagnosisKeys(packageName, token, database).flatMap { findMeasuredExposures(it, database) }
|
||||||
for (key in listMatchedDiagnosisKeys(packageName, token)) {
|
|
||||||
list.addAll(findMeasuredExposures(key))
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findMeasuredExposures(key: TemporaryExposureKey): List<MeasuredExposure> {
|
private fun findMeasuredExposures(key: TemporaryExposureKey, database: SQLiteDatabase = readableDatabase): List<MeasuredExposure> {
|
||||||
val allRpis = key.generateAllRpiIds()
|
val allRpis = key.generateAllRpiIds()
|
||||||
val rpis = (0 until key.rollingPeriod).map { i ->
|
val rpis = (0 until key.rollingPeriod).map { i ->
|
||||||
val pos = i * 16
|
val pos = i * 16
|
||||||
allRpis.sliceArray(pos until (pos + 16))
|
allRpis.sliceArray(pos until (pos + 16))
|
||||||
}
|
}
|
||||||
val measures = findExposures(rpis, key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS - ALLOWED_KEY_OFFSET_MS, (key.rollingStartIntervalNumber.toLong() + key.rollingPeriod) * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS)
|
val measures = findExposures(rpis, key.rollingStartIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH_MS - ALLOWED_KEY_OFFSET_MS, (key.rollingStartIntervalNumber.toLong() + key.rollingPeriod) * ROLLING_WINDOW_LENGTH_MS + ALLOWED_KEY_OFFSET_MS, database)
|
||||||
return measures.filter {
|
return measures.filter {
|
||||||
val index = rpis.indexOfFirst { rpi -> rpi.contentEquals(it.rpi) }
|
val index = rpis.indexOfFirst { rpi -> rpi.contentEquals(it.rpi) }
|
||||||
val targetTimestamp = (key.rollingStartIntervalNumber + index).toLong() * ROLLING_WINDOW_LENGTH_MS
|
val targetTimestamp = (key.rollingStartIntervalNumber + index).toLong() * ROLLING_WINDOW_LENGTH_MS
|
||||||
|
@ -287,7 +313,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findExposures(rpis: List<ByteArray>, minTime: Long, maxTime: Long): List<PlainExposure> = readableDatabase.run {
|
private fun findExposures(rpis: List<ByteArray>, minTime: Long, maxTime: Long, database: SQLiteDatabase = readableDatabase): List<PlainExposure> = database.run {
|
||||||
if (rpis.isEmpty()) return emptyList()
|
if (rpis.isEmpty()) return emptyList()
|
||||||
val qs = rpis.map { "?" }.joinToString(",")
|
val qs = rpis.map { "?" }.joinToString(",")
|
||||||
queryWithFactory({ _, cursorDriver, editTable, query ->
|
queryWithFactory({ _, cursorDriver, editTable, query ->
|
||||||
|
@ -321,7 +347,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findOwnKeyAt(rollingStartNumber: Int): TemporaryExposureKey? = readableDatabase.run {
|
private fun findOwnKeyAt(rollingStartNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run {
|
||||||
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber = ?", arrayOf(rollingStartNumber.toString()), null, null, null).use { cursor ->
|
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber = ?", arrayOf(rollingStartNumber.toString()), null, null, null).use { cursor ->
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
||||||
|
@ -474,8 +500,20 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
||||||
}
|
}
|
||||||
|
|
||||||
private val currentTemporaryExposureKey: TemporaryExposureKey
|
private val currentTemporaryExposureKey: TemporaryExposureKey
|
||||||
get() = findOwnKeyAt(currentRollingStartNumber.toInt())
|
get() = writableDatabase.let { database ->
|
||||||
?: storeOwnKey(generateCurrentTemporaryExposureKey())
|
database.beginTransaction()
|
||||||
|
try {
|
||||||
|
var key = findOwnKeyAt(currentRollingStartNumber.toInt(), database)
|
||||||
|
if (key == null) {
|
||||||
|
key = generateCurrentTemporaryExposureKey()
|
||||||
|
storeOwnKey(key, database)
|
||||||
|
}
|
||||||
|
database.setTransactionSuccessful()
|
||||||
|
key
|
||||||
|
} finally {
|
||||||
|
database.endTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val currentRpiId: UUID
|
val currentRpiId: UUID
|
||||||
get() {
|
get() {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyExpo
|
||||||
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyProto
|
import org.microg.gms.nearby.exposurenotification.proto.TemporaryExposureKeyProto
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class ExposureNotificationServiceImpl(private val context: Context, private val packageName: String) : INearbyExposureNotificationService.Stub() {
|
class ExposureNotificationServiceImpl(private val context: Context, private val packageName: String) : INearbyExposureNotificationService.Stub() {
|
||||||
private fun pendingConfirm(permission: String): PendingIntent {
|
private fun pendingConfirm(permission: String): PendingIntent {
|
||||||
|
@ -130,12 +131,8 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
||||||
|
|
||||||
private fun storeDiagnosisKeyExport(token: String, export: TemporaryExposureKeyExport): Int = ExposureDatabase.with(context) { database ->
|
private fun storeDiagnosisKeyExport(token: String, export: TemporaryExposureKeyExport): Int = ExposureDatabase.with(context) { database ->
|
||||||
Log.d(TAG, "Importing keys from file ${export.start_timestamp?.let { Date(it * 1000) }} to ${export.end_timestamp?.let { Date(it * 1000) }}")
|
Log.d(TAG, "Importing keys from file ${export.start_timestamp?.let { Date(it * 1000) }} to ${export.end_timestamp?.let { Date(it * 1000) }}")
|
||||||
for (key in export.keys) {
|
database.batchStoreDiagnosisKey(packageName, token, export.keys.map { it.toKey() })
|
||||||
database.storeDiagnosisKey(packageName, token, key.toKey())
|
database.batchUpdateDiagnosisKey(packageName, token, export.revised_keys.map { it.toKey() })
|
||||||
}
|
|
||||||
for (key in export.revised_keys) {
|
|
||||||
database.updateDiagnosisKey(packageName, token, key.toKey())
|
|
||||||
}
|
|
||||||
export.keys.size + export.revised_keys.size
|
export.keys.size + export.revised_keys.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,10 +143,10 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
||||||
database.storeConfiguration(packageName, params.token, params.configuration)
|
database.storeConfiguration(packageName, params.token, params.configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
// keys
|
// keys
|
||||||
for (key in params.keys.orEmpty()) {
|
params.keys?.let { database.batchStoreDiagnosisKey(packageName, params.token, it) }
|
||||||
database.storeDiagnosisKey(packageName, params.token, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key files
|
// Key files
|
||||||
var keys = params.keys?.size ?: 0
|
var keys = params.keys?.size ?: 0
|
||||||
|
@ -182,7 +179,8 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
||||||
Log.w(TAG, "Failed parsing file", e)
|
Log.w(TAG, "Failed parsing file", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(TAG, "$packageName/${params.token} provided $keys keys")
|
val time = (System.currentTimeMillis() - start).toDouble() / 1000.0
|
||||||
|
Log.d(TAG, "$packageName/${params.token} provided $keys keys in ${time}s -> ${(keys.toDouble() / time * 1000).roundToInt().toDouble() / 1000.0} keys/s")
|
||||||
|
|
||||||
database.noteAppAction(packageName, "provideDiagnosisKeys", JSONObject().apply {
|
database.noteAppAction(packageName, "provideDiagnosisKeys", JSONObject().apply {
|
||||||
put("request_token", params.token)
|
put("request_token", params.token)
|
||||||
|
|
Loading…
Reference in a new issue