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

Commit f0b1ddc0 authored by Charlie Anderson's avatar Charlie Anderson Committed by Android (Google) Code Review
Browse files

Merge "Adds restore metrics to RestoreDbTask.java" into main

parents 93504b42 1fcf8da4
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;
@@ -124,8 +131,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) {
@@ -148,7 +158,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());
@@ -187,6 +198,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");

@@ -346,21 +360,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);
@@ -371,10 +388,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)) {
@@ -438,11 +458,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();
@@ -477,17 +502,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);
        }
@@ -546,7 +570,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,
@@ -555,19 +579,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 "
@@ -577,4 +601,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);