diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 7c40a31e62..7b9f6fa241 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -18,6 +18,7 @@ package com.android.launcher3.model; import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN; import static com.android.launcher3.Flags.enableSupportForArchiving; +import static com.android.launcher3.Flags.enableLauncherBrMetrics; import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE; import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR; @@ -232,8 +233,11 @@ public class LoaderTask implements Runnable { LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); mIsRestoreFromBackup = (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE); - LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger - .Companion.newInstance(mApp.getContext()); + LauncherRestoreEventLogger restoreEventLogger = null; + if (enableLauncherBrMetrics()) { + restoreEventLogger = LauncherRestoreEventLogger.Companion + .newInstance(mApp.getContext()); + } try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); @@ -364,9 +368,11 @@ public class LoaderTask implements Runnable { transaction.commit(); memoryLogger.clearLogs(); if (mIsRestoreFromBackup) { - restoreEventLogger.reportLauncherRestoreResults(); mIsRestoreFromBackup = false; LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false)); + if (restoreEventLogger != null) { + restoreEventLogger.reportLauncherRestoreResults(); + } } } catch (CancellationException e) { // Loader stopped, ignore @@ -421,7 +427,7 @@ public class LoaderTask implements Runnable { final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); ModelDbController dbController = mApp.getModel().getModelDbController(); - dbController.tryMigrateDB(); + dbController.tryMigrateDB(restoreEventLogger); Log.d(TAG, "loadWorkspace: loading default favorites"); dbController.loadDefaultFavoritesIfNecessary(); diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index d2b7161697..c68274af2b 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -19,6 +19,7 @@ import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL; @@ -48,6 +49,7 @@ import android.util.Base64; import android.util.Log; import android.util.Xml; +import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.launcher3.AutoInstallsLayout; @@ -62,6 +64,7 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; @@ -86,6 +89,7 @@ public class ModelDbController { private static final String TAG = "LauncherProvider"; private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; + private static final String RESTORE_ERROR_GRID_MIGRATION_FAILURE = "grid_migration_failed"; public static final String EXTRA_DB_NAME = "db_name"; protected DatabaseHelper mOpenHelper; @@ -261,8 +265,12 @@ public class ModelDbController { /** * Migrates the DB if needed. If the migration failed, it clears the DB. */ - public void tryMigrateDB() { + public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) { + if (!migrateGridIfNeeded()) { + if (restoreEventLogger != null) { + sendMetricsForFailedMigration(restoreEventLogger, getDb()); + } FileLog.d(TAG, "Migration failed: resetting launcher database"); createEmptyDB(); LauncherPrefs.get(mContext).putSync( @@ -312,6 +320,30 @@ public class ModelDbController { } } + /** + * In case of migration failure, report metrics for the count of each itemType in the DB. + * @param restoreEventLogger logger used to report Launcher restore metrics + */ + private void sendMetricsForFailedMigration(LauncherRestoreEventLogger restoreEventLogger, + SQLiteDatabase db) { + try (Cursor cursor = db.rawQuery( + "SELECT itemType, COUNT(*) AS count FROM favorites GROUP BY itemType", + null + )) { + if (cursor.moveToFirst()) { + do { + restoreEventLogger.logFavoritesItemsRestoreFailed( + cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)), + cursor.getInt(cursor.getColumnIndexOrThrow("count")), + RESTORE_ERROR_GRID_MIGRATION_FAILURE + ); + } while (cursor.moveToNext()); + } + } catch (Exception e) { + FileLog.e(TAG, "sendMetricsForFailedDb: Error reading from database", e); + } + } + /** * Returns the underlying model database */ diff --git a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java index fb364ad44d..dbb271574c 100644 --- a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java +++ b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java @@ -64,7 +64,7 @@ public class FavoriteItemsTransaction { runOnExecutorSync(MODEL_EXECUTOR, () -> { ModelDbController controller = model.getModelDbController(); // Migrate any previous data so that the DB state is correct - controller.tryMigrateDB(); + controller.tryMigrateDB(null /* restoreEventLogger */); // Create DB again to load fresh data controller.createEmptyDB(); diff --git a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt index 9d9bd5175e..6bd182b1fe 100644 --- a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt +++ b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt @@ -30,7 +30,7 @@ object ModelTestExtensions { loadModelSync() TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { modelDbController.run { - tryMigrateDB() + tryMigrateDB(null /* restoreEventLogger */) createEmptyDB() clearEmptyDbFlag() } @@ -72,7 +72,7 @@ object ModelTestExtensions { loadModelSync() TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { val controller: ModelDbController = modelDbController - controller.tryMigrateDB() + controller.tryMigrateDB(null /* restoreEventLogger */) modelDbController.newTransaction().use { transaction -> val values = ContentValues().apply {