From dc77226995f96deda91bee692299c3520a912202 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 16 Sep 2024 08:49:42 -0400 Subject: [PATCH] Address a FTS table configuration crash. --- .../securesms/database/SearchTable.kt | 8 +++++++ .../helpers/SignalDatabaseMigrations.kt | 23 +++++++++++++++++-- .../impl/CellServiceConstraintObserver.java | 7 +++++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt index 25a831935a..54a4d7509e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.database import android.annotation.SuppressLint +import android.app.Application import android.content.Context import android.database.Cursor import android.database.sqlite.SQLiteException @@ -11,6 +12,8 @@ import org.signal.core.util.SqlUtil import org.signal.core.util.ThreadUtil import org.signal.core.util.logging.Log import org.signal.core.util.withinTransaction +import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider import org.thoughtcrime.securesms.jobs.RebuildMessageSearchIndexJob /** @@ -288,6 +291,11 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa Log.w(TAG, "[fullyResetTables] Recreating triggers...") CREATE_TRIGGERS.forEach { db.execSQL(it) } + // There are specific error recovery paths where this is run inside of database initialization, before the job manager is initialized + if (!AppDependencies.isInitialized) { + AppDependencies.init(context as Application, ApplicationDependencyProvider(context)) + } + RebuildMessageSearchIndexJob.enqueue() Log.w(TAG, "[fullyResetTables] Done. Index will be rebuilt asynchronously)") diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index a832f496cd..9415e50b6f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -2,10 +2,11 @@ package org.thoughtcrime.securesms.database.helpers import android.app.Application import android.content.Context +import android.database.sqlite.SQLiteException import net.zetetic.database.sqlcipher.SQLiteDatabase import org.signal.core.util.areForeignKeyConstraintsEnabled import org.signal.core.util.logging.Log -import org.signal.core.util.withinTransaction +import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.helpers.migration.SignalDatabaseMigration import org.thoughtcrime.securesms.database.helpers.migration.V149_LegacyMigrations import org.thoughtcrime.securesms.database.helpers.migration.V150_UrgentMslFlagMigration @@ -226,10 +227,28 @@ object SignalDatabaseMigrations { Log.i(TAG, "Running migration for version $version: ${migration.javaClass.simpleName}. Foreign keys: ${migration.enableForeignKeys}") val startTime = System.currentTimeMillis() + var ftsException: SQLiteException? = null + db.setForeignKeyConstraintsEnabled(migration.enableForeignKeys) - db.withinTransaction { + db.beginTransaction() + try { migration.migrate(context, db, oldVersion, newVersion) db.version = version + db.setTransactionSuccessful() + } catch (e: SQLiteException) { + if (e.message?.contains("invalid fts5 file format") == true || e.message?.contains("vtable constructor failed") == true) { + ftsException = e + } else { + throw e + } + } finally { + db.endTransaction() + } + + if (ftsException != null) { + Log.w(TAG, "Encountered FTS format issue! Attempting to repair.", ftsException) + SignalDatabase.messageSearch.fullyResetTables(db) + throw ftsException } Log.i(TAG, "Successfully completed migration for version $version in ${System.currentTimeMillis() - startTime} ms") diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java index ffa6655228..1790dc0371 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/impl/CellServiceConstraintObserver.java @@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.jobmanager.impl; import android.app.Application; import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyCallback; @@ -44,7 +46,10 @@ public class CellServiceConstraintObserver implements ConstraintObserver { if (Build.VERSION.SDK_INT >= 31) { telephonyManager.registerTelephonyCallback(SignalExecutors.BOUNDED, new ServiceStateListenerApi31()); } else { - SignalExecutors.BOUNDED.execute(() -> { + HandlerThread handlerThread = SignalExecutors.getAndStartHandlerThread("CellServiceConstraintObserver", Thread.NORM_PRIORITY); + Handler handler = new Handler(handlerThread.getLooper()); + + handler.post(() -> { telephonyManager.listen(serviceStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); }); }