Merge "Workaround bad GC of tombstone watcher." into main
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index adee322..f722e41 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -48,6 +48,7 @@
     private static final String TAG = "JobScheduler.IdleController";
     // Policy: we decide that we're "idle" if the device has been unused /
     // screen off or dreaming or wireless charging dock idle for at least this long
+    @GuardedBy("mLock")
     final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
     IdlenessTracker mIdleTracker;
     private final FlexibilityController mFlexibilityController;
@@ -118,8 +119,10 @@
             for (int i = mTrackedTasks.size()-1; i >= 0; i--) {
                 mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle);
             }
+            if (!mTrackedTasks.isEmpty()) {
+                mStateChangedListener.onControllerStateChanged(mTrackedTasks);
+            }
         }
-        mStateChangedListener.onControllerStateChanged(mTrackedTasks);
     }
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 287d2bd..b38f76e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2593,6 +2593,9 @@
         try {
             Objects.requireNonNull(packageName);
             return mPM.isAppArchivable(packageName, new UserHandle(getUserId()));
+        } catch (ParcelableException e) {
+            e.maybeRethrow(NameNotFoundException.class);
+            throw new RuntimeException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 64042235..b18c7be 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2360,6 +2360,7 @@
                     new UserHandle(mUserId), flags);
         } catch (ParcelableException e) {
             e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            throw new RuntimeException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2396,6 +2397,7 @@
         } catch (ParcelableException e) {
             e.maybeRethrow(IOException.class);
             e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            throw new RuntimeException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2427,6 +2429,7 @@
                     userActionIntent, new UserHandle(mUserId));
         } catch (ParcelableException e) {
             e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            throw new RuntimeException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 40e03db..3273780 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -518,23 +518,25 @@
 
                     Handler mainHandler = new Handler(mContext.getMainLooper());
 
-                    for (Map.Entry<DynamicSensorCallback, Handler> entry :
-                            mDynamicSensorCallbacks.entrySet()) {
-                        final DynamicSensorCallback callback = entry.getKey();
-                        Handler handler =
-                                entry.getValue() == null ? mainHandler : entry.getValue();
+                    synchronized (mDynamicSensorCallbacks) {
+                        for (Map.Entry<DynamicSensorCallback, Handler> entry :
+                                mDynamicSensorCallbacks.entrySet()) {
+                            final DynamicSensorCallback callback = entry.getKey();
+                            Handler handler =
+                                    entry.getValue() == null ? mainHandler : entry.getValue();
 
-                        handler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                for (Sensor s: addedList) {
-                                    callback.onDynamicSensorConnected(s);
+                            handler.post(new Runnable() {
+                                @Override
+                                public void run() {
+                                    for (Sensor s: addedList) {
+                                        callback.onDynamicSensorConnected(s);
+                                    }
+                                    for (Sensor s: removedList) {
+                                        callback.onDynamicSensorDisconnected(s);
+                                    }
                                 }
-                                for (Sensor s: removedList) {
-                                    callback.onDynamicSensorDisconnected(s);
-                                }
-                            }
-                        });
+                            });
+                        }
                     }
 
                     for (Sensor s: removedList) {
@@ -653,13 +655,15 @@
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
         }
-        if (mDynamicSensorCallbacks.containsKey(callback)) {
-            // has been already registered, ignore
-            return;
-        }
+        synchronized (mDynamicSensorCallbacks) {
+            if (mDynamicSensorCallbacks.containsKey(callback)) {
+                // has been already registered, ignore
+                return;
+            }
 
-        setupDynamicSensorBroadcastReceiver();
-        mDynamicSensorCallbacks.put(callback, handler);
+            setupDynamicSensorBroadcastReceiver();
+            mDynamicSensorCallbacks.put(callback, handler);
+        }
     }
 
     /** @hide */
@@ -668,7 +672,9 @@
         if (DEBUG_DYNAMIC_SENSOR) {
             Log.i(TAG, "Removing dynamic sensor listener");
         }
-        mDynamicSensorCallbacks.remove(callback);
+        synchronized (mDynamicSensorCallbacks) {
+            mDynamicSensorCallbacks.remove(callback);
+        }
     }
 
     /*
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 9f3364f..04d4970 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -107,4 +107,8 @@
 per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS
 
 # Memory
-per-file OomKillRecord.java = file:/MEMORY_OWNERS
\ No newline at end of file
+per-file OomKillRecord.java = file:/MEMORY_OWNERS
+
+# MessageQueue
+per-file MessageQueue.java = mfasheh@google.com, shayba@google.com
+per-file Message.java = mfasheh@google.com, shayba@google.com
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp
index 31f4e64..d426f12 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.cpp
+++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp
@@ -88,7 +88,7 @@
         ALOGD("Total number of LOAD segments %zu", programHeaders.size());
 
         ALOGD("Size before punching holes st_blocks: %" PRIu64
-              ", st_blksize: %ld, st_size: %" PRIu64 "",
+              ", st_blksize: %d, st_size: %" PRIu64 "",
               beforePunch.st_blocks, beforePunch.st_blksize,
               static_cast<uint64_t>(beforePunch.st_size));
     }
@@ -193,7 +193,7 @@
             ALOGD("lstat64 failed for filePath %s, error:%d", filePath, errno);
             return false;
         }
-        ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %ld, st_size: %" PRIu64
+        ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %d, st_size: %" PRIu64
               "",
               afterPunch.st_blocks, afterPunch.st_blksize,
               static_cast<uint64_t>(afterPunch.st_size));
@@ -271,7 +271,7 @@
     uint64_t blockSize = beforePunch.st_blksize;
     IF_ALOGD() {
         ALOGD("Extra field length: %hu,  Size before punching holes st_blocks: %" PRIu64
-              ", st_blksize: %ld, st_size: %" PRIu64 "",
+              ", st_blksize: %d, st_size: %" PRIu64 "",
               extraFieldLen, beforePunch.st_blocks, beforePunch.st_blksize,
               static_cast<uint64_t>(beforePunch.st_size));
     }
@@ -346,7 +346,7 @@
             return false;
         }
         ALOGD("punchHolesInApk:: Size after punching holes st_blocks: %" PRIu64
-              ", st_blksize: %ld, st_size: %" PRIu64 "",
+              ", st_blksize: %d, st_size: %" PRIu64 "",
               afterPunch.st_blocks, afterPunch.st_blksize,
               static_cast<uint64_t>(afterPunch.st_size));
     }
diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS
index b7e008b..b669e3b 100644
--- a/core/tests/coretests/OWNERS
+++ b/core/tests/coretests/OWNERS
@@ -3,3 +3,4 @@
 per-file BinderTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
 per-file ParcelTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
 per-file SurfaceControlRegistryTests.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file VintfObjectTest.java = file:platform/system/libvintf:/OWNERS
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 6c8b69f..9767d67 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -20,6 +20,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.testng.Assert.assertThrows;
 
 import android.platform.test.annotations.IgnoreUnderRavenwood;
@@ -27,6 +29,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.os.BinderInternal;
+
+
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -81,4 +86,27 @@
         binder.setExtension(null);
         assertNull(binder.getExtension());
     }
+
+    @SmallTest
+    @Test(expected = java.lang.SecurityException.class)
+    public void testServiceManagerNativeSecurityException() throws RemoteException {
+        // Find the service manager
+        IServiceManager sServiceManager = ServiceManagerNative
+                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
+
+        Binder binder = new Binder();
+        sServiceManager.addService("ValidName",  binder,
+                anyBoolean(), anyInt());
+    }
+
+    @SmallTest
+    @Test(expected = java.lang.NullPointerException.class)
+    public void testServiceManagerNativeNullptrException() throws RemoteException {
+        // Find the service manager
+        IServiceManager sServiceManager = ServiceManagerNative
+                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
+
+        sServiceManager.addService("ValidName",  null,
+                anyBoolean(), anyInt());
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d359a90..3cff915 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -1149,6 +1149,8 @@
 
         /**
          * Sets the serial number used for the certificate of the generated key pair.
+         * To ensure compatibility with devices and certificate parsers, the value
+         * should be 20 bytes or shorter (see RFC 5280 section 4.1.2.2).
          *
          * <p>By default, the serial number is {@code 1}.
          */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index af69b52..54a98c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -1470,7 +1470,7 @@
         public void setHomeTransitionListener(IHomeTransitionListener listener) {
             executeRemoteCallWithTaskPermission(mTransitions, "setHomeTransitionListener",
                     (transitions) -> {
-                        transitions.mHomeTransitionObserver.setHomeTransitionListener(mTransitions,
+                        transitions.mHomeTransitionObserver.setHomeTransitionListener(transitions,
                                 listener);
                     });
         }
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
index 48c51af..61670e9 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
@@ -128,7 +128,7 @@
                         res.getInt(mContext.getResources().getString(R.string.status_key)));
             });
 
-            // Launch process registering a dynamic auido policy and dying after RECORD_TIME_MS ms
+            // Launch process registering a dynamic audio policy and dying after RECORD_TIME_MS ms
             // RECORD_TIME_MS must be shorter than PLAYBACK_TIME_MS
             Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class);
             intent.putExtra(mContext.getResources().getString(R.string.capture_duration_key),
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
index b8f54b3..ae69019 100644
--- a/packages/DynamicSystemInstallationService/Android.bp
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -30,10 +30,6 @@
     certificate: "platform",
     privileged: true,
     platform_apis: true,
-
-    optimize: {
-        enabled: false,
-    },
 }
 
 java_library {
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 7fcef9c..c0b354c 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -2373,7 +2373,7 @@
         public Plane[] getPlanes() {
             throwISEIfImageIsInvalid();
             if (mPlanes == null) {
-                int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.getFd() : -1;
+                int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.detachFd() : -1;
                 mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mParcelImage.buffer);
                 mPlanes = ImageReader.initializeImagePlanes(mParcelImage.planeCount, mGraphicBuffer,
                         fenceFd, mParcelImage.format, mParcelImage.timestamp,
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index f82a6aa..748253f 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -106,7 +106,7 @@
     private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
     private static final int DEFAULT_MAX_FILES = 1000;
     private static final int DEFAULT_MAX_FILES_LOWRAM = 300;
-    private static final int DEFAULT_QUOTA_KB = 10 * 1024;
+    private static final int DEFAULT_QUOTA_KB = Build.IS_USERDEBUG ? 20 * 1024 : 10 * 1024;
     private static final int DEFAULT_QUOTA_PERCENT = 10;
     private static final int DEFAULT_RESERVE_PERCENT = 0;
     private static final int QUOTA_RESCAN_MILLIS = 5000;
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 966478e..a619257 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -138,12 +138,6 @@
 
     static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
 
-    // Time needed to apply mitigation
-    private static final String MITIGATION_WINDOW_MS =
-            "persist.device_config.configuration.mitigation_window_ms";
-    @VisibleForTesting
-    static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5);
-
     // Threshold level at which or above user might experience significant disruption.
     private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
             "persist.device_config.configuration.major_user_impact_level_threshold";
@@ -216,9 +210,6 @@
     @GuardedBy("mLock")
     private boolean mSyncRequired = false;
 
-    @GuardedBy("mLock")
-    private long mLastMitigation = -1000000;
-
     @FunctionalInterface
     @VisibleForTesting
     interface SystemClock {
@@ -409,16 +400,6 @@
             Slog.w(TAG, "Could not resolve a list of failing packages");
             return;
         }
-        synchronized (mLock) {
-            final long now = mSystemClock.uptimeMillis();
-            if (Flags.recoverabilityDetection()) {
-                if (now >= mLastMitigation
-                        && (now - mLastMitigation) < getMitigationWindowMs()) {
-                    Slog.i(TAG, "Skipping onPackageFailure mitigation");
-                    return;
-                }
-            }
-        }
         mLongTaskHandler.post(() -> {
             synchronized (mLock) {
                 if (mAllObservers.isEmpty()) {
@@ -519,17 +500,10 @@
                               int currentObserverImpact,
                               int mitigationCount) {
         if (currentObserverImpact < getUserImpactLevelLimit()) {
-            synchronized (mLock) {
-                mLastMitigation = mSystemClock.uptimeMillis();
-            }
             currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
         }
     }
 
-    private long getMitigationWindowMs() {
-        return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS);
-    }
-
 
     /**
      * Called when the system server boots. If the system server is detected to be in a boot loop,
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 54fb65c4..1ad0abf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -581,7 +581,7 @@
         public RebootEscrowManager getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks,
                 LockSettingsStorage storage) {
             return new RebootEscrowManager(mContext, callbacks, storage,
-                    getHandler(getServiceThread()));
+                    getHandler(getServiceThread()), getUserManagerInternal());
         }
 
         public int binderGetCallingUid() {
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index e1cd2c5..d0b8990 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -51,16 +51,20 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.widget.RebootEscrowListener;
+import com.android.server.pm.UserManagerInternal;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Set;
 
 import javax.crypto.SecretKey;
 
@@ -138,6 +142,7 @@
             ERROR_KEYSTORE_FAILURE,
             ERROR_NO_NETWORK,
             ERROR_TIMEOUT_EXHAUSTED,
+            ERROR_NO_REBOOT_ESCROW_DATA,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface RebootEscrowErrorCode {
@@ -153,6 +158,7 @@
     static final int ERROR_KEYSTORE_FAILURE = 7;
     static final int ERROR_NO_NETWORK = 8;
     static final int ERROR_TIMEOUT_EXHAUSTED = 9;
+    static final int ERROR_NO_REBOOT_ESCROW_DATA = 10;
 
     private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
 
@@ -222,11 +228,16 @@
         private final RebootEscrowKeyStoreManager mKeyStoreManager;
         private final LockSettingsStorage mStorage;
         private RebootEscrowProviderInterface mRebootEscrowProvider;
+        private final UserManagerInternal mUserManagerInternal;
 
-        Injector(Context context, LockSettingsStorage storage) {
+        Injector(
+                Context context,
+                LockSettingsStorage storage,
+                UserManagerInternal userManagerInternal) {
             mContext = context;
             mStorage = storage;
             mKeyStoreManager = new RebootEscrowKeyStoreManager();
+            mUserManagerInternal = userManagerInternal;
         }
 
         private RebootEscrowProviderInterface createRebootEscrowProvider() {
@@ -326,6 +337,10 @@
             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
 
+        public UserManagerInternal getUserManagerInternal() {
+            return mUserManagerInternal;
+        }
+
         public RebootEscrowKeyStoreManager getKeyStoreManager() {
             return mKeyStoreManager;
         }
@@ -402,8 +417,8 @@
     }
 
     RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage,
-            Handler handler) {
-        this(new Injector(context, storage), callbacks, storage, handler);
+                        Handler handler, UserManagerInternal userManagerInternal) {
+        this(new Injector(context, storage, userManagerInternal), callbacks, storage, handler);
     }
 
     @VisibleForTesting
@@ -451,18 +466,50 @@
         onEscrowRestoreComplete(false, attemptCount, retryHandler);
     }
 
-    void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
-        List<UserInfo> users = mUserManager.getUsers();
-        List<UserInfo> rebootEscrowUsers = new ArrayList<>();
+    private List<UserInfo> getUsersToUnlock(List<UserInfo> users) {
+        // System user must be unlocked to unlock any other user
+        if (mCallbacks.isUserSecure(USER_SYSTEM) && !mStorage.hasRebootEscrow(USER_SYSTEM)) {
+            Slog.i(TAG, "No reboot escrow data found for system user");
+            return Collections.emptyList();
+        }
+
+        Set<Integer> noEscrowDataUsers = new HashSet<>();
         for (UserInfo user : users) {
-            if (mCallbacks.isUserSecure(user.id) && mStorage.hasRebootEscrow(user.id)) {
-                rebootEscrowUsers.add(user);
+            if (mCallbacks.isUserSecure(user.id)
+                    && !mStorage.hasRebootEscrow(user.id)) {
+                Slog.d(TAG, "No reboot escrow data found for user " + user);
+                noEscrowDataUsers.add(user.id);
             }
         }
 
+        List<UserInfo> rebootEscrowUsers = new ArrayList<>();
+        for (UserInfo user : users) {
+            // No lskf, no need to unlock.
+            if (!mCallbacks.isUserSecure(user.id)) {
+                continue;
+            }
+            // Don't unlock if user or user's parent does not have reboot data
+            int userId = user.id;
+            if (noEscrowDataUsers.contains(userId)
+                    || noEscrowDataUsers.contains(
+                            mInjector.getUserManagerInternal().getProfileParentId(userId))) {
+                continue;
+            }
+            rebootEscrowUsers.add(user);
+        }
+        return rebootEscrowUsers;
+    }
+
+    void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
+        List<UserInfo> users = mUserManager.getUsers();
+        List<UserInfo> rebootEscrowUsers = getUsersToUnlock(users);
+
         if (rebootEscrowUsers.isEmpty()) {
             Slog.i(TAG, "No reboot escrow data found for users,"
                     + " skipping loading escrow data");
+            setLoadEscrowDataErrorCode(ERROR_NO_REBOOT_ESCROW_DATA, retryHandler);
+            reportMetricOnRestoreComplete(
+                    /* success= */ false, /* attemptCount= */ 1, retryHandler);
             clearMetricsStorage();
             return;
         }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index c8bcc51..e753ce8 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -926,7 +926,9 @@
         }
         Slog.i(TAG, "Enabling rollback for install of " + packageName
                 + ", session:" + session.sessionId
-                + ", rollbackDataPolicy=" + rollbackDataPolicy);
+                + ", rollbackDataPolicy=" + rollbackDataPolicy
+                + ", rollbackId:" + rollback.info.getRollbackId()
+                + ", originalSessionId:" + rollback.getOriginalSessionId());
 
         final String installerPackageName = session.getInstallerPackageName();
         if (!enableRollbackAllowed(installerPackageName, packageName)) {
diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
index c1d92cf..68eb8eb 100644
--- a/services/core/java/com/android/server/tracing/TracingServiceProxy.java
+++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
@@ -93,6 +93,7 @@
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final LruCache<ComponentName, ServiceConnector<IMessenger>> mCachedReporterServices;
+    private boolean mServicePublished = false;
 
     private final ITracingServiceProxy.Stub mTracingServiceProxy = new ITracingServiceProxy.Stub() {
         /**
@@ -122,9 +123,12 @@
     public void onStart() {}
 
     @Override
-    public void onBootPhase(int phase) {
-        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        // We need the device storage to be unlocked before we can accept and forward
+        // requests.
+        if (!mServicePublished) {
             publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy);
+            mServicePublished = true;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 3cf19dd..dd53d32 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -561,32 +561,35 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println("AccessibilityWindowsPopulator");
-        String prefix2 = prefix + "  ";
+        synchronized (mLock) {
+            pw.print(prefix); pw.println("AccessibilityWindowsPopulator");
+            String prefix2 = prefix + "  ";
 
-        pw.print(prefix2); pw.print("mWindowsNotificationEnabled: ");
-        pw.println(mWindowsNotificationEnabled);
+            pw.print(prefix2); pw.print("mWindowsNotificationEnabled: ");
+            pw.println(mWindowsNotificationEnabled);
 
-        if (mVisibleWindows.isEmpty()) {
-            pw.print(prefix2); pw.println("No visible windows");
-        } else {
-            pw.print(prefix2); pw.print(mVisibleWindows.size());
-            pw.print(" visible windows: "); pw.println(mVisibleWindows);
+            if (mVisibleWindows.isEmpty()) {
+                pw.print(prefix2); pw.println("No visible windows");
+            } else {
+                pw.print(prefix2); pw.print(mVisibleWindows.size());
+                pw.print(" visible windows: "); pw.println(mVisibleWindows);
+            }
+            KeyDumper noKeyDumper = (i, k) -> {}; // display id is already shown on value;
+            KeyDumper displayDumper = (i, d) -> pw.printf("%sDisplay #%d: ", prefix, d);
+            // Ideally magnificationSpecDumper should use spec.dump(pw), but there is no such method
+            ValueDumper<MagnificationSpec> magnificationSpecDumper = spec -> pw.print(spec);
+
+            dumpSparseArray(pw, prefix2, mDisplayInfos,
+                    "display info", noKeyDumper, d -> pw.print(d));
+            dumpSparseArray(pw, prefix2, mInputWindowHandlesOnDisplays,
+                    "window handles on display", displayDumper, list -> pw.print(list));
+            dumpSparseArray(pw, prefix2, mMagnificationSpecInverseMatrix,
+                    "magnification spec matrix", noKeyDumper, matrix -> matrix.dump(pw));
+            dumpSparseArray(pw, prefix2, mCurrentMagnificationSpec,
+                    "current magnification spec", noKeyDumper, magnificationSpecDumper);
+            dumpSparseArray(pw, prefix2, mPreviousMagnificationSpec,
+                    "previous magnification spec", noKeyDumper, magnificationSpecDumper);
         }
-        KeyDumper noKeyDumper = (i, k) -> {}; // display id is already shown on value;
-        KeyDumper displayDumper = (i, d) -> pw.printf("%sDisplay #%d: ", prefix, d);
-        // Ideally magnificationSpecDumper should use spec.dump(pw), but there is no such method
-        ValueDumper<MagnificationSpec> magnificationSpecDumper = spec -> pw.print(spec);
-
-        dumpSparseArray(pw, prefix2, mDisplayInfos, "display info", noKeyDumper, d -> pw.print(d));
-        dumpSparseArray(pw, prefix2, mInputWindowHandlesOnDisplays, "window handles on display",
-                displayDumper, list -> pw.print(list));
-        dumpSparseArray(pw, prefix2, mMagnificationSpecInverseMatrix, "magnification spec matrix",
-                noKeyDumper, matrix -> matrix.dump(pw));
-        dumpSparseArray(pw, prefix2, mCurrentMagnificationSpec, "current magnification spec",
-                noKeyDumper, magnificationSpecDumper);
-        dumpSparseArray(pw, prefix2, mPreviousMagnificationSpec, "previous magnification spec",
-                noKeyDumper, magnificationSpecDumper);
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 5d01912..76be8ae 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1257,10 +1257,13 @@
 
             // In a multi-resumed environment, like in a freeform device, the top
             // activity can be resumed, but it might not be the focused app.
-            // Set focused app when top activity is resumed
-            if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null
-                    && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
-                taskDisplayArea.mDisplayContent.setFocusedApp(next);
+            // Set focused app when top activity is resumed. However, we shouldn't do it for a
+            // same task because it can break focused state. (e.g. activity embedding)
+            if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null) {
+                final ActivityRecord focusedApp = taskDisplayArea.mDisplayContent.mFocusedApp;
+                if (focusedApp == null || focusedApp.getTask() != next.getTask()) {
+                    taskDisplayArea.mDisplayContent.setFocusedApp(next);
+                }
             }
             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
                     + "resumed %s", next);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 64e6236..17b499e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -19,6 +19,7 @@
 import static android.content.pm.UserInfo.FLAG_FULL;
 import static android.content.pm.UserInfo.FLAG_PRIMARY;
 import static android.content.pm.UserInfo.FLAG_PROFILE;
+import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID;
 import static android.os.UserHandle.USER_SYSTEM;
 
 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
@@ -32,6 +33,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyByte;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -65,6 +67,7 @@
 
 import com.android.internal.widget.RebootEscrowListener;
 import com.android.server.locksettings.ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection;
+import com.android.server.pm.UserManagerInternal;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -107,6 +110,7 @@
 
     private Context mContext;
     private UserManager mUserManager;
+    private UserManagerInternal mUserManagerInternal;
     private RebootEscrowManager.Callbacks mCallbacks;
     private IRebootEscrow mRebootEscrow;
     private ResumeOnRebootServiceConnection mServiceConnection;
@@ -126,13 +130,15 @@
         long getCurrentTimeMillis();
 
         void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
-                int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
+                          int escrowDurationInSeconds, int vbmetaDigestStatus,
+                          int durationSinceBootComplete);
     }
 
     static class MockInjector extends RebootEscrowManager.Injector {
         private final IRebootEscrow mRebootEscrow;
         private final RebootEscrowProviderInterface mDefaultRebootEscrowProvider;
         private final UserManager mUserManager;
+        private final UserManagerInternal mUserManagerInternal;
         private final MockableRebootEscrowInjected mInjected;
         private final RebootEscrowKeyStoreManager mKeyStoreManager;
         private boolean mServerBased;
@@ -141,12 +147,16 @@
         private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
         private boolean mWaitForInternet;
 
-        MockInjector(Context context, UserManager userManager,
+        MockInjector(
+                Context context,
+                UserManager userManager,
+                UserManagerInternal userManagerInternal,
                 IRebootEscrow rebootEscrow,
                 RebootEscrowKeyStoreManager keyStoreManager,
                 LockSettingsStorageTestable storage,
                 MockableRebootEscrowInjected injected) {
-            super(context, storage);
+            // TODO: change this
+            super(context, storage, userManagerInternal);
             mRebootEscrow = rebootEscrow;
             mServerBased = false;
             mWaitForInternet = false;
@@ -159,16 +169,20 @@
                     };
             mDefaultRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector);
             mUserManager = userManager;
+            mUserManagerInternal = userManagerInternal;
             mKeyStoreManager = keyStoreManager;
             mInjected = injected;
         }
 
-        MockInjector(Context context, UserManager userManager,
+        MockInjector(
+                Context context,
+                UserManager userManager,
+                UserManagerInternal userManagerInternal,
                 ResumeOnRebootServiceConnection serviceConnection,
                 RebootEscrowKeyStoreManager keyStoreManager,
                 LockSettingsStorageTestable storage,
                 MockableRebootEscrowInjected injected) {
-            super(context, storage);
+            super(context, storage, userManagerInternal);
             mRebootEscrow = null;
             mServerBased = true;
             mWaitForInternet = false;
@@ -187,6 +201,7 @@
             mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(
                     storage, injector);
             mUserManager = userManager;
+            mUserManagerInternal = userManagerInternal;
             mKeyStoreManager = keyStoreManager;
             mInjected = injected;
         }
@@ -202,6 +217,11 @@
         }
 
         @Override
+        public UserManagerInternal getUserManagerInternal() {
+            return mUserManagerInternal;
+        }
+
+        @Override
         public boolean serverBasedResumeOnReboot() {
             return mServerBased;
         }
@@ -289,8 +309,8 @@
 
         @Override
         public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
-                int escrowDurationInSeconds, int vbmetaDigestStatus,
-                int durationSinceBootComplete) {
+                                 int escrowDurationInSeconds, int vbmetaDigestStatus,
+                                 int durationSinceBootComplete) {
 
             mInjected.reportMetric(success, errorCode, serviceType, attemptCount,
                     escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete);
@@ -301,6 +321,7 @@
     public void setUp_baseServices() throws Exception {
         mContext = new ContextWrapper(InstrumentationRegistry.getContext());
         mUserManager = mock(UserManager.class);
+        mUserManagerInternal = mock(UserManagerInternal.class);
         mCallbacks = mock(RebootEscrowManager.Callbacks.class);
         mRebootEscrow = mock(IRebootEscrow.class);
         mServiceConnection = mock(ResumeOnRebootServiceConnection.class);
@@ -314,28 +335,43 @@
                 new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings"));
 
         ArrayList<UserInfo> users = new ArrayList<>();
-        users.add(new UserInfo(PRIMARY_USER_ID, "primary", FLAG_PRIMARY));
-        users.add(new UserInfo(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE));
-        users.add(new UserInfo(NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL));
-        users.add(new UserInfo(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL));
+        users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, PRIMARY_USER_ID));
+        users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, PRIMARY_USER_ID));
+        users.add(
+                createUser(
+                        NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL, NO_PROFILE_GROUP_ID));
+        users.add(createUser(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, NO_PROFILE_GROUP_ID));
         when(mUserManager.getUsers()).thenReturn(users);
         when(mCallbacks.isUserSecure(PRIMARY_USER_ID)).thenReturn(true);
         when(mCallbacks.isUserSecure(WORK_PROFILE_USER_ID)).thenReturn(true);
         when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false);
         when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true);
         mInjected = mock(MockableRebootEscrowInjected.class);
-        mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow,
-                mKeyStoreManager, mStorage, mInjected);
+        mMockInjector =
+                new MockInjector(
+                        mContext,
+                        mUserManager,
+                        mUserManagerInternal,
+                        mRebootEscrow,
+                        mKeyStoreManager,
+                        mStorage,
+                        mInjected);
         HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
         thread.start();
         mHandler = new Handler(thread.getLooper());
         mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler);
-
     }
 
     private void setServerBasedRebootEscrowProvider() throws Exception {
-        mMockInjector = new MockInjector(mContext, mUserManager, mServiceConnection,
-                mKeyStoreManager, mStorage, mInjected);
+        mMockInjector =
+                new MockInjector(
+                        mContext,
+                        mUserManager,
+                        mUserManagerInternal,
+                        mServiceConnection,
+                        mKeyStoreManager,
+                        mStorage,
+                        mInjected);
         mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler);
     }
 
@@ -352,6 +388,12 @@
         waitForHandler();
     }
 
+    private UserInfo createUser(int id, String name, int flag, int profileGroupId) {
+        UserInfo user = new UserInfo(id, name, flag);
+        when(mUserManagerInternal.getProfileParentId(eq(id))).thenReturn(profileGroupId);
+        return user;
+    }
+
     @Test
     public void prepareRebootEscrow_Success() throws Exception {
         RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -559,6 +601,172 @@
     }
 
     @Test
+    public void loadRebootEscrowDataIfAvailable_noDataPrimaryUser_Failure() throws Exception {
+        setServerBasedRebootEscrowProvider();
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mServiceConnection);
+
+        // escrow secondary user, don't escrow primary user
+        callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+        when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+                .thenAnswer(invocation -> invocation.getArgument(0));
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+        verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+
+        assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID));
+        assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+        assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+        // pretend reboot happens here
+        when(mInjected.getBootCount()).thenReturn(1);
+        ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+        doNothing()
+                .when(mInjected)
+                .reportMetric(
+                        metricsSuccessCaptor.capture(),
+                        metricsErrorCodeCaptor.capture(),
+                        eq(2) /* Server based */,
+                        eq(1) /* attempt count */,
+                        anyInt(),
+                        eq(0) /* vbmeta status */,
+                        anyInt());
+        mService.loadRebootEscrowDataIfAvailable(null);
+        verify(mServiceConnection, never()).unwrap(any(), anyLong());
+        verify(mCallbacks, never()).onRebootEscrowRestored(anyByte(), any(), anyInt());
+        assertFalse(metricsSuccessCaptor.getValue());
+        assertEquals(
+                Integer.valueOf(RebootEscrowManager.ERROR_NO_REBOOT_ESCROW_DATA),
+                metricsErrorCodeCaptor.getValue());
+    }
+
+    @Test
+    public void loadRebootEscrowDataIfAvailable_noDataSecondaryUser_Success() throws Exception {
+        setServerBasedRebootEscrowProvider();
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mServiceConnection);
+
+        // Setup work profile with secondary user as parent.
+        ArrayList<UserInfo> users = new ArrayList<>();
+        users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, NO_PROFILE_GROUP_ID));
+        users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, SECURE_SECONDARY_USER_ID));
+        users.add(
+                createUser(
+                        SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, SECURE_SECONDARY_USER_ID));
+        when(mUserManager.getUsers()).thenReturn(users);
+
+        // escrow primary user and work profile, don't escrow secondary user
+        callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+        callToRebootEscrowIfNeededAndWait(WORK_PROFILE_USER_ID);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+        when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+                .thenAnswer(invocation -> invocation.getArgument(0));
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+        verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+
+        assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+        assertFalse(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID));
+        assertTrue(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID));
+        assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+        // pretend reboot happens here
+        when(mInjected.getBootCount()).thenReturn(1);
+        ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+        doNothing()
+                .when(mInjected)
+                .reportMetric(
+                        metricsSuccessCaptor.capture(),
+                        eq(0) /* error code */,
+                        eq(2) /* Server based */,
+                        eq(1) /* attempt count */,
+                        anyInt(),
+                        eq(0) /* vbmeta status */,
+                        anyInt());
+        when(mServiceConnection.unwrap(any(), anyLong()))
+                .thenAnswer(invocation -> invocation.getArgument(0));
+
+        mService.loadRebootEscrowDataIfAvailable(null);
+
+        verify(mServiceConnection).unwrap(any(), anyLong());
+        verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID));
+        verify(mCallbacks, never())
+                .onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID));
+        verify(mCallbacks, never())
+                .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID));
+        verify(mCallbacks, never())
+                .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID));
+        assertTrue(metricsSuccessCaptor.getValue());
+    }
+
+    @Test
+    public void loadRebootEscrowDataIfAvailable_noDataWorkProfile_Success() throws Exception {
+        setServerBasedRebootEscrowProvider();
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mServiceConnection);
+
+        // escrow primary user and secondary user, don't escrow work profile
+        callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+        callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+        when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+                .thenAnswer(invocation -> invocation.getArgument(0));
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+        verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+
+        assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+        assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID));
+        assertFalse(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID));
+        assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+        // pretend reboot happens here
+        when(mInjected.getBootCount()).thenReturn(1);
+        ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+        doNothing()
+                .when(mInjected)
+                .reportMetric(
+                        metricsSuccessCaptor.capture(),
+                        eq(0) /* error code */,
+                        eq(2) /* Server based */,
+                        eq(1) /* attempt count */,
+                        anyInt(),
+                        eq(0) /* vbmeta status */,
+                        anyInt());
+        when(mServiceConnection.unwrap(any(), anyLong()))
+                .thenAnswer(invocation -> invocation.getArgument(0));
+
+        mService.loadRebootEscrowDataIfAvailable(null);
+
+        verify(mServiceConnection).unwrap(any(), anyLong());
+        verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID));
+        verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID));
+        verify(mCallbacks, never())
+                .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID));
+        verify(mCallbacks, never())
+                .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID));
+        assertTrue(metricsSuccessCaptor.getValue());
+    }
+
+    @Test
     public void loadRebootEscrowDataIfAvailable_ServerBased_Success() throws Exception {
         setServerBasedRebootEscrowProvider();
 
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index 358c490..b10006f 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -38,6 +38,10 @@
     defaults: ["FlickerTestsDefault"],
     manifest: "AndroidManifest.xml",
     test_config_template: "AndroidTestTemplate.xml",
+    test_suites: [
+        "device-tests",
+        "device-platinum-tests",
+    ],
     srcs: ["src/**/*"],
     static_libs: ["FlickerTestsBase"],
     data: ["trace_config/*"],
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index a8b383c..093923f 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -101,8 +101,8 @@
     private static final String OBSERVER_NAME_2 = "observer2";
     private static final String OBSERVER_NAME_3 = "observer3";
     private static final String OBSERVER_NAME_4 = "observer4";
-    private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(10);
-    private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(50);
+    private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+    private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -1453,8 +1453,7 @@
         raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
                 VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
-        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS
-                - TimeUnit.MINUTES.toMillis(1));
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS);
 
         // The first failure will be outside the threshold.
         raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
@@ -1713,9 +1712,6 @@
             watchdog.onPackageFailure(packages, failureReason);
         }
         mTestLooper.dispatchAll();
-        if (Flags.recoverabilityDetection()) {
-            moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS);
-        }
     }
 
     private PackageWatchdog createWatchdog() {