Merge "Prevent the disabling of specified apps" into main
diff --git a/Android.bp b/Android.bp
index 316555f..19181de 100644
--- a/Android.bp
+++ b/Android.bp
@@ -127,6 +127,7 @@
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
         ":libupdate_engine_aidl",
+        ":libupdate_engine_stable-V2-java-source",
         ":logd_aidl",
         ":resourcemanager_aidl",
         ":storaged_aidl",
@@ -204,6 +205,7 @@
         "apex_aidl_interface-java",
         "packagemanager_aidl-java",
         "framework-protos",
+        "libtombstone_proto_java",
         "updatable-driver-protos",
         "ota_metadata_proto_java",
         "android.hidl.base-V1.0-java",
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index e7adf20..d03bbd2 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -34,7 +34,6 @@
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
-        ":libtombstone_proto-src",
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
     ],
diff --git a/STABILITY_OWNERS b/STABILITY_OWNERS
new file mode 100644
index 0000000..a7ecb4d
--- /dev/null
+++ b/STABILITY_OWNERS
@@ -0,0 +1,2 @@
+gaillard@google.com
+
diff --git a/TEST_MAPPING b/TEST_MAPPING
index eef3d27..8338c33 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -125,6 +125,9 @@
     },
     {
       "name": "vts_treble_vintf_vendor_test"
+    },
+    {
+      "name": "CtsStrictJavaPackagesTestCases"
     }
   ],
   "postsubmit-managedprofile-stress": [
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 28b2d4b..50c9fd3 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -900,6 +900,15 @@
     ],
     api_levels_sdk_type: "system",
     extensions_info_file: ":sdk-extensions-info",
+    dists: [
+        // Make the api-versions.xml file for the system API available in the
+        // sdk build target.
+        {
+            targets: ["sdk"],
+            dest: "api-versions_system.xml",
+            tag: ".api_versions.xml",
+        },
+    ],
 }
 
 // This module can be built with:
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4c2e4fc..8eca0fe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10925,7 +10925,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static int rebootAndApply(@NonNull android.content.Context, @NonNull String, boolean) throws java.io.IOException;
     method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
-    method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
+    method @Deprecated public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
     field public static final int RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME = 2000; // 0x7d0
     field public static final int RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED = 3000; // 0xbb8
     field public static final int RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE = 5000; // 0x1388
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a9b7257..5871717 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1315,9 +1315,7 @@
         if (IS_ENG) return true;
 
         if (IS_TREBLE_ENABLED) {
-            // If we can run this code, the device should already pass AVB.
-            // So, we don't need to check AVB here.
-            int result = VintfObject.verifyWithoutAvb();
+            int result = VintfObject.verifyBuildAtBoot();
 
             if (result != 0) {
                 Slog.e(TAG, "Vendor interface is incompatible, error="
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 7f60a20..2145c1a 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -90,4 +90,8 @@
 per-file Temperature.java = file:/THERMAL_OWNERS
 
 # SecurityStateManager
-per-file *SecurityStateManager* = file:/SECURITY_STATE_OWNERS
\ No newline at end of file
+per-file *SecurityStateManager* = file:/SECURITY_STATE_OWNERS
+
+# SystemConfig
+per-file ISystemConfig.aidl = file:/PACKAGE_MANAGER_OWNERS
+per-file SystemConfigManager.java = file:/PACKAGE_MANAGER_OWNERS
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a3b836a..d002fe1 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -18,8 +18,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,11 +45,8 @@
 import android.util.Log;
 import android.view.Display;
 
-import libcore.io.Streams;
-
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -73,7 +68,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
 
 import sun.security.pkcs.PKCS7;
 import sun.security.pkcs.SignerInfo;
@@ -423,72 +417,43 @@
         } finally {
             raf.close();
         }
-
-        // Additionally verify the package compatibility.
-        if (!readAndVerifyPackageCompatibilityEntry(packageFile)) {
-            throw new SignatureException("package compatibility verification failed");
-        }
     }
 
     /**
      * Verifies the compatibility entry from an {@link InputStream}.
      *
-     * @return the verification result.
+     * @param inputStream The stream that contains the package compatibility info.
+     * @throws IOException Never.
+     * @return {@code true}.
+     * @deprecated This function no longer checks {@code inputStream} and
+     *   unconditionally returns true. Instead, check compatibility when the
+     *   OTA package is generated.
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(
+            publicAlternatives = "Use {@code true} directly",
+            maxTargetSdk = Build.VERSION_CODES.VANILLA_ICE_CREAM)
     private static boolean verifyPackageCompatibility(InputStream inputStream) throws IOException {
-        ArrayList<String> list = new ArrayList<>();
-        ZipInputStream zis = new ZipInputStream(inputStream);
-        ZipEntry entry;
-        while ((entry = zis.getNextEntry()) != null) {
-            long entrySize = entry.getSize();
-            if (entrySize > Integer.MAX_VALUE || entrySize < 0) {
-                throw new IOException(
-                        "invalid entry size (" + entrySize + ") in the compatibility file");
-            }
-            byte[] bytes = new byte[(int) entrySize];
-            Streams.readFully(zis, bytes);
-            list.add(new String(bytes, UTF_8));
-        }
-        if (list.isEmpty()) {
-            throw new IOException("no entries found in the compatibility file");
-        }
-        return (VintfObject.verify(list.toArray(new String[list.size()])) == 0);
-    }
-
-    /**
-     * Reads and verifies the compatibility entry in an OTA zip package. The compatibility entry is
-     * a zip file (inside the OTA package zip).
-     *
-     * @return {@code true} if the entry doesn't exist or verification passes.
-     */
-    private static boolean readAndVerifyPackageCompatibilityEntry(File packageFile)
-            throws IOException {
-        try (ZipFile zip = new ZipFile(packageFile)) {
-            ZipEntry entry = zip.getEntry("compatibility.zip");
-            if (entry == null) {
-                return true;
-            }
-            InputStream inputStream = zip.getInputStream(entry);
-            return verifyPackageCompatibility(inputStream);
-        }
+        return true;
     }
 
     /**
      * Verifies the package compatibility info against the current system.
      *
      * @param compatibilityFile the {@link File} that contains the package compatibility info.
-     * @throws IOException if there were any errors reading the compatibility file.
-     * @return the compatibility verification result.
+     * @throws IOException Never.
+     * @return {@code true}
+     * @deprecated This function no longer checks {@code compatibilityFile} and
+     *   unconditionally returns true. Instead, check compatibility when the
+     *   OTA package is generated.
      *
      * {@hide}
      */
+    @Deprecated
     @SystemApi
     @SuppressLint("RequiresPermission")
     public static boolean verifyPackageCompatibility(File compatibilityFile) throws IOException {
-        try (InputStream inputStream = new FileInputStream(compatibilityFile)) {
-            return verifyPackageCompatibility(inputStream);
-        }
+        return true;
     }
 
     /**
diff --git a/core/java/android/os/UpdateEngineStable.java b/core/java/android/os/UpdateEngineStable.java
new file mode 100644
index 0000000..9e2593e
--- /dev/null
+++ b/core/java/android/os/UpdateEngineStable.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2024 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 android.os;
+
+import android.annotation.IntDef;
+
+/**
+ * UpdateEngineStable handles calls to the update engine stalbe which takes care of A/B OTA updates.
+ * This interface has lesser functionalities than UpdateEngine and doesn't allow cancel.
+ *
+ * <p>The minimal flow is:
+ *
+ * <ol>
+ *   <li>Create a new UpdateEngineStable instance.
+ *   <li>Call {@link #bind}, provide callback function.
+ *   <li>Call {@link #applyPayloadFd}.
+ * </ol>
+ *
+ * The APIs defined in this class and UpdateEngineStableCallback class must be in sync with the ones
+ * in {@code system/update_engine/stable/android/os/IUpdateEngineStable.aidl} and {@code
+ * ssystem/update_engine/stable/android/os/IUpdateEngineStableCallback.aidl}.
+ *
+ * @hide
+ */
+public class UpdateEngineStable {
+    private static final String TAG = "UpdateEngineStable";
+
+    private static final String UPDATE_ENGINE_STABLE_SERVICE =
+            "android.os.UpdateEngineStableService";
+
+    /**
+     * Error codes from update engine upon finishing a call to {@link applyPayloadFd}. Values will
+     * be passed via the callback function {@link
+     * UpdateEngineStableCallback#onPayloadApplicationComplete}. Values must agree with the ones in
+     * {@code system/update_engine/common/error_code.h}.
+     */
+    /** @hide */
+    @IntDef(
+            value = {
+                UpdateEngine.ErrorCodeConstants.SUCCESS,
+                UpdateEngine.ErrorCodeConstants.ERROR,
+                UpdateEngine.ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
+                UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+                UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+                UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+                UpdateEngine.ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
+                UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+                UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
+                UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+                UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+                UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+                UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+                UpdateEngine.ErrorCodeConstants.NOT_ENOUGH_SPACE,
+                UpdateEngine.ErrorCodeConstants.DEVICE_CORRUPTED,
+            })
+    public @interface ErrorCode {}
+
+    private final IUpdateEngineStable mUpdateEngineStable;
+    private IUpdateEngineStableCallback mUpdateEngineStableCallback = null;
+    private final Object mUpdateEngineStableCallbackLock = new Object();
+
+    /**
+     * Creates a new instance.
+     *
+     * @hide
+     */
+    public UpdateEngineStable() {
+        mUpdateEngineStable =
+                IUpdateEngineStable.Stub.asInterface(
+                        ServiceManager.getService(UPDATE_ENGINE_STABLE_SERVICE));
+        if (mUpdateEngineStable == null) {
+            throw new IllegalStateException("Failed to find " + UPDATE_ENGINE_STABLE_SERVICE);
+        }
+    }
+
+    /**
+     * Prepares this instance for use. The callback will be notified on any status change, and when
+     * the update completes. A handler can be supplied to control which thread runs the callback, or
+     * null.
+     *
+     * @hide
+     */
+    public boolean bind(final UpdateEngineStableCallback callback, final Handler handler) {
+        synchronized (mUpdateEngineStableCallbackLock) {
+            mUpdateEngineStableCallback =
+                    new IUpdateEngineStableCallback.Stub() {
+                        @Override
+                        public void onStatusUpdate(final int status, final float percent) {
+                            if (handler != null) {
+                                handler.post(
+                                        new Runnable() {
+                                            @Override
+                                            public void run() {
+                                                callback.onStatusUpdate(status, percent);
+                                            }
+                                        });
+                            } else {
+                                callback.onStatusUpdate(status, percent);
+                            }
+                        }
+
+                        @Override
+                        public void onPayloadApplicationComplete(final int errorCode) {
+                            if (handler != null) {
+                                handler.post(
+                                        new Runnable() {
+                                            @Override
+                                            public void run() {
+                                                callback.onPayloadApplicationComplete(errorCode);
+                                            }
+                                        });
+                            } else {
+                                callback.onPayloadApplicationComplete(errorCode);
+                            }
+                        }
+
+                        @Override
+                        public int getInterfaceVersion() {
+                            return super.VERSION;
+                        }
+
+                        @Override
+                        public String getInterfaceHash() {
+                            return super.HASH;
+                        }
+                    };
+
+            try {
+                return mUpdateEngineStable.bind(mUpdateEngineStableCallback);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Equivalent to {@code bind(callback, null)}.
+     *
+     * @hide
+     */
+    public boolean bind(final UpdateEngineStableCallback callback) {
+        return bind(callback, null);
+    }
+
+    /**
+     * Applies payload from given ParcelFileDescriptor. Usage is same as UpdateEngine#applyPayload
+     *
+     * @hide
+     */
+    public void applyPayloadFd(
+            ParcelFileDescriptor fd, long offset, long size, String[] headerKeyValuePairs) {
+        try {
+            mUpdateEngineStable.applyPayloadFd(fd, offset, size, headerKeyValuePairs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unbinds the last bound callback function.
+     *
+     * @hide
+     */
+    public boolean unbind() {
+        synchronized (mUpdateEngineStableCallbackLock) {
+            if (mUpdateEngineStableCallback == null) {
+                return true;
+            }
+            try {
+                boolean result = mUpdateEngineStable.unbind(mUpdateEngineStableCallback);
+                mUpdateEngineStableCallback = null;
+                return result;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+}
diff --git a/core/java/android/os/UpdateEngineStableCallback.java b/core/java/android/os/UpdateEngineStableCallback.java
new file mode 100644
index 0000000..4bcfb4b
--- /dev/null
+++ b/core/java/android/os/UpdateEngineStableCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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 android.os;
+
+/**
+ * Callback function for UpdateEngineStable. Used to keep the caller up to date with progress, so
+ * the UI (if any) can be updated.
+ *
+ * <p>The APIs defined in this class and UpdateEngineStable class must be in sync with the ones in
+ * system/update_engine/stable/android/os/IUpdateEngineStable.aidl and
+ * system/update_engine/stable/android/os/IUpdateEngineStableCallback.aidl.
+ *
+ * <p>{@hide}
+ */
+public abstract class UpdateEngineStableCallback {
+
+    /**
+     * Invoked when anything changes. The value of {@code status} will be one of the values from
+     * {@link UpdateEngine.UpdateStatusConstants}, and {@code percent} will be valid
+     *
+     * @hide
+     */
+    public abstract void onStatusUpdate(int status, float percent);
+
+    /**
+     * Invoked when the payload has been applied, whether successfully or unsuccessfully. The value
+     * of {@code errorCode} will be one of the values from {@link UpdateEngine.ErrorCodeConstants}.
+     *
+     * @hide
+     */
+    public abstract void onPayloadApplicationComplete(@UpdateEngineStable.ErrorCode int errorCode);
+}
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 1f11197..4fc5131 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.util.Slog;
 
 import java.util.Map;
 
@@ -44,44 +43,8 @@
     public static native String[] report();
 
     /**
-     * Verify that the given metadata for an OTA package is compatible with
-     * this device.
-     *
-     * @param packageInfo a list of serialized form of HalManifest's /
-     * CompatibilityMatri'ces (XML).
-     * @return = 0 if success (compatible)
-     *         &gt; 0 if incompatible
-     *         &lt; 0 if any error (mount partition fails, illformed XML, etc.)
-     *
-     * @deprecated Checking compatibility against an OTA package is no longer
-     * supported because the format of VINTF metadata in the OTA package may not
-     * be recognized by the current system.
-     *
-     * <p>
-     * <ul>
-     * <li>This function always returns 0 for non-empty {@code packageInfo}.
-     * </li>
-     * <li>This function returns the result of {@link #verifyWithoutAvb} for
-     * null or empty {@code packageInfo}.</li>
-     * </ul>
-     *
-     * @hide
-     */
-    @Deprecated
-    public static int verify(String[] packageInfo) {
-        if (packageInfo != null && packageInfo.length > 0) {
-            Slog.w(LOG_TAG, "VintfObject.verify() with non-empty packageInfo is deprecated. "
-                    + "Skipping compatibility checks for update package.");
-            return 0;
-        }
-        Slog.w(LOG_TAG, "VintfObject.verify() is deprecated. Call verifyWithoutAvb() instead.");
-        return verifyWithoutAvb();
-    }
-
-    /**
-     * Verify Vintf compatibility on the device without checking AVB
-     * (Android Verified Boot). It is useful to verify a running system
-     * image where AVB check is irrelevant.
+     * Verify Vintf compatibility on the device at boot time. Certain checks
+     * like kernel checks, AVB checks are disabled.
      *
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
@@ -89,7 +52,7 @@
      *
      * @hide
      */
-    public static native int verifyWithoutAvb();
+    public static native int verifyBuildAtBoot();
 
     /**
      * @return a list of HAL names and versions that is supported by this
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 59b945c..db48bad 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -366,11 +366,13 @@
          * <p>
          * As of Android 11 apps will need specific permission to query other packages. To use
          * this method an app must include in their AndroidManifest:
+         * <pre>{@code
          * <queries>
          *   <intent>
          *     <action android:name="android.provider.Telephony.SMS_DELIVER"/>
          *   </intent>
          * </queries>
+         * }</pre>
          * Which will allow them to query packages which declare intent filters that include
          * the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} intent.
          * </p>
diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS
deleted file mode 100644
index 1c2d19d..0000000
--- a/core/java/com/android/server/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 1baea2a..b651711 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -46,6 +46,7 @@
 using vintf::Version;
 using vintf::VintfObject;
 using vintf::Vndk;
+using vintf::CheckFlags::ENABLE_ALL_CHECKS;
 
 template<typename V>
 static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
@@ -93,12 +94,13 @@
     return toJavaStringArray(env, cStrings);
 }
 
-static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) {
+static jint android_os_VintfObject_verifyBuildAtBoot(JNIEnv* env, jclass) {
     std::string error;
-    int32_t status = VintfObject::GetInstance()->checkCompatibility(&error,
-            ::android::vintf::CheckFlags::DISABLE_AVB_CHECK);
+    int32_t status =
+            VintfObject::GetInstance()
+                    ->checkCompatibility(&error, ENABLE_ALL_CHECKS.disableAvb().disableKernel());
     if (status)
-        LOG(WARNING) << "VintfObject.verifyWithoutAvb() returns " << status << ": " << error;
+        LOG(WARNING) << "VintfObject.verifyBuildAtBoot() returns " << status << ": " << error;
     return status;
 }
 
@@ -170,7 +172,7 @@
 
 static const JNINativeMethod gVintfObjectMethods[] = {
         {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
-        {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb},
+        {"verifyBuildAtBoot", "()I", (void*)android_os_VintfObject_verifyBuildAtBoot},
         {"getHalNamesAndVersions", "()[Ljava/lang/String;",
          (void*)android_os_VintfObject_getHalNamesAndVersions},
         {"getSepolicyVersion", "()Ljava/lang/String;",
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index 95bb42e..ef0750c 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -164,7 +164,7 @@
             }
 
             default:
-                CHECK(!"Should not be here");
+                CHECK(!"Should not be here") << "Item type: " << item.mType;
         }
     }
 
diff --git a/data/keyboards/Android.bp b/data/keyboards/Android.bp
new file mode 100644
index 0000000..f15c153
--- /dev/null
+++ b/data/keyboards/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2010 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.
+
+genrule {
+    name: "validate_framework_keymaps",
+    srcs: [
+        "*.kl",
+        "*.kcm",
+        "*.idc",
+    ],
+    tools: ["validatekeymaps"],
+    out: ["stamp"],
+    cmd: "$(location validatekeymaps) -q $(in) " +
+        "&& touch $(out)",
+    dist: {
+        targets: ["droidcore"],
+    },
+}
diff --git a/data/keyboards/Android.mk b/data/keyboards/Android.mk
deleted file mode 100644
index 6ae8800..0000000
--- a/data/keyboards/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2010 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.
-
-# This makefile performs build time validation of framework keymap files.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(LOCAL_PATH)/common.mk
-
-# Validate all key maps.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := validate_framework_keymaps
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
-LOCAL_BUILT_MODULE := $(intermediates)/stamp
-
-validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
-$(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
-$(LOCAL_BUILT_MODULE) : $(framework_keylayouts) $(framework_keycharmaps) $(framework_keyconfigs) | $(validatekeymaps)
-	$(hide) $(PRIVATE_VALIDATEKEYMAPS) -q $^
-	$(hide) mkdir -p $(dir $@) && touch $@
-
-# Run validatekeymaps uncondionally for platform build.
-droidcore : $(LOCAL_BUILT_MODULE)
-
-# Reset temp vars.
-validatekeymaps :=
-framework_keylayouts :=
-framework_keycharmaps :=
-framework_keyconfigs :=
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
deleted file mode 100644
index d75b691..0000000
--- a/data/keyboards/common.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2010 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.
-
-# This is the list of framework provided keylayouts and key character maps to include.
-# Used by Android.mk and keyboards.mk.
-
-framework_keylayouts := $(wildcard $(LOCAL_PATH)/*.kl)
-
-framework_keycharmaps := $(wildcard $(LOCAL_PATH)/*.kcm)
-
-framework_keyconfigs := $(wildcard $(LOCAL_PATH)/*.idc)
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 926d7a4..5cdfca7 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -48,6 +48,8 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.am.DropboxRateLimiter;
+import com.android.server.os.TombstoneProtos;
+import com.android.server.os.TombstoneProtos.Tombstone;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -60,11 +62,14 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.attribute.PosixFilePermissions;
+import java.util.AbstractMap;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * Performs a number of miscellaneous, non-system-critical actions
@@ -327,12 +332,12 @@
      *
      * @param ctx Context
      * @param tombstone path to the tombstone
-     * @param proto whether the tombstone is stored as proto
+     * @param tombstoneProto the parsed proto tombstone
      * @param processName the name of the process corresponding to the tombstone
      * @param tmpFileLock the lock for reading/writing tmp files
      */
     public static void addTombstoneToDropBox(
-                Context ctx, File tombstone, boolean proto, String processName,
+                Context ctx, File tombstone, Tombstone tombstoneProto, String processName,
                 ReentrantLock tmpFileLock) {
         final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
         if (db == null) {
@@ -342,31 +347,33 @@
 
         // Check if we should rate limit and abort early if needed.
         DropboxRateLimiter.RateLimitResult rateLimitResult =
-                sDropboxRateLimiter.shouldRateLimit(
-                        proto ? TAG_TOMBSTONE_PROTO_WITH_HEADERS : TAG_TOMBSTONE, processName);
+                sDropboxRateLimiter.shouldRateLimit(TAG_TOMBSTONE_PROTO_WITH_HEADERS, processName);
         if (rateLimitResult.shouldRateLimit()) return;
 
         HashMap<String, Long> timestamps = readTimestamps();
         try {
-            if (proto) {
-                if (recordFileTimestamp(tombstone, timestamps)) {
-                    // We need to attach the count indicating the number of dropped dropbox entries
-                    // due to rate limiting. Do this by enclosing the proto tombsstone in a
-                    // container proto that has the dropped entry count and the proto tombstone as
-                    // bytes (to avoid the complexity of reading and writing nested protos).
-                    tmpFileLock.lock();
-                    try {
-                        addAugmentedProtoToDropbox(tombstone, db, rateLimitResult);
-                    } finally {
-                        tmpFileLock.unlock();
-                    }
+            // Remove the memory data from the proto.
+            Tombstone tombstoneProtoWithoutMemory = removeMemoryFromTombstone(tombstoneProto);
+
+            final byte[] tombstoneBytes = tombstoneProtoWithoutMemory.toByteArray();
+
+            // Use JNI to call the c++ proto to text converter and add the headers to the tombstone.
+            String tombstoneWithoutMemory = new StringBuilder(getBootHeadersToLogAndUpdate())
+                    .append(rateLimitResult.createHeader())
+                    .append(getTombstoneText(tombstoneBytes))
+                    .toString();
+
+            // Add the tombstone without memory data to dropbox.
+            db.addText(TAG_TOMBSTONE, tombstoneWithoutMemory);
+
+            // Add the tombstone proto to dropbox.
+            if (recordFileTimestamp(tombstone, timestamps)) {
+                tmpFileLock.lock();
+                try {
+                    addAugmentedProtoToDropbox(tombstone, tombstoneBytes, db, rateLimitResult);
+                } finally {
+                    tmpFileLock.unlock();
                 }
-            } else {
-                // Add the header indicating how many events have been dropped due to rate limiting.
-                final String headers = getBootHeadersToLogAndUpdate()
-                        + rateLimitResult.createHeader();
-                addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE,
-                                 TAG_TOMBSTONE);
             }
         } catch (IOException e) {
             Slog.e(TAG, "Can't log tombstone", e);
@@ -375,11 +382,8 @@
     }
 
     private static void addAugmentedProtoToDropbox(
-                File tombstone, DropBoxManager db,
+                File tombstone, byte[] tombstoneBytes, DropBoxManager db,
                 DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException {
-        // Read the proto tombstone file as bytes.
-        final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());
-
         final File tombstoneProtoWithHeaders = File.createTempFile(
                 tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
         Files.setPosixFilePermissions(
@@ -412,6 +416,8 @@
         }
     }
 
+    private static native String getTombstoneText(byte[] tombstoneBytes);
+
     private static void addLastkToDropBox(
             DropBoxManager db, HashMap<String, Long> timestamps,
             String headers, String footers, String filename, int maxSize,
@@ -429,6 +435,31 @@
         addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag);
     }
 
+    /** Removes memory information from the Tombstone proto. */
+    @VisibleForTesting
+    public static Tombstone removeMemoryFromTombstone(Tombstone tombstoneProto) {
+        Tombstone.Builder tombstoneBuilder = tombstoneProto.toBuilder()
+                .clearMemoryMappings()
+                .clearThreads()
+                .putAllThreads(tombstoneProto.getThreadsMap().entrySet()
+                        .stream()
+                        .map(BootReceiver::clearMemoryDump)
+                        .collect(Collectors.toMap(e->e.getKey(), e->e.getValue())));
+
+        if (tombstoneProto.hasSignalInfo()) {
+            tombstoneBuilder.setSignalInfo(
+                    tombstoneProto.getSignalInfo().toBuilder().clearFaultAdjacentMetadata());
+        }
+
+        return tombstoneBuilder.build();
+    }
+
+    private static AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread> clearMemoryDump(
+            Map.Entry<Integer, TombstoneProtos.Thread> e) {
+        return new AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread>(
+            e.getKey(), e.getValue().toBuilder().clearMemoryDump().build());
+    }
+
     private static void addFileToDropBox(
             DropBoxManager db, HashMap<String, Long> timestamps,
             String headers, String filename, int maxSize, String tag) throws IOException {
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index a2d7a81..5335cc3 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -43,3 +43,6 @@
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
 per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS
 per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS
+
+# SystemConfig
+per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1595a35..490aa1f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3215,7 +3215,7 @@
         super.createUserStorageKeys_enforcePermission();
 
         try {
-            mVold.createUserStorageKeys(userId, serialNumber, ephemeral);
+            mVold.createUserStorageKeys(userId, ephemeral);
             // Since the user's CE key was just created, the user's CE storage is now unlocked.
             synchronized (mLock) {
                 mCeUnlockedUsers.append(userId);
@@ -3260,7 +3260,7 @@
         super.unlockCeStorage_enforcePermission();
 
         if (StorageManager.isFileEncrypted()) {
-            mVold.unlockCeStorage(userId, serialNumber, HexDump.toHexString(secret));
+            mVold.unlockCeStorage(userId, HexDump.toHexString(secret));
         }
         synchronized (mLock) {
             mCeUnlockedUsers.append(userId);
@@ -3347,7 +3347,7 @@
     private void prepareUserStorageInternal(String volumeUuid, int userId, int serialNumber,
             int flags) throws Exception {
         try {
-            mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
+            mVold.prepareUserStorage(volumeUuid, userId, flags);
             // After preparing user storage, we should check if we should mount data mirror again,
             // and we do it for user 0 only as we only need to do once for all users.
             if (volumeUuid != null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 39d9b45..e9acce6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7629,7 +7629,6 @@
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
         DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
-        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI);
     }
 
     /** only public for mocking/spying, do not call outside of AudioService */
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index ab0d0d2..b7e7374 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -41,14 +41,13 @@
 import android.system.StructStat;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.proto.ProtoInputStream;
-import android.util.proto.ProtoParseException;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.BootReceiver;
 import com.android.server.ServiceThread;
 import com.android.server.os.TombstoneProtos.Cause;
 import com.android.server.os.TombstoneProtos.Tombstone;
+import com.android.server.os.protobuf.CodedInputStream;
 
 import libcore.io.IoUtils;
 
@@ -128,18 +127,21 @@
             return;
         }
 
-        String processName = "UNKNOWN";
         final boolean isProtoFile = filename.endsWith(".pb");
-        File protoPath = isProtoFile ? path : new File(path.getAbsolutePath() + ".pb");
-
-        Optional<TombstoneFile> parsedTombstone = handleProtoTombstone(protoPath, isProtoFile);
-        if (parsedTombstone.isPresent()) {
-            processName = parsedTombstone.get().getProcessName();
+        if (!isProtoFile) {
+            return;
         }
-        BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock);
+
+        Optional<ParsedTombstone> parsedTombstone = handleProtoTombstone(path, true);
+        if (parsedTombstone.isPresent()) {
+            BootReceiver.addTombstoneToDropBox(
+                    mContext, path, parsedTombstone.get().getTombstone(),
+                    parsedTombstone.get().getProcessName(), mTmpFileLock);
+        }
     }
 
-    private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) {
+    private Optional<ParsedTombstone> handleProtoTombstone(
+            File path, boolean addToList) {
         final String filename = path.getName();
         if (!filename.endsWith(".pb")) {
             Slog.w(TAG, "unexpected tombstone name: " + path);
@@ -169,7 +171,7 @@
             return Optional.empty();
         }
 
-        final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd);
+        final Optional<ParsedTombstone> parsedTombstone = TombstoneFile.parse(pfd);
         if (!parsedTombstone.isPresent()) {
             IoUtils.closeQuietly(pfd);
             return Optional.empty();
@@ -182,7 +184,7 @@
                     previous.dispose();
                 }
 
-                mTombstones.put(number, parsedTombstone.get());
+                mTombstones.put(number, parsedTombstone.get().getTombstoneFile());
             }
         }
 
@@ -330,6 +332,27 @@
         }
     }
 
+    static class ParsedTombstone {
+        TombstoneFile mTombstoneFile;
+        Tombstone mTombstone;
+        ParsedTombstone(TombstoneFile tombstoneFile, Tombstone tombstone) {
+            mTombstoneFile = tombstoneFile;
+            mTombstone = tombstone;
+        }
+
+        public String getProcessName() {
+            return mTombstoneFile.getProcessName();
+        }
+
+        public TombstoneFile getTombstoneFile() {
+            return mTombstoneFile;
+        }
+
+        public Tombstone getTombstone() {
+            return mTombstone;
+        }
+    }
+
     static class TombstoneFile {
         final ParcelFileDescriptor mPfd;
 
@@ -412,67 +435,21 @@
             }
         }
 
-        static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) {
-            final FileInputStream is = new FileInputStream(pfd.getFileDescriptor());
-            final ProtoInputStream stream = new ProtoInputStream(is);
+        static Optional<ParsedTombstone> parse(ParcelFileDescriptor pfd) {
+            Tombstone tombstoneProto;
+            try (FileInputStream is = new FileInputStream(pfd.getFileDescriptor())) {
+                final byte[] tombstoneBytes = is.readAllBytes();
 
-            int pid = 0;
-            int uid = 0;
-            String processName = null;
-            String crashReason = "";
-            String selinuxLabel = "";
-
-            try {
-                while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                    switch (stream.getFieldNumber()) {
-                        case (int) Tombstone.PID:
-                            pid = stream.readInt(Tombstone.PID);
-                            break;
-
-                        case (int) Tombstone.UID:
-                            uid = stream.readInt(Tombstone.UID);
-                            break;
-
-                        case (int) Tombstone.COMMAND_LINE:
-                            if (processName == null) {
-                                processName = stream.readString(Tombstone.COMMAND_LINE);
-                            }
-                            break;
-
-                        case (int) Tombstone.CAUSES:
-                            if (!crashReason.equals("")) {
-                                // Causes appear in decreasing order of likelihood. For now we only
-                                // want the most likely crash reason here, so ignore all others.
-                                break;
-                            }
-                            long token = stream.start(Tombstone.CAUSES);
-                        cause:
-                            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                                switch (stream.getFieldNumber()) {
-                                    case (int) Cause.HUMAN_READABLE:
-                                        crashReason = stream.readString(Cause.HUMAN_READABLE);
-                                        break cause;
-
-                                    default:
-                                        break;
-                                }
-                            }
-                            stream.end(token);
-                            break;
-
-                        case (int) Tombstone.SELINUX_LABEL:
-                            selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL);
-                            break;
-
-                        default:
-                            break;
-                    }
-                }
-            } catch (IOException | ProtoParseException ex) {
+                tombstoneProto = Tombstone.parseFrom(
+                        CodedInputStream.newInstance(tombstoneBytes));
+            } catch (IOException ex) {
                 Slog.e(TAG, "Failed to parse tombstone", ex);
                 return Optional.empty();
             }
 
+            int pid = tombstoneProto.getPid();
+            int uid = tombstoneProto.getUid();
+
             if (!UserHandle.isApp(uid)) {
                 Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring");
                 return Optional.empty();
@@ -489,6 +466,7 @@
             final int userId = UserHandle.getUserId(uid);
             final int appId = UserHandle.getAppId(uid);
 
+            String selinuxLabel = tombstoneProto.getSelinuxLabel();
             if (!selinuxLabel.startsWith("u:r:untrusted_app")) {
                 Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring");
                 return Optional.empty();
@@ -500,11 +478,30 @@
             result.mAppId = appId;
             result.mPid = pid;
             result.mUid = uid;
-            result.mProcessName = processName == null ? "" : processName;
+            result.mProcessName = getCmdLineProcessName(tombstoneProto);
             result.mTimestampMs = timestampMs;
-            result.mCrashReason = crashReason;
+            result.mCrashReason = getCrashReason(tombstoneProto);
 
-            return Optional.of(result);
+            return Optional.of(new ParsedTombstone(result, tombstoneProto));
+        }
+
+        private static String getCmdLineProcessName(Tombstone tombstoneProto) {
+            for (String cmdline : tombstoneProto.getCommandLineList()) {
+                if (cmdline != null) {
+                    return cmdline;
+                }
+            }
+            return "";
+        }
+
+        private static String getCrashReason(Tombstone tombstoneProto) {
+            for (Cause cause : tombstoneProto.getCausesList()) {
+                if (cause.getHumanReadable() != null
+                        && !cause.getHumanReadable().equals("")) {
+                    return cause.getHumanReadable();
+                }
+            }
+            return "";
         }
 
         public IParcelFileDescriptorRetriever getPfdRetriever() {
diff --git a/services/core/java/com/android/server/trust/TEST_MAPPING b/services/core/java/com/android/server/trust/TEST_MAPPING
index fa46acd..0de7c28 100644
--- a/services/core/java/com/android/server/trust/TEST_MAPPING
+++ b/services/core/java/com/android/server/trust/TEST_MAPPING
@@ -12,6 +12,19 @@
         ]
       }
     ],
+    "postsubmit": [
+      {
+        "name": "FrameworksMockingServicesTests",
+        "options": [
+          {
+            "include-filter": "com.android.server.trust"
+          },
+          {
+            "exclude-annotation": "androidx.test.filters.FlakyTest"
+          }
+        ]
+      }
+    ],
     "trust-tablet": [
       {
         "name": "TrustTests",
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 1ebad9b..002bb62 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -75,6 +75,7 @@
 import android.view.WindowManagerGlobal;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.DumpUtils;
@@ -1441,6 +1442,13 @@
         if (biometricManager == null) {
             return new long[0];
         }
+        if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()
+                && mLockPatternUtils.isProfileWithUnifiedChallenge(userId)) {
+            // Profiles with unified challenge have their own set of biometrics, but the device
+            // unlock happens via the parent user.  In this case Keystore needs to be given the list
+            // of biometric SIDs from the parent user, not the profile.
+            userId = resolveProfileParent(userId);
+        }
         return biometricManager.getAuthenticatorIds(userId);
     }
 
@@ -1807,6 +1815,11 @@
         }
     };
 
+    @VisibleForTesting
+    void waitForIdle() {
+        mHandler.runWithScissors(() -> {}, 0);
+    }
+
     private boolean isTrustUsuallyManagedInternal(int userId) {
         synchronized (mTrustUsuallyManagedForUser) {
             int i = mTrustUsuallyManagedForUser.indexOfKey(userId);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e51afbe..0bc60cd 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4708,6 +4708,7 @@
         }
         if (top.isAttached()) {
             top.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+            top.mWaitForEnteringPinnedMode = false;
         }
     }
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 8cd55c7..591a559 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -37,6 +37,7 @@
         "com_android_server_adb_AdbDebuggingManager.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
+        "com_android_server_BootReceiver.cpp",
         "com_android_server_ConsumerIrService.cpp",
         "com_android_server_companion_virtual_InputController.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
@@ -91,6 +92,16 @@
     header_libs: [
         "bionic_libc_platform_headers",
     ],
+
+    static_libs: [
+        "libunwindstack",
+    ],
+
+    whole_static_libs: [
+        "libdebuggerd_tombstone_proto_to_text",
+    ],
+
+    runtime_libs: ["libdexfile"],
 }
 
 cc_defaults {
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index d4f6312..33d3686 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -32,3 +32,7 @@
 
 # Bug component : 158088 = per-file *AnrTimer*
 per-file *AnrTimer* = file:/PERFORMANCE_OWNERS
+
+# Bug component : 158088 = per-file com_android_server_utils_AnrTimer*.java
+per-file com_android_server_utils_AnrTimer*.java = file:/PERFORMANCE_OWNERS
+per-file com_android_server_BootReceiver.cpp = file:/STABILITY_OWNERS
diff --git a/services/core/jni/com_android_server_BootReceiver.cpp b/services/core/jni/com_android_server_BootReceiver.cpp
new file mode 100644
index 0000000..3892d28
--- /dev/null
+++ b/services/core/jni/com_android_server_BootReceiver.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <libdebuggerd/tombstone.h>
+#include <nativehelper/JNIHelp.h>
+
+#include <sstream>
+
+#include "jni.h"
+#include "tombstone.pb.h"
+
+namespace android {
+
+static void writeToString(std::stringstream& ss, const std::string& line, bool should_log) {
+    ss << line << std::endl;
+}
+
+static jstring com_android_server_BootReceiver_getTombstoneText(JNIEnv* env, jobject,
+                                                                jbyteArray tombstoneBytes) {
+    Tombstone tombstone;
+    tombstone.ParseFromArray(env->GetByteArrayElements(tombstoneBytes, 0),
+                             env->GetArrayLength(tombstoneBytes));
+
+    std::stringstream tombstoneString;
+
+    tombstone_proto_to_text(tombstone,
+                            std::bind(&writeToString, std::ref(tombstoneString),
+                                      std::placeholders::_1, std::placeholders::_2));
+
+    return env->NewStringUTF(tombstoneString.str().c_str());
+}
+
+static const JNINativeMethod sMethods[] = {
+        /* name, signature, funcPtr */
+        {"getTombstoneText", "([B)Ljava/lang/String;",
+         (jstring*)com_android_server_BootReceiver_getTombstoneText},
+};
+
+int register_com_android_server_BootReceiver(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/server/BootReceiver", sMethods,
+                                    NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index a87902f..e7de081 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -63,6 +63,7 @@
 int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
 int register_android_server_companion_virtual_InputController(JNIEnv* env);
 int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_com_android_server_BootReceiver(JNIEnv* env);
 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
 int register_com_android_server_display_DisplayControl(JNIEnv* env);
 int register_com_android_server_SystemClockTime(JNIEnv* env);
@@ -122,6 +123,7 @@
     register_android_server_sensor_SensorService(vm, env);
     register_android_server_companion_virtual_InputController(env);
     register_android_server_app_GameManagerService(env);
+    register_com_android_server_BootReceiver(env);
     register_com_android_server_wm_TaskFpsCallbackController(env);
     register_com_android_server_display_DisplayControl(env);
     register_com_android_server_SystemClockTime(env);
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
index 52eae21..a70802a 100644
--- a/services/robotests/Android.bp
+++ b/services/robotests/Android.bp
@@ -57,9 +57,13 @@
     ],
     static_libs: [
         "androidx.test.ext.truth",
+        "Settings-robo-testutils",
+        "SettingsLib-robo-testutils",
     ],
 
     instrumentation_for: "FrameworksServicesLib",
+
+    upstream: true,
 }
 
 filegroup {
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index 66ee696..fba2cad 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -56,6 +56,8 @@
     // Include the testing libraries
     libs: [
         "mockito-robolectric-prebuilt",
+        "Settings-robo-testutils",
+        "SettingsLib-robo-testutils",
         "platform-test-annotations",
         "testng",
         "truth",
@@ -63,4 +65,6 @@
 
     instrumentation_for: "BackupFrameworksServicesLib",
 
+    upstream: true,
+
 }
diff --git a/services/robotests/backup/config/robolectric.properties b/services/robotests/backup/config/robolectric.properties
index 850557a..1ebf6d4 100644
--- a/services/robotests/backup/config/robolectric.properties
+++ b/services/robotests/backup/config/robolectric.properties
@@ -1 +1,3 @@
-sdk=NEWEST_SDK
\ No newline at end of file
+sdk=NEWEST_SDK
+looperMode=LEGACY
+shadows=com.android.server.testing.shadows.FrameworkShadowLooper
diff --git a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
index ee5a534..6839a06 100644
--- a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
@@ -57,6 +57,7 @@
             ShadowBackupDataOutput.class,
             ShadowEnvironment.class,
             ShadowFullBackup.class,
+            ShadowSigningInfo.class,
         })
 public class AppMetadataBackupWriterTest {
     private static final String TEST_PACKAGE = "com.test.package";
diff --git a/services/robotests/backup/src/com/android/server/backup/fullbackup/ShadowSigningInfo.java b/services/robotests/backup/src/com/android/server/backup/fullbackup/ShadowSigningInfo.java
new file mode 100644
index 0000000..53d807c
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/fullbackup/ShadowSigningInfo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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.server.backup.fullbackup;
+
+import static android.os.Build.VERSION_CODES.P;
+
+import android.content.pm.SigningInfo;
+
+import org.robolectric.annotation.Implements;
+
+@Implements(value = SigningInfo.class, minSdk = P)
+public class ShadowSigningInfo {
+}
diff --git a/services/robotests/src/com/android/server/location/gnss/NtpNetworkTimeHelperTest.java b/services/robotests/src/com/android/server/location/gnss/NtpNetworkTimeHelperTest.java
index 4949091..0092763 100644
--- a/services/robotests/src/com/android/server/location/gnss/NtpNetworkTimeHelperTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/NtpNetworkTimeHelperTest.java
@@ -35,6 +35,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowLooper;
 
 import java.util.concurrent.CountDownLatch;
@@ -45,6 +46,7 @@
  */
 @RunWith(RobolectricTestRunner.class)
 @Presubmit
+@LooperMode(LooperMode.Mode.LEGACY)
 public class NtpNetworkTimeHelperTest {
 
     private static final long MOCK_NTP_TIME = 1519930775453L;
diff --git a/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowLooper.java b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowLooper.java
index 16d16cd..3681bd4 100644
--- a/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowLooper.java
+++ b/services/robotests/src/com/android/server/testing/shadows/FrameworkShadowLooper.java
@@ -21,12 +21,15 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.annotation.RealObject;
+import org.robolectric.shadows.LooperShadowPicker;
+import org.robolectric.shadows.ShadowLegacyLooper;
 import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.shadows.ShadowPausedLooper;
 
 import java.util.Optional;
 
-@Implements(value = Looper.class)
-public class FrameworkShadowLooper extends ShadowLooper {
+@Implements(value = Looper.class, shadowPicker = FrameworkShadowLooper.Picker.class)
+public class FrameworkShadowLooper extends ShadowLegacyLooper {
     @RealObject private Looper mLooper;
     private Optional<Boolean> mIsCurrentThread = Optional.empty();
 
@@ -45,4 +48,10 @@
         }
         return Thread.currentThread() == mLooper.getThread();
     }
+
+    public static class Picker extends LooperShadowPicker<ShadowLooper> {
+        public Picker() {
+            super(FrameworkShadowLooper.class, ShadowPausedLooper.class);
+        }
+    }
 }
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index 4a99486..1da6759 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -95,7 +95,6 @@
         sPackageAppEnabledStates.put(packageName, Integer.valueOf(newState));  // flags unused here.
     }
 
-    @Override
     protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
             throws NameNotFoundException {
         if (!sPackageInfos.containsKey(packageName)) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 9851bc1..97e94e3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -16,24 +16,24 @@
 
 package com.android.server.trust;
 
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.argThat;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyBoolean;
-
 import android.Manifest;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
 import android.content.BroadcastReceiver;
@@ -45,14 +45,23 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricManager;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.test.TestLooper;
+import android.os.UserManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
+import android.security.Authorization;
+import android.security.authorization.IKeystoreAuthorization;
 import android.service.trust.TrustAgentService;
 import android.testing.TestableContext;
 import android.view.IWindowManager;
@@ -61,12 +70,11 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 
-import com.google.android.collect.Lists;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -74,37 +82,74 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Random;
+import java.util.Collection;
+import java.util.List;
 
 public class TrustManagerServiceTest {
 
     @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
+            .spyStatic(ActivityManager.class)
+            .spyStatic(Authorization.class)
+            .mockStatic(ServiceManager.class)
+            .mockStatic(WindowManagerGlobal.class)
+            .build();
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Rule
     public final MockContext mMockContext = new MockContext(
             ApplicationProvider.getApplicationContext());
 
     private static final String URI_SCHEME_PACKAGE = "package";
-    private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
+    private static final int TEST_USER_ID = 50;
+    private static final int PARENT_USER_ID = 60;
+    private static final int PROFILE_USER_ID = 70;
+    private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L };
+    private static final long[] PROFILE_BIOMETRIC_SIDS = new long[] { 700L, 701L };
 
-    private final TestLooper mLooper = new TestLooper();
     private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>();
-    private final LockPatternUtils mLockPatternUtils = new LockPatternUtils(mMockContext);
-    private final TrustManagerService mService = new TrustManagerService(mMockContext);
+    private final ArrayList<ComponentName> mKnownTrustAgents = new ArrayList<>();
+    private final ArrayList<ComponentName> mEnabledTrustAgents = new ArrayList<>();
 
-    @Mock
-    private PackageManager mPackageManagerMock;
+    private @Mock ActivityManager mActivityManager;
+    private @Mock BiometricManager mBiometricManager;
+    private @Mock DevicePolicyManager mDevicePolicyManager;
+    private @Mock IKeystoreAuthorization mKeystoreAuthorization;
+    private @Mock LockPatternUtils mLockPatternUtils;
+    private @Mock PackageManager mPackageManager;
+    private @Mock UserManager mUserManager;
+    private @Mock IWindowManager mWindowManager;
+
+    private HandlerThread mHandlerThread;
+    private TrustManagerService.Injector mInjector;
+    private TrustManagerService mService;
+    private ITrustManager mTrustManager;
 
     @Before
-    public void setUp() {
-        resetTrustAgentLockSettings();
-        LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class));
+    public void setUp() throws Exception {
+        when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true);
+        doReturn(mock(IActivityManager.class)).when(() -> ActivityManager.getService());
+
+        doReturn(mKeystoreAuthorization).when(() -> Authorization.getService());
+
+        when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
+        when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
+        when(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).thenReturn(mKnownTrustAgents);
+        when(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).thenReturn(mEnabledTrustAgents);
+        doAnswer(invocation -> {
+            mKnownTrustAgents.clear();
+            mKnownTrustAgents.addAll((Collection<ComponentName>) invocation.getArgument(0));
+            return null;
+        }).when(mLockPatternUtils).setKnownTrustAgents(any(), eq(TEST_USER_ID));
+        doAnswer(invocation -> {
+            mEnabledTrustAgents.clear();
+            mEnabledTrustAgents.addAll((Collection<ComponentName>) invocation.getArgument(0));
+            return null;
+        }).when(mLockPatternUtils).setEnabledTrustAgents(any(), eq(TEST_USER_ID));
 
         ArgumentMatcher<Intent> trustAgentIntentMatcher = new ArgumentMatcher<Intent>() {
             @Override
@@ -112,17 +157,43 @@
                 return TrustAgentService.SERVICE_INTERFACE.equals(argument.getAction());
             }
         };
-        when(mPackageManagerMock.queryIntentServicesAsUser(argThat(trustAgentIntentMatcher),
+        when(mPackageManager.queryIntentServicesAsUser(argThat(trustAgentIntentMatcher),
                 anyInt(), anyInt())).thenReturn(mTrustAgentResolveInfoList);
-        when(mPackageManagerMock.checkPermission(any(), any())).thenReturn(
+        when(mPackageManager.checkPermission(any(), any())).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
-        mMockContext.setMockPackageManager(mPackageManagerMock);
+
+        when(mUserManager.getAliveUsers()).thenReturn(
+                List.of(new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL)));
+
+        when(mWindowManager.isKeyguardLocked()).thenReturn(true);
+
+        mMockContext.addMockSystemService(ActivityManager.class, mActivityManager);
+        mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager);
+        mMockContext.setMockPackageManager(mPackageManager);
+        mMockContext.addMockSystemService(UserManager.class, mUserManager);
+        doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService());
+        LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class));
+
+        grantPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE);
+        grantPermission(Manifest.permission.TRUST_LISTENER);
+
+        mHandlerThread = new HandlerThread("handler");
+        mHandlerThread.start();
+        mInjector = new TrustManagerService.Injector(mLockPatternUtils, mHandlerThread.getLooper());
+        mService = new TrustManagerService(mMockContext, mInjector);
+
+        // Get the ITrustManager from the new TrustManagerService.
+        mService.onStart();
+        ArgumentCaptor<IBinder> binderArgumentCaptor = ArgumentCaptor.forClass(IBinder.class);
+        verify(() -> ServiceManager.addService(eq(Context.TRUST_SERVICE),
+                    binderArgumentCaptor.capture(), anyBoolean(), anyInt()));
+        mTrustManager = ITrustManager.Stub.asInterface(binderArgumentCaptor.getValue());
     }
 
     @After
     public void tearDown() {
-        resetTrustAgentLockSettings();
         LocalServices.removeServiceForTest(SystemServiceManager.class);
+        mHandlerThread.quit();
     }
 
     @Test
@@ -142,10 +213,9 @@
 
         bootService();
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                systemTrustAgent1, systemTrustAgent2);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                systemTrustAgent1, systemTrustAgent2, userTrustAgent1, userTrustAgent2);
+        assertThat(mEnabledTrustAgents).containsExactly(systemTrustAgent1, systemTrustAgent2);
+        assertThat(mKnownTrustAgents).containsExactly(systemTrustAgent1, systemTrustAgent2,
+                    userTrustAgent1, userTrustAgent2);
     }
 
     @Test
@@ -162,10 +232,8 @@
 
         bootService();
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                defaultTrustAgent);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                systemTrustAgent, defaultTrustAgent);
+        assertThat(mEnabledTrustAgents).containsExactly(defaultTrustAgent);
+        assertThat(mKnownTrustAgents).containsExactly(systemTrustAgent, defaultTrustAgent);
     }
 
     @Test
@@ -174,16 +242,16 @@
                 "com.android/.SystemTrustAgent");
         ComponentName trustAgent2 = ComponentName.unflattenFromString(
                 "com.android/.AnotherSystemTrustAgent");
-        initializeEnabledAgents(trustAgent1);
+        mEnabledTrustAgents.add(trustAgent1);
+        Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
+                Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
         addTrustAgent(trustAgent1, /* isSystemApp= */ true);
         addTrustAgent(trustAgent2, /* isSystemApp= */ true);
 
         bootService();
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                trustAgent1);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                trustAgent1, trustAgent2);
+        assertThat(mEnabledTrustAgents).containsExactly(trustAgent1);
+        assertThat(mKnownTrustAgents).containsExactly(trustAgent1, trustAgent2);
     }
 
     @Test
@@ -192,17 +260,17 @@
                 "com.android/.SystemTrustAgent");
         ComponentName trustAgent2 = ComponentName.unflattenFromString(
                 "com.android/.AnotherSystemTrustAgent");
-        initializeEnabledAgents(trustAgent1);
-        initializeKnownAgents(trustAgent1);
+        Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
+                Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
+        Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
+                Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
         addTrustAgent(trustAgent1, /* isSystemApp= */ true);
         addTrustAgent(trustAgent2, /* isSystemApp= */ true);
 
         bootService();
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                trustAgent1, trustAgent2);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                trustAgent1, trustAgent2);
+        assertThat(mEnabledTrustAgents).containsExactly(trustAgent1, trustAgent2);
+        assertThat(mKnownTrustAgents).containsExactly(trustAgent1, trustAgent2);
     }
 
     @Test
@@ -214,10 +282,8 @@
 
         mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                newAgentComponentName);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                newAgentComponentName);
+        assertThat(mEnabledTrustAgents).containsExactly(newAgentComponentName);
+        assertThat(mKnownTrustAgents).containsExactly(newAgentComponentName);
     }
 
     @Test
@@ -235,10 +301,8 @@
 
         mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                defaultTrustAgent);
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                defaultTrustAgent, newAgentComponentName);
+        assertThat(mEnabledTrustAgents).containsExactly(defaultTrustAgent);
+        assertThat(mKnownTrustAgents).containsExactly(defaultTrustAgent, newAgentComponentName);
     }
 
     @Test
@@ -250,9 +314,8 @@
 
         mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).isEmpty();
-        assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
-                newAgentComponentName);
+        assertThat(mEnabledTrustAgents).isEmpty();
+        assertThat(mKnownTrustAgents).containsExactly(newAgentComponentName);
     }
 
     @Test
@@ -265,50 +328,88 @@
         addTrustAgent(systemTrustAgent2, /* isSystemApp= */ true);
         bootService();
         // Simulate user turning off systemTrustAgent2
-        mLockPatternUtils.setEnabledTrustAgents(Collections.singletonList(systemTrustAgent1),
-                TEST_USER_ID);
+        mLockPatternUtils.setEnabledTrustAgents(List.of(systemTrustAgent1), TEST_USER_ID);
 
         mMockContext.sendPackageChangedBroadcast(systemTrustAgent2);
 
-        assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
-                systemTrustAgent1);
+        assertThat(mEnabledTrustAgents).containsExactly(systemTrustAgent1);
     }
 
     @Test
     public void reportEnabledTrustAgentsChangedInformsListener() throws RemoteException {
-        final LockPatternUtils utils = mock(LockPatternUtils.class);
-        final TrustManagerService service = new TrustManagerService(mMockContext,
-                new TrustManagerService.Injector(utils, mLooper.getLooper()));
         final ITrustListener trustListener = mock(ITrustListener.class);
-        final IWindowManager windowManager = mock(IWindowManager.class);
-        final int userId = new Random().nextInt();
+        mTrustManager.registerTrustListener(trustListener);
+        mService.waitForIdle();
+        mTrustManager.reportEnabledTrustAgentsChanged(TEST_USER_ID);
+        mService.waitForIdle();
+        verify(trustListener).onEnabledTrustAgentsChanged(TEST_USER_ID);
+    }
 
-        mMockContext.getTestablePermissions().setPermission(Manifest.permission.TRUST_LISTENER,
-                PERMISSION_GRANTED);
+    // Tests that when the device is locked for a managed profile with a *unified* challenge, the
+    // device locked notification that is sent to Keystore contains the biometric SIDs of the parent
+    // user, not the profile.  This matches the authentication that is needed to unlock the device
+    // for the profile again.
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids()
+            throws Exception {
+        setupMocksForProfile(/* unifiedChallenge= */ true);
 
-        when(utils.getKnownTrustAgents(anyInt())).thenReturn(new ArrayList<>());
+        when(mWindowManager.isKeyguardLocked()).thenReturn(false);
+        mTrustManager.reportKeyguardShowingChanged();
+        verify(mKeystoreAuthorization).onDeviceUnlocked(PARENT_USER_ID, null);
+        verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null);
 
-        MockitoSession mockSession = mockitoSession()
-                .initMocks(this)
-                .mockStatic(ServiceManager.class)
-                .mockStatic(WindowManagerGlobal.class)
-                .startMocking();
+        when(mWindowManager.isKeyguardLocked()).thenReturn(true);
+        mTrustManager.reportKeyguardShowingChanged();
+        verify(mKeystoreAuthorization)
+                .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS));
+        verify(mKeystoreAuthorization)
+                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS));
+    }
 
-        doReturn(windowManager).when(() -> {
-            WindowManagerGlobal.getWindowManagerService();
-        });
+    // Tests that when the device is locked for a managed profile with a *separate* challenge, the
+    // device locked notification that is sent to Keystore contains the biometric SIDs of the
+    // profile itself.  This matches the authentication that is needed to unlock the device for the
+    // profile again.
+    @Test
+    public void testLockDeviceForManagedProfileWithSeparateChallenge_usesProfileBiometricSids()
+            throws Exception {
+        setupMocksForProfile(/* unifiedChallenge= */ false);
 
-        service.onStart();
-        ArgumentCaptor<IBinder> binderArgumentCaptor = ArgumentCaptor.forClass(IBinder.class);
-        verify(() -> ServiceManager.addService(eq(Context.TRUST_SERVICE),
-                binderArgumentCaptor.capture(), anyBoolean(), anyInt()));
-        ITrustManager manager = ITrustManager.Stub.asInterface(binderArgumentCaptor.getValue());
-        manager.registerTrustListener(trustListener);
-        mLooper.dispatchAll();
-        manager.reportEnabledTrustAgentsChanged(userId);
-        mLooper.dispatchAll();
-        verify(trustListener).onEnabledTrustAgentsChanged(eq(userId));
-        mockSession.finishMocking();
+        mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, false);
+        verify(mKeystoreAuthorization).onDeviceUnlocked(PROFILE_USER_ID, null);
+
+        mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, true);
+        verify(mKeystoreAuthorization)
+                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS));
+    }
+
+    private void setupMocksForProfile(boolean unifiedChallenge) {
+        UserInfo parent = new UserInfo(PARENT_USER_ID, "parent", UserInfo.FLAG_FULL);
+        UserInfo profile = new UserInfo(PROFILE_USER_ID, "profile", UserInfo.FLAG_MANAGED_PROFILE);
+        when(mUserManager.getAliveUsers()).thenReturn(List.of(parent, profile));
+        when(mUserManager.getUserInfo(PARENT_USER_ID)).thenReturn(parent);
+        when(mUserManager.getUserInfo(PROFILE_USER_ID)).thenReturn(profile);
+        when(mUserManager.getProfileParent(PROFILE_USER_ID)).thenReturn(parent);
+        when(mUserManager.getEnabledProfileIds(PARENT_USER_ID))
+                .thenReturn(new int[] { PROFILE_USER_ID });
+
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isProfileWithUnifiedChallenge(PROFILE_USER_ID))
+                .thenReturn(unifiedChallenge);
+        when(mLockPatternUtils.isManagedProfileWithUnifiedChallenge(PROFILE_USER_ID))
+                .thenReturn(unifiedChallenge);
+        when(mLockPatternUtils.isSeparateProfileChallengeEnabled(PROFILE_USER_ID))
+                .thenReturn(!unifiedChallenge);
+
+        when(mBiometricManager.getAuthenticatorIds(PARENT_USER_ID))
+                .thenReturn(PARENT_BIOMETRIC_SIDS);
+        when(mBiometricManager.getAuthenticatorIds(PROFILE_USER_ID))
+                .thenReturn(PROFILE_BIOMETRIC_SIDS);
+
+        bootService();
+        mService.onUserSwitching(null, new SystemService.TargetUser(parent));
     }
 
     private void addTrustAgent(ComponentName agentComponentName, boolean isSystemApp) {
@@ -327,27 +428,16 @@
         mTrustAgentResolveInfoList.add(resolveInfo);
     }
 
-    private void initializeEnabledAgents(ComponentName... enabledAgents) {
-        mLockPatternUtils.setEnabledTrustAgents(Lists.newArrayList(enabledAgents), TEST_USER_ID);
-        Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
-                Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
-    }
-
-    private void initializeKnownAgents(ComponentName... knownAgents) {
-        mLockPatternUtils.setKnownTrustAgents(Lists.newArrayList(knownAgents), TEST_USER_ID);
-        Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
-                Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
-    }
-
     private void bootService() {
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+        mMockContext.sendUserStartedBroadcast();
     }
 
-    private void resetTrustAgentLockSettings() {
-        mLockPatternUtils.setEnabledTrustAgents(Collections.emptyList(), TEST_USER_ID);
-        mLockPatternUtils.setKnownTrustAgents(Collections.emptyList(), TEST_USER_ID);
+    private void grantPermission(String permission) {
+        mMockContext.getTestablePermissions().setPermission(
+                permission, PackageManager.PERMISSION_GRANTED);
     }
 
     /** A mock Context that allows the test process to send protected broadcasts. */
@@ -355,6 +445,8 @@
 
         private final ArrayList<BroadcastReceiver> mPackageChangedBroadcastReceivers =
                 new ArrayList<>();
+        private final ArrayList<BroadcastReceiver> mUserStartedBroadcastReceivers =
+                new ArrayList<>();
 
         MockContext(Context base) {
             super(base);
@@ -369,10 +461,18 @@
             if (filter.hasAction(Intent.ACTION_PACKAGE_CHANGED)) {
                 mPackageChangedBroadcastReceivers.add(receiver);
             }
+            if (filter.hasAction(Intent.ACTION_USER_STARTED)) {
+                mUserStartedBroadcastReceivers.add(receiver);
+            }
             return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
                     scheduler);
         }
 
+        @Override
+        public void sendBroadcastAsUser(Intent intent, UserHandle user,
+                @Nullable String receiverPermission, @Nullable Bundle options) {
+        }
+
         void sendPackageChangedBroadcast(ComponentName changedComponent) {
             Intent intent = new Intent(
                     Intent.ACTION_PACKAGE_CHANGED,
@@ -386,5 +486,13 @@
                 receiver.onReceive(this, intent);
             }
         }
+
+        void sendUserStartedBroadcast() {
+            Intent intent = new Intent(Intent.ACTION_USER_STARTED)
+                    .putExtra(Intent.EXTRA_USER_HANDLE, TEST_USER_ID);
+            for (BroadcastReceiver receiver : mUserStartedBroadcastReceivers) {
+                receiver.onReceive(this, intent);
+            }
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
new file mode 100644
index 0000000..523c5c0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.AndroidTestCase;
+
+import com.android.server.os.TombstoneProtos;
+import com.android.server.os.TombstoneProtos.Tombstone;
+
+public class BootReceiverTest extends AndroidTestCase {
+    private static final String TAG = "BootReceiverTest";
+
+    public void testRemoveMemoryFromTombstone() {
+        Tombstone tombstoneBase = Tombstone.newBuilder()
+                .setBuildFingerprint("build_fingerprint")
+                .setRevision("revision")
+                .setPid(123)
+                .setTid(23)
+                .setUid(34)
+                .setSelinuxLabel("selinux_label")
+                .addCommandLine("cmd1")
+                .addCommandLine("cmd2")
+                .addCommandLine("cmd3")
+                .setProcessUptime(300)
+                .setAbortMessage("abort")
+                .addCauses(TombstoneProtos.Cause.newBuilder()
+                        .setHumanReadable("cause1")
+                        .setMemoryError(TombstoneProtos.MemoryError.newBuilder()
+                                .setTool(TombstoneProtos.MemoryError.Tool.SCUDO)
+                                .setType(TombstoneProtos.MemoryError.Type.DOUBLE_FREE)))
+                .addLogBuffers(TombstoneProtos.LogBuffer.newBuilder().setName("name").addLogs(
+                        TombstoneProtos.LogMessage.newBuilder()
+                                .setTimestamp("123")
+                                .setMessage("message")))
+                .addOpenFds(TombstoneProtos.FD.newBuilder().setFd(1).setPath("path"))
+                .build();
+
+        Tombstone tombstoneWithoutMemory = tombstoneBase.toBuilder()
+                .putThreads(1, TombstoneProtos.Thread.newBuilder()
+                        .setId(1)
+                        .setName("thread1")
+                        .addRegisters(TombstoneProtos.Register.newBuilder().setName("r1").setU64(1))
+                        .addRegisters(TombstoneProtos.Register.newBuilder().setName("r2").setU64(2))
+                        .addBacktraceNote("backtracenote1")
+                        .addUnreadableElfFiles("files1")
+                        .setTaggedAddrCtrl(1)
+                        .setPacEnabledKeys(10)
+                        .build())
+                .build();
+
+        Tombstone tombstoneWithMemory = tombstoneBase.toBuilder()
+                .addMemoryMappings(TombstoneProtos.MemoryMapping.newBuilder()
+                        .setBeginAddress(1)
+                        .setEndAddress(100)
+                        .setOffset(10)
+                        .setRead(true)
+                        .setWrite(true)
+                        .setExecute(false)
+                        .setMappingName("mapping")
+                        .setBuildId("build")
+                        .setLoadBias(70))
+                .putThreads(1, TombstoneProtos.Thread.newBuilder()
+                        .setId(1)
+                        .setName("thread1")
+                        .addRegisters(TombstoneProtos.Register.newBuilder().setName("r1").setU64(1))
+                        .addRegisters(TombstoneProtos.Register.newBuilder().setName("r2").setU64(2))
+                        .addBacktraceNote("backtracenote1")
+                        .addUnreadableElfFiles("files1")
+                        .addMemoryDump(TombstoneProtos.MemoryDump.newBuilder()
+                                .setRegisterName("register1")
+                                .setMappingName("mapping")
+                                .setBeginAddress(10))
+                        .setTaggedAddrCtrl(1)
+                        .setPacEnabledKeys(10)
+                        .build())
+                .build();
+
+        assertThat(BootReceiver.removeMemoryFromTombstone(tombstoneWithMemory))
+                .isEqualTo(tombstoneWithoutMemory);
+    }
+}