Change spinner to lazily read database stuff.

Otherwise you get into situations where Spinner will force DB accesses
super early during Application#onCreate on the main thread, which can be
bad when testing large DB migrations.
main
Greyson Parrelli 2022-12-15 15:17:25 -05:00 zatwierdzone przez Cody Henthorne
rodzic 3ce5a7da67
commit 10f78d5daa
4 zmienionych plików z 39 dodań i 35 usunięć

Wyświetl plik

@ -51,25 +51,25 @@ class SpinnerApplicationContext : ApplicationContext() {
Spinner.init( Spinner.init(
this, this,
mapOf( mapOf(
"Device" to "${Build.MODEL} (Android ${Build.VERSION.RELEASE}, API ${Build.VERSION.SDK_INT})", "Device" to { "${Build.MODEL} (Android ${Build.VERSION.RELEASE}, API ${Build.VERSION.SDK_INT})" },
"Package" to "$packageName (${AppSignatureUtil.getAppSignature(this)})", "Package" to { "$packageName (${AppSignatureUtil.getAppSignature(this)})" },
"App Version" to "${BuildConfig.VERSION_NAME} (${BuildConfig.CANONICAL_VERSION_CODE}, ${BuildConfig.GIT_HASH})", "App Version" to { "${BuildConfig.VERSION_NAME} (${BuildConfig.CANONICAL_VERSION_CODE}, ${BuildConfig.GIT_HASH})" },
"Profile Name" to (if (SignalStore.account().isRegistered) Recipient.self().profileName.toString() else "none"), "Profile Name" to { (if (SignalStore.account().isRegistered) Recipient.self().profileName.toString() else "none") },
"E164" to (SignalStore.account().e164 ?: "none"), "E164" to { SignalStore.account().e164 ?: "none" },
"ACI" to (SignalStore.account().aci?.toString() ?: "none"), "ACI" to { SignalStore.account().aci?.toString() ?: "none" },
"PNI" to (SignalStore.account().pni?.toString() ?: "none"), "PNI" to { SignalStore.account().pni?.toString() ?: "none" },
Spinner.KEY_ENVIRONMENT to BuildConfig.FLAVOR_environment.uppercase(Locale.US) Spinner.KEY_ENVIRONMENT to { BuildConfig.FLAVOR_environment.uppercase(Locale.US) }
), ),
linkedMapOf( linkedMapOf(
"signal" to DatabaseConfig( "signal" to DatabaseConfig(
db = SignalDatabase.rawDatabase, db = { SignalDatabase.rawDatabase },
columnTransformers = listOf(MessageBitmaskColumnTransformer, GV2Transformer, GV2UpdateTransformer, IsStoryTransformer, TimestampTransformer, ProfileKeyCredentialTransformer) columnTransformers = listOf(MessageBitmaskColumnTransformer, GV2Transformer, GV2UpdateTransformer, IsStoryTransformer, TimestampTransformer, ProfileKeyCredentialTransformer)
), ),
"jobmanager" to DatabaseConfig(db = JobDatabase.getInstance(this).sqlCipherDatabase), "jobmanager" to DatabaseConfig(db = { JobDatabase.getInstance(this).sqlCipherDatabase }),
"keyvalue" to DatabaseConfig(db = KeyValueDatabase.getInstance(this).sqlCipherDatabase), "keyvalue" to DatabaseConfig(db = { KeyValueDatabase.getInstance(this).sqlCipherDatabase }),
"megaphones" to DatabaseConfig(db = MegaphoneDatabase.getInstance(this).sqlCipherDatabase), "megaphones" to DatabaseConfig(db = { MegaphoneDatabase.getInstance(this).sqlCipherDatabase }),
"localmetrics" to DatabaseConfig(db = LocalMetricsDatabase.getInstance(this).sqlCipherDatabase), "localmetrics" to DatabaseConfig(db = { LocalMetricsDatabase.getInstance(this).sqlCipherDatabase }),
"logs" to DatabaseConfig(db = LogDatabase.getInstance(this).sqlCipherDatabase), "logs" to DatabaseConfig(db = { LogDatabase.getInstance(this).sqlCipherDatabase }),
), ),
linkedMapOf( linkedMapOf(
StorageServicePlugin.PATH to StorageServicePlugin() StorageServicePlugin.PATH to StorageServicePlugin()

Wyświetl plik

@ -20,10 +20,10 @@ class MainActivity : AppCompatActivity() {
Spinner.init( Spinner.init(
application, application,
mapOf( mapOf(
"Name" to "${Build.MODEL} (API ${Build.VERSION.SDK_INT})", "Name" to { "${Build.MODEL} (API ${Build.VERSION.SDK_INT})" },
"Package" to packageName "Package" to { packageName }
), ),
mapOf("main" to Spinner.DatabaseConfig(db = db)), mapOf("main" to Spinner.DatabaseConfig(db = { db })),
emptyMap() emptyMap()
) )
} }

Wyświetl plik

@ -18,7 +18,7 @@ object Spinner {
private lateinit var server: SpinnerServer private lateinit var server: SpinnerServer
fun init(application: Application, deviceInfo: Map<String, String>, databases: Map<String, DatabaseConfig>, plugins: Map<String, Plugin>) { fun init(application: Application, deviceInfo: Map<String, () -> String>, databases: Map<String, DatabaseConfig>, plugins: Map<String, Plugin>) {
try { try {
server = SpinnerServer(application, deviceInfo, databases, plugins) server = SpinnerServer(application, deviceInfo, databases, plugins)
server.start() server.start()
@ -91,7 +91,7 @@ object Spinner {
} }
data class DatabaseConfig( data class DatabaseConfig(
val db: SupportSQLiteDatabase, val db: () -> SupportSQLiteDatabase,
val columnTransformers: List<ColumnTransformer> = emptyList() val columnTransformers: List<ColumnTransformer> = emptyList()
) )
} }

Wyświetl plik

@ -28,7 +28,7 @@ import kotlin.math.min
*/ */
internal class SpinnerServer( internal class SpinnerServer(
private val application: Application, private val application: Application,
deviceInfo: Map<String, String>, deviceInfo: Map<String, () -> String>,
private val databases: Map<String, DatabaseConfig>, private val databases: Map<String, DatabaseConfig>,
private val plugins: Map<String, Plugin> private val plugins: Map<String, Plugin>
) : NanoHTTPD(5000) { ) : NanoHTTPD(5000) {
@ -37,8 +37,8 @@ internal class SpinnerServer(
private val TAG = Log.tag(SpinnerServer::class.java) private val TAG = Log.tag(SpinnerServer::class.java)
} }
private val deviceInfo: Map<String, String> = deviceInfo.filterKeys { !it.startsWith(Spinner.KEY_PREFIX) } private val deviceInfo: Map<String, () -> String> = deviceInfo.filterKeys { !it.startsWith(Spinner.KEY_PREFIX) }
private val environment: String = deviceInfo[Spinner.KEY_ENVIRONMENT] ?: "UNKNOWN" private val environment: String = deviceInfo[Spinner.KEY_ENVIRONMENT]?.let { it() } ?: "UNKNOWN"
private val handlebars: Handlebars = Handlebars(AssetTemplateLoader(application)).apply { private val handlebars: Handlebars = Handlebars(AssetTemplateLoader(application)).apply {
registerHelper("eq", ConditionalHelpers.eq) registerHelper("eq", ConditionalHelpers.eq)
@ -61,8 +61,8 @@ internal class SpinnerServer(
return when { return when {
session.method == Method.GET && session.uri == "/css/main.css" -> newFileResponse("css/main.css", "text/css") session.method == Method.GET && session.uri == "/css/main.css" -> newFileResponse("css/main.css", "text/css")
session.method == Method.GET && session.uri == "/js/main.js" -> newFileResponse("js/main.js", "text/javascript") session.method == Method.GET && session.uri == "/js/main.js" -> newFileResponse("js/main.js", "text/javascript")
session.method == Method.GET && session.uri == "/" -> getIndex(dbParam, dbConfig.db) session.method == Method.GET && session.uri == "/" -> getIndex(dbParam, dbConfig.db())
session.method == Method.GET && session.uri == "/browse" -> getBrowse(dbParam, dbConfig.db) session.method == Method.GET && session.uri == "/browse" -> getBrowse(dbParam, dbConfig.db())
session.method == Method.POST && session.uri == "/browse" -> postBrowse(dbParam, dbConfig, session) session.method == Method.POST && session.uri == "/browse" -> postBrowse(dbParam, dbConfig, session)
session.method == Method.GET && session.uri == "/query" -> getQuery(dbParam) session.method == Method.GET && session.uri == "/query" -> getQuery(dbParam)
session.method == Method.POST && session.uri == "/query" -> postQuery(dbParam, dbConfig, session) session.method == Method.POST && session.uri == "/query" -> postQuery(dbParam, dbConfig, session)
@ -98,7 +98,7 @@ internal class SpinnerServer(
"overview", "overview",
OverviewPageModel( OverviewPageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
@ -115,7 +115,7 @@ internal class SpinnerServer(
"browse", "browse",
BrowsePageModel( BrowsePageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
@ -130,7 +130,7 @@ internal class SpinnerServer(
var pageIndex: Int = session.parameters["pageIndex"]?.get(0)?.toInt() ?: 0 var pageIndex: Int = session.parameters["pageIndex"]?.get(0)?.toInt() ?: 0
val action: String? = session.parameters["action"]?.get(0) val action: String? = session.parameters["action"]?.get(0)
val rowCount = dbConfig.db.getTableRowCount(table) val rowCount = dbConfig.db().getTableRowCount(table)
val pageCount = ceil(rowCount.toFloat() / pageSize.toFloat()).toInt() val pageCount = ceil(rowCount.toFloat() / pageSize.toFloat()).toInt()
when (action) { when (action) {
@ -141,17 +141,17 @@ internal class SpinnerServer(
} }
val query = "select * from $table limit $pageSize offset ${pageSize * pageIndex}" val query = "select * from $table limit $pageSize offset ${pageSize * pageIndex}"
val queryResult = dbConfig.db.query(query).use { it.toQueryResult(columnTransformers = dbConfig.columnTransformers) } val queryResult = dbConfig.db().query(query).use { it.toQueryResult(columnTransformers = dbConfig.columnTransformers) }
return renderTemplate( return renderTemplate(
"browse", "browse",
BrowsePageModel( BrowsePageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
tableNames = dbConfig.db.getTableNames(), tableNames = dbConfig.db().getTableNames(),
table = table, table = table,
queryResult = queryResult, queryResult = queryResult,
pagingData = PagingData( pagingData = PagingData(
@ -171,7 +171,7 @@ internal class SpinnerServer(
"query", "query",
QueryPageModel( QueryPageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
@ -193,7 +193,7 @@ internal class SpinnerServer(
"recent", "recent",
RecentPageModel( RecentPageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
@ -212,12 +212,12 @@ internal class SpinnerServer(
"query", "query",
QueryPageModel( QueryPageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
query = rawQuery, query = rawQuery,
queryResult = dbConfig.db.query(query).use { it.toQueryResult(queryStartTimeNanos = startTimeNanos, columnTransformers = dbConfig.columnTransformers) } queryResult = dbConfig.db().query(query).use { it.toQueryResult(queryStartTimeNanos = startTimeNanos, columnTransformers = dbConfig.columnTransformers) }
) )
) )
} }
@ -227,7 +227,7 @@ internal class SpinnerServer(
"plugin", "plugin",
PluginPageModel( PluginPageModel(
environment = environment, environment = environment,
deviceInfo = deviceInfo, deviceInfo = deviceInfo.resolve(),
database = dbName, database = dbName,
databases = databases.keys.toList(), databases = databases.keys.toList(),
plugins = plugins.values.toList(), plugins = plugins.values.toList(),
@ -389,6 +389,10 @@ internal class SpinnerServer(
return params[name] return params[name]
} }
private fun Map<String, () -> String>.resolve(): Map<String, String> {
return this.mapValues { entry -> entry.value() }.toMap()
}
interface PrefixPageData { interface PrefixPageData {
val environment: String val environment: String
val deviceInfo: Map<String, String> val deviceInfo: Map<String, String>