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

Commit 1fcf8da4 authored by Charlie Anderson's avatar Charlie Anderson
Browse files

Adds restore metrics to RestoreDbTask.java

Bug: 307527314
Flag: ACONFIG enable_launcher_br_metrics TEAMFOOD
Test: locally verified
Change-Id: I105b17276cf7e2c270c819854a8fbc269b7c81b4
parent 2c385bec
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ open class LauncherRestoreEventLogger : ResourceBasedOverride {
        const val RESTORE_ERROR_SHORTCUT_NOT_FOUND = "shortcut_not_found"
        const val RESTORE_ERROR_APP_NOT_INSTALLED = "app_not_installed"
        const val RESTORE_ERROR_WIDGETS_DISABLED = "widgets_disabled"
        const val RESTORE_ERROR_PROFILE_NOT_RESTORED = "profile_not_restored"
        const val RESTORE_ERROR_WIDGET_REMOVED = "widget_not_found"

        fun newInstance(context: Context?): LauncherRestoreEventLogger {
            return ResourceBasedOverride.Overrides.getObject(
+71 −20
Original line number Diff line number Diff line
@@ -18,12 +18,18 @@ package com.android.launcher3.provider;

import static android.os.Process.myUserHandle;

import static com.android.launcher3.Flags.enableLauncherBrMetrics;
import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_NOT_RESTORED;
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED;
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGET_REMOVED;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;

@@ -53,6 +59,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.model.DeviceGridState;
import com.android.launcher3.model.LoaderTask;
@@ -123,8 +130,11 @@ public class RestoreDbTask {
        FileLog.d(TAG, "performRestore: starting restore from db");
        try (SQLiteTransaction t = new SQLiteTransaction(db)) {
            RestoreDbTask task = new RestoreDbTask();
            task.sanitizeDB(context, controller, db, new BackupManager(context));
            task.restoreAppWidgetIdsIfExists(context, controller);
            BackupManager backupManager = new BackupManager(context);
            LauncherRestoreEventLogger restoreEventLogger =
                    LauncherRestoreEventLogger.Companion.newInstance(context);
            task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger);
            task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger);
            t.commit();
            return true;
        } catch (Exception e) {
@@ -147,7 +157,8 @@ public class RestoreDbTask {
     */
    @VisibleForTesting
    protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
            BackupManager backupManager) throws Exception {
            BackupManager backupManager, LauncherRestoreEventLogger restoreEventLogger)
            throws Exception {
        logFavoritesTable(db, "Old Launcher Database before sanitizing:", null, null);
        // Primary user ids
        long myProfileId = controller.getSerialNumberForUser(myUserHandle());
@@ -186,6 +197,9 @@ public class RestoreDbTask {
        Arrays.fill(args, "?");
        final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
        logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
        if (enableLauncherBrMetrics()) {
            reportUnrestoredProfiles(db, where, profileIds, restoreEventLogger);
        }
        int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
        FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");

@@ -345,21 +359,24 @@ public class RestoreDbTask {
        DeviceGridState deviceGridState = new DeviceGridState(context);
        FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
        LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
        if (enableLauncherBrMetrics()) {
            LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
        }
    }

    @WorkerThread
    @VisibleForTesting
    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) {
    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller,
            LauncherRestoreEventLogger restoreEventLogger) {
        LauncherPrefs lp = LauncherPrefs.get(context);
        if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
            AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
            restoreAppWidgetIds(context, controller,
            restoreAppWidgetIds(context, controller, restoreEventLogger,
                    IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
                    IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
                    host);
        } else {
            FileLog.d(TAG, "No app widget ids were received from backup to restore.");
            FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore");
        }

        lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
@@ -370,10 +387,13 @@ public class RestoreDbTask {
     */
    @WorkerThread
    private void restoreAppWidgetIds(Context context, ModelDbController controller,
            int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
            LauncherRestoreEventLogger launcherRestoreEventLogger, int[] oldWidgetIds,
            int[] newWidgetIds, @NonNull AppWidgetHost host) {
        if (WidgetsModel.GO_DISABLE_WIDGETS) {
            FileLog.e(TAG, "Skipping widget ID remap as widgets not supported");
            host.deleteHost();
            launcherRestoreEventLogger.logFavoritesItemsRestoreFailed(Favorites.ITEM_TYPE_APPWIDGET,
                    oldWidgetIds.length, RESTORE_ERROR_WIDGETS_DISABLED);
            return;
        }
        if (!RestoreDbTask.isPending(context)) {
@@ -437,11 +457,16 @@ public class RestoreDbTask {
                        FileLog.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
                                + oldWidgetId);
                        host.deleteAppWidgetId(newWidgetIds[i]);
                        launcherRestoreEventLogger.logSingleFavoritesItemRestoreFailed(
                                ITEM_TYPE_APPWIDGET,
                                RESTORE_ERROR_WIDGET_REMOVED
                        );
                    }
                }
            }
        }

        logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
        if (app != null) {
            app.getModel().forceReload();
@@ -476,17 +501,16 @@ public class RestoreDbTask {
            StringBuilder builder = new StringBuilder();
            builder.append("[");
            for (int i = 0; i < widgetIdList.size(); i++) {
                builder.append("[")
                builder.append("[appWidgetId=")
                        .append(widgetIdList.get(i))
                        .append(", ")
                        .append(", restoreFlag=")
                        .append(widgetRestoreList.get(i))
                        .append(", ")
                        .append(", profileId=")
                        .append(widgetProfileIdList.get(i))
                        .append("]");
            }
            builder.append("]");
            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
                    + builder);
            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: " + builder);
        } catch (Exception ex) {
            Log.e(TAG, "Getting widget ids from the database failed", ex);
        }
@@ -545,7 +569,7 @@ public class RestoreDbTask {
     */
    public static void logFavoritesTable(SQLiteDatabase database, @NonNull String logHeader,
            String where, String[] profileIds) {
        try (Cursor itemsToDelete = database.query(
        try (Cursor cursor = database.query(
                /* table */ Favorites.TABLE_NAME,
                /* columns */ DB_COLUMNS_TO_LOG,
                /* selection */ where,
@@ -554,19 +578,19 @@ public class RestoreDbTask {
                /* having */ null,
                /* orderBy */ null
        )) {
            if (itemsToDelete.moveToFirst()) {
                String[] columnNames = itemsToDelete.getColumnNames();
            if (cursor.moveToFirst()) {
                String[] columnNames = cursor.getColumnNames();
                StringBuilder stringBuilder = new StringBuilder(logHeader + "\n");
                do {
                    for (String columnName : columnNames) {
                        stringBuilder.append(columnName)
                                .append("=")
                                .append(itemsToDelete.getString(
                                        itemsToDelete.getColumnIndex(columnName)))
                                .append(cursor.getString(
                                        cursor.getColumnIndex(columnName)))
                                .append(" ");
                    }
                    stringBuilder.append("\n");
                } while (itemsToDelete.moveToNext());
                } while (cursor.moveToNext());
                FileLog.d(TAG, stringBuilder.toString());
            } else {
                FileLog.d(TAG, "logFavoritesTable: No items found from query for "
@@ -576,4 +600,31 @@ public class RestoreDbTask {
            FileLog.e(TAG, "logFavoritesTable: Error reading from database", e);
        }
    }


    /**
     * Queries and reports the count of each itemType to be removed due to unrestored profiles.
     * @param database The Launcher db to query from.
     * @param where Query being used for to find unrestored profiles
     * @param profileIds profile ids that were not restored
     * @param restoreEventLogger Backup/Restore Logger to report metrics
     */
    private void reportUnrestoredProfiles(SQLiteDatabase database, String where,
            String[] profileIds, LauncherRestoreEventLogger restoreEventLogger) {
        final String query = "SELECT itemType, COUNT(*) AS count FROM favorites WHERE "
                + where + " GROUP BY itemType";
        try (Cursor cursor = database.rawQuery(query, profileIds)) {
            if (cursor.moveToFirst()) {
                do {
                    restoreEventLogger.logFavoritesItemsRestoreFailed(
                            cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
                            cursor.getInt(cursor.getColumnIndexOrThrow("count")),
                            RESTORE_ERROR_PROFILE_NOT_RESTORED
                    );
                } while (cursor.moveToNext());
            }
        } catch (Exception e) {
            FileLog.e(TAG, "reportUnrestoredProfiles: Error reading from database", e);
        }
    }
}
+10 −6
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LauncherModelHelper;
@@ -90,6 +91,7 @@ public class RestoreDbTaskTest {
    private SQLiteDatabase mMockDb;
    private Cursor mMockCursor;
    private LauncherPrefs mPrefs;
    private LauncherRestoreEventLogger mMockRestoreEventLogger;

    @Before
    public void setup() {
@@ -100,6 +102,7 @@ public class RestoreDbTaskTest {
        mMockDb = mock(SQLiteDatabase.class);
        mMockCursor = mock(Cursor.class);
        mPrefs = new LauncherPrefs(mContext);
        mMockRestoreEventLogger = mock(LauncherRestoreEventLogger.class);
    }

    @After
@@ -178,7 +181,7 @@ public class RestoreDbTaskTest {
        assertEquals(10, getItemCountForProfile(db, myProfileId_old));
        assertEquals(6, getItemCountForProfile(db, workProfileId_old));

        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);

        // All the data has been migrated to the new user ids
        assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -207,7 +210,7 @@ public class RestoreDbTaskTest {
        assertEquals(10, getItemCountForProfile(db, myProfileId_old));
        assertEquals(6, getItemCountForProfile(db, workProfileId_old));

        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);

        // All the data has been migrated to the new user ids
        assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -219,7 +222,7 @@ public class RestoreDbTaskTest {
    @Test
    public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() {
        // When
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
        // Then
        assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
    }
@@ -235,7 +238,7 @@ public class RestoreDbTaskTest {

        // When
        setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);

        // Then
        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -257,7 +260,7 @@ public class RestoreDbTaskTest {

        // When
        setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);

        // Then
        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -280,12 +283,13 @@ public class RestoreDbTaskTest {
        when(mMockDb.query(any(), any(), any(), any(), any(), any(), any()))
                .thenReturn(mMockCursor);
        when(mMockCursor.moveToFirst()).thenReturn(true);
        when(mMockCursor.getColumnNames()).thenReturn(new String[] {});
        when(mMockCursor.isAfterLast()).thenReturn(true);
        RestoreDbTask.setPending(mContext);

        // When
        setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);

        // Then
        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds);