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

Commit 0d2cc9e8 authored by Stefan Andonian's avatar Stefan Andonian Committed by Android (Google) Code Review
Browse files

Merge "Revert^2 "Remove Unused parts of LauncherPrefs causing cyclical dependency."" into main

parents e8609736 1a626d2d
Loading
Loading
Loading
Loading
+0 −52
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep

import android.content.Context
import android.util.Log
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.moveStartupDataToDeviceProtectedStorageIsEnabled
import com.android.launcher3.util.LockedUserState

/**
 * Loads expensive objects in memory before the user is unlocked. This decreases experienced latency
 * when starting the launcher for the first time after a reboot.
 */
object BootAwarePreloader {
    private const val TAG = "BootAwarePreloader"

    @JvmStatic
    fun start(context: Context) {
        val lp = LauncherPrefs.get(context)
        when {
            LockedUserState.get(context).isUserUnlocked ||
                !moveStartupDataToDeviceProtectedStorageIsEnabled -> {
                /* No-Op */
            }
            lp.isStartupDataMigrated -> {
                Log.d(TAG, "preloading start up data")
                LauncherAppState.INSTANCE.get(context)
            }
            else -> {
                Log.d(TAG, "queuing start up data migration to boot aware prefs")
                LockedUserState.get(context).runOnUserUnlocked {
                    lp.migrateStartupDataToDeviceProtectedStorage()
                }
            }
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -501,7 +501,6 @@ public class TouchInteractionService extends Service {
        mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
        mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
        mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
        BootAwarePreloader.start(this);

        // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
        LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
+12 −93
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
@@ -37,8 +36,6 @@ import com.android.launcher3.util.Themes
 * Use same context for shared preferences, so that we use a single cached instance
 *
 * TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
 * TODO(b/274501660): Fix ReorderWidgets#simpleReorder test before enabling
 *   isBootAwareStartupDataEnabled
 */
class LauncherPrefs(private val encryptedContext: Context) {
    private val deviceProtectedStorageContext =
@@ -51,22 +48,8 @@ class LauncherPrefs(private val encryptedContext: Context) {
    private val Item.encryptedPrefs
        get() = encryptedContext.getSharedPreferences(sharedPrefFile, MODE_PRIVATE)

    // This call to `SharedPreferences` needs to be explicit rather than using `get` since doing so
    // would result in a circular dependency between `isStartupDataMigrated` and `choosePreferences`
    val isStartupDataMigrated: Boolean
        get() =
            bootAwarePrefs.getBoolean(
                IS_STARTUP_DATA_MIGRATED.sharedPrefKey,
                IS_STARTUP_DATA_MIGRATED.defaultValue
            )

    private fun chooseSharedPreferences(item: Item): SharedPreferences =
        if (
            (moveStartupDataToDeviceProtectedStorageIsEnabled &&
                item.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
                isStartupDataMigrated) || item.encryptionType == EncryptionType.DEVICE_PROTECTED
        )
            bootAwarePrefs
        if (item.encryptionType == EncryptionType.DEVICE_PROTECTED) bootAwarePrefs
        else item.encryptedPrefs

    /** Wrapper around `getInner` for a `ContextualItem` */
@@ -146,11 +129,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
                .toMutableMap()

        val bootAwareUpdates =
            updates.filter {
                (it.first.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
                    it.first.encryptionType == EncryptionType.DEVICE_PROTECTED
            }
            updates.filter { it.first.encryptionType == EncryptionType.DEVICE_PROTECTED }
        if (bootAwareUpdates.isNotEmpty()) {
            updatesPerPrefFile[bootAwarePrefs] = bootAwareUpdates
        }
@@ -251,12 +230,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
                .groupBy { it.encryptedPrefs }
                .toMutableMap()

        val bootAwareUpdates =
            items.filter {
                (it.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
                    it.encryptionType == EncryptionType.DEVICE_PROTECTED
            }
        val bootAwareUpdates = items.filter { it.encryptionType == EncryptionType.DEVICE_PROTECTED }
        if (bootAwareUpdates.isNotEmpty()) {
            itemsPerFile[bootAwarePrefs] = bootAwareUpdates
        }
@@ -268,24 +242,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
        }
    }

    fun migrateStartupDataToDeviceProtectedStorage() {
        if (!moveStartupDataToDeviceProtectedStorageIsEnabled) return

        Log.d(
            TAG,
            "Migrating data to unencrypted shared preferences to enable preloading " +
                "while the user is locked the next time the device reboots."
        )

        with(bootAwarePrefs.edit()) {
            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.forEach { putValue(it, get(it)) }
            putBoolean(IS_STARTUP_DATA_MIGRATED.sharedPrefKey, true)
            apply()
        }
    }

    companion object {
        private const val TAG = "LauncherPrefs"
        @VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"

        @JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) }
@@ -295,30 +252,20 @@ class LauncherPrefs(private val encryptedContext: Context) {
        const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
        const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
        @JvmField
        val ICON_STATE =
            nonRestorableItem("pref_icon_shape_path", "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
        val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)

        @JvmField
        val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
        @JvmField
        val THEMED_ICONS =
            backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
        val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
        @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
        @JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
        @JvmField
        val WORKSPACE_SIZE =
            backedUpItem(
                DeviceGridState.KEY_WORKSPACE_SIZE,
                "",
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
            backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", EncryptionType.ENCRYPTED)
        @JvmField
        val HOTSEAT_COUNT =
            backedUpItem(
                DeviceGridState.KEY_HOTSEAT_COUNT,
                -1,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
            backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, EncryptionType.ENCRYPTED)
        @JvmField
        val TASKBAR_PINNING =
            backedUpItem(TASKBAR_PINNING_KEY, false, EncryptionType.DEVICE_PROTECTED)
@@ -328,11 +275,10 @@ class LauncherPrefs(private val encryptedContext: Context) {
            backedUpItem(
                DeviceGridState.KEY_DEVICE_TYPE,
                InvariantDeviceProfile.TYPE_PHONE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
                EncryptionType.ENCRYPTED
            )
        @JvmField
        val DB_FILE =
            backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
        val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.ENCRYPTED)
        @JvmField
        val SHOULD_SHOW_SMARTSPACE =
            backedUpItem(
@@ -345,15 +291,11 @@ class LauncherPrefs(private val encryptedContext: Context) {
            backedUpItem(
                RestoreDbTask.RESTORED_DEVICE_TYPE,
                InvariantDeviceProfile.TYPE_PHONE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
                EncryptionType.ENCRYPTED
            )
        @JvmField
        val IS_FIRST_LOAD_AFTER_RESTORE =
            nonRestorableItem(
                FIRST_LOAD_AFTER_RESTORE_KEY,
                false,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
            nonRestorableItem(FIRST_LOAD_AFTER_RESTORE_KEY, false, EncryptionType.ENCRYPTED)
        @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
        @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
        @JvmField
@@ -362,7 +304,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
                "idp_grid_name",
                isBackedUp = true,
                defaultValue = null,
                encryptionType = EncryptionType.MOVE_TO_DEVICE_PROTECTED,
                encryptionType = EncryptionType.ENCRYPTED,
                type = String::class.java
            )
        @JvmField
@@ -370,14 +312,6 @@ class LauncherPrefs(private val encryptedContext: Context) {
            backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
                RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
            }
        @JvmField
        val IS_STARTUP_DATA_MIGRATED =
            ConstantItem(
                "is_startup_data_boot_aware",
                isBackedUp = false,
                defaultValue = false,
                encryptionType = EncryptionType.DEVICE_PROTECTED
            )

        // Preferences for widget configurations
        @JvmField
@@ -442,12 +376,6 @@ class LauncherPrefs(private val encryptedContext: Context) {
    }
}

// It is a var because the unit tests are setting this to true so they can run.
var moveStartupDataToDeviceProtectedStorageIsEnabled: Boolean =
    com.android.launcher3.config.FeatureFlags.MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE.get()

private val ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE: MutableSet<ConstantItem<*>> = mutableSetOf()

abstract class Item {
    abstract val sharedPrefKey: String
    abstract val isBackedUp: Boolean
@@ -467,14 +395,6 @@ data class ConstantItem<T>(
    // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
    override val type: Class<out T> = defaultValue!!::class.java
) : Item() {
    init {
        if (
            encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
                moveStartupDataToDeviceProtectedStorageIsEnabled
        ) {
            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.add(this)
        }
    }

    fun get(c: Context): T = LauncherPrefs.get(c).get(this)
}
@@ -501,5 +421,4 @@ data class ContextualItem<T>(
enum class EncryptionType {
    ENCRYPTED,
    DEVICE_PROTECTED,
    MOVE_TO_DEVICE_PROTECTED
}
+0 −7
Original line number Diff line number Diff line
@@ -80,13 +80,6 @@ public final class FeatureFlags {
    public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
            "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
            "Show an 'Undo' snackbar when users dismiss a predicted hotseat item");

    public static final BooleanFlag MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE = getDebugFlag(
            251502424, "ENABLE_BOOT_AWARE_STARTUP_DATA", DISABLED,
            "Marks LauncherPref data as (and allows it to) available while the device is"
                    + " locked. Enabling this causes a 1-time movement of certain SharedPreferences"
                    + " data. Improves startup latency.");

    public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
            "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");

+1 −122
Original line number Diff line number Diff line
@@ -25,8 +25,6 @@ import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

@@ -48,20 +46,6 @@ class LauncherPrefsTest {
    private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
    private val launcherPrefs by lazy { LauncherPrefs.get(context) }

    companion object {
        @BeforeClass
        @JvmStatic
        fun setup() {
            moveStartupDataToDeviceProtectedStorageIsEnabled = true
        }

        @AfterClass
        @JvmStatic
        fun teardown() {
            moveStartupDataToDeviceProtectedStorageIsEnabled = false
        }
    }

    @Test
    fun has_keyMissingFromLauncherPrefs_returnsFalse() {
        assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
@@ -222,32 +206,13 @@ class LauncherPrefsTest {
        launcherPrefs.removeSync(bootAwareItem)
    }

    @Test
    fun put_bootAwareItem_updatesEncryptedStorage() {
        val bootAwareItem =
            LauncherPrefs.backedUpItem(
                TEST_PREF_KEY,
                TEST_DEFAULT_VALUE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )

        val encryptedPrefs: SharedPreferences =
            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
        encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()

        launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue))
        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()

        launcherPrefs.removeSync(bootAwareItem)
    }

    @Test
    fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
        val bootAwareItem =
            LauncherPrefs.backedUpItem(
                TEST_PREF_KEY,
                TEST_DEFAULT_VALUE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
                EncryptionType.DEVICE_PROTECTED
            )

        val bootAwarePrefs: SharedPreferences =
@@ -263,90 +228,4 @@ class LauncherPrefsTest {
        launcherPrefs.removeSync(bootAwareItem)
        assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
    }

    @Test
    fun remove_bootAwareItem_removesFromEncryptedStorage() {
        val bootAwareItem =
            LauncherPrefs.backedUpItem(
                TEST_PREF_KEY,
                TEST_DEFAULT_VALUE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )

        val encryptedPrefs: SharedPreferences =
            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)

        encryptedPrefs
            .edit()
            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
            .commit()

        launcherPrefs.removeSync(bootAwareItem)
        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
    }

    @Test
    fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() {
        val bootAwareItem =
            LauncherPrefs.backedUpItem(
                TEST_PREF_KEY,
                TEST_DEFAULT_VALUE,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
        launcherPrefs.removeSync(bootAwareItem)

        val bootAwarePrefs: SharedPreferences =
            context
                .createDeviceProtectedStorageContext()
                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)

        if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) {
            bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
        }

        val encryptedPrefs: SharedPreferences =
            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)

        encryptedPrefs
            .edit()
            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
            .commit()

        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
        assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()

        launcherPrefs.removeSync(bootAwareItem)
    }

    @Test
    fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() {
        val onlyEncryptedItem =
            LauncherPrefs.backedUpItem(
                TEST_PREF_KEY + "_",
                TEST_DEFAULT_VALUE + "_",
                EncryptionType.ENCRYPTED
            )

        val bootAwarePrefs: SharedPreferences =
            context
                .createDeviceProtectedStorageContext()
                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)

        if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) {
            bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
        }

        val encryptedPrefs: SharedPreferences =
            context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE)

        encryptedPrefs
            .edit()
            .putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue)
            .commit()

        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
        assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse()

        encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
    }
}