Merge "Update OWNERS files for MediaProjection & related classes"
diff --git a/api/Android.bp b/api/Android.bp
index ef88790..fe283e1a 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -116,6 +116,7 @@
     system_server_classpath: [
         "service-media-s",
         "service-permission",
+        "service-rkp",
         "service-sdksandbox",
     ],
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 33739f3..e840739 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1114,6 +1114,11 @@
 
         int nextReadPos;
 
+        if (strlen(l) == 0) {
+            s = ++endl;
+            continue;
+        }
+
         int topLineNumbers = sscanf(l, "%d %d %d %d", &width, &height, &fps, &progress);
         if (topLineNumbers == 3 || topLineNumbers == 4) {
             // SLOGD("> w=%d, h=%d, fps=%d, progress=%d", width, height, fps, progress);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 83ffa24..d2e7536 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -376,6 +376,20 @@
     },
 }
 
+// Build Rust bindings for remote provisioning. Needed by keystore2.
+aidl_interface {
+    name: "android.security.rkp_aidl",
+    unstable: true,
+    srcs: [
+        "android/security/rkp/*.aidl",
+    ],
+    backend: {
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
 aidl_interface {
     name: "android.debug_aidl",
     unstable: true,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index cc42a4c..415469a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5907,6 +5907,14 @@
     public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
 
     /**
+     * Binder service for remote key provisioning.
+     *
+     * @see android.frameworks.rkp.IRemoteProvisioning
+     * @hide
+     */
+    public static final String REMOTE_PROVISIONING_SERVICE = "remote_provisioning";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.lights.LightsManager} for controlling device lights.
      *
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index 24480e9..beb7f36 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -198,6 +198,15 @@
      */
     public static final int RESULT_ERROR_INVALID_XML = -10007;
 
+    /**
+     * Indicates a failure due to invalid debug certificate file.
+     *
+     * This error code is only used with the shell command interaction.
+     *
+     * @hide
+     */
+    public static final int RESULT_ERROR_INVALID_DEBUG_CERTIFICATE = -10008;
+
     private FontManager(@NonNull IFontManager iFontManager) {
         mIFontManager = iFontManager;
     }
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 1924dc6..4899a4d 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -71,5 +71,8 @@
 # Tracing
 per-file Trace.java = file:/TRACE_OWNERS
 
+# PatternMatcher
+per-file PatternMatcher* = file:/PACKAGE_MANAGER_OWNERS
+
 # PermissionEnforcer
 per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com
diff --git a/core/java/android/security/rkp/IGetKeyCallback.aidl b/core/java/android/security/rkp/IGetKeyCallback.aidl
new file mode 100644
index 0000000..85ceae62
--- /dev/null
+++ b/core/java/android/security/rkp/IGetKeyCallback.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.security.rkp;
+
+import android.security.rkp.RemotelyProvisionedKey;
+
+/**
+ * Callback interface for receiving remotely provisioned keys from a
+ * {@link IRegistration}.
+ *
+ * @hide
+ */
+oneway interface IGetKeyCallback {
+    /**
+     * Called in response to {@link IRegistration.getKey}, indicating
+     * a remotely-provisioned key is available.
+     *
+     * @param key The key that was received from the remote provisioning service.
+     */
+    void onSuccess(in RemotelyProvisionedKey key);
+
+    /**
+     * Called when the key request has been successfully cancelled.
+     * @see IRegistration.cancelGetKey
+     */
+    void onCancel();
+
+    /**
+     * Called when an error has occurred while trying to get a remotely provisioned key.
+     *
+     * @param error A description of what failed, suitable for logging.
+     */
+    void onError(String error);
+}
+
diff --git a/core/java/android/security/rkp/IGetRegistrationCallback.aidl b/core/java/android/security/rkp/IGetRegistrationCallback.aidl
new file mode 100644
index 0000000..e375a6f
--- /dev/null
+++ b/core/java/android/security/rkp/IGetRegistrationCallback.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.security.rkp;
+
+import android.security.rkp.IRegistration;
+
+/**
+ * Callback interface for receiving a remote provisioning registration.
+ * {@link IRegistration}.
+ *
+ * @hide
+ */
+oneway interface IGetRegistrationCallback {
+    /**
+     * Called in response to {@link IRemoteProvisioning.getRegistration}.
+     *
+     * @param registration an IRegistration that is used to fetch remotely
+     * provisioned keys for the given IRemotelyProvisionedComponent.
+     */
+    void onSuccess(in IRegistration registration);
+
+    /**
+     * Called when the get registration request has been successfully cancelled.
+     * @see IRemoteProvisioning.cancelGetRegistration
+     */
+    void onCancel();
+
+    /**
+     * Called when an error has occurred while trying to get a registration.
+     *
+     * @param error A description of what failed, suitable for logging.
+     */
+    void onError(String error);
+}
+
diff --git a/core/java/android/security/rkp/IRegistration.aidl b/core/java/android/security/rkp/IRegistration.aidl
new file mode 100644
index 0000000..6522a45
--- /dev/null
+++ b/core/java/android/security/rkp/IRegistration.aidl
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.security.rkp;
+
+import android.security.rkp.IGetKeyCallback;
+
+/**
+ * This interface is associated with the registration of an
+ * IRemotelyProvisionedComponent. Each component has a unique set of keys
+ * and certificates that are provisioned to the device for attestation. An
+ * IRegistration binder is created by calling
+ * {@link IRemoteProvisioning#getRegistration()}.
+ *
+ * This interface is used to query for available keys and certificates for the
+ * registered component.
+ *
+ * @hide
+ */
+oneway interface IRegistration {
+    /**
+     * Fetch a remotely provisioned key for the given keyId. Keys are unique
+     * per caller/keyId/registration tuple. This ensures that no two
+     * applications are able to correlate keys to uniquely identify a
+     * device/user. Callers receive their key via {@code callback}.
+     *
+     * If a key is available, this call immediately invokes {@code callback}.
+     *
+     * If no keys are immediately available, then this function contacts the
+     * remote provisioning server to provision a key. After provisioning is
+     * completed, the key is passed to {@code callback}.
+     *
+     * @param keyId This is a client-chosen key identifier, used to
+     * differentiate between keys for varying client-specific use-cases. For
+     * example, keystore2 passes the UID of the applications that call it as
+     * the keyId value here, so that each of keystore2's clients gets a unique
+     * key.
+     * @param callback Receives the result of the call. A callback must only
+     * be used with one {@code getKey} call at a time.
+     */
+    void getKey(int keyId, IGetKeyCallback callback);
+
+    /**
+     * Cancel an active request for a remotely provisioned key, as initiated via
+     * {@link getKey}. Upon cancellation, {@code callback.onCancel} will be invoked.
+     */
+    void cancelGetKey(IGetKeyCallback callback);
+
+    /**
+     * Replace an obsolete key blob with an upgraded key blob.
+     * In certain cases, such as security patch level upgrade, keys become "old".
+     * In these cases, the component which supports operations with the remotely
+     * provisioned key blobs must support upgrading the blobs to make them "new"
+     * and usable on the updated system.
+     *
+     * For an example of a remotely provisioned component that has an upgrade
+     * mechanism, see the documentation for IKeyMintDevice.upgradeKey.
+     *
+     * Once a key has been upgraded, the IRegistration where the key is stored
+     * needs to be told about the new blob. After calling storeUpgradedKey,
+     * getKey will return the new key blob instead of the old one.
+     *
+     * Note that this function does NOT extend the lifetime of key blobs. The
+     * certificate for the key is unchanged, and the key will still expire at
+     * the same time it would have if storeUpgradedKey had never been called.
+     *
+     * @param oldKeyBlob The old key blob to be replaced by {@code newKeyBlob}.
+     *
+     * @param newKeyblob The new blob to replace {@code oldKeyBlob}.
+     */
+    void storeUpgradedKey(in byte[] oldKeyBlob, in byte[] newKeyBlob);
+}
diff --git a/core/java/android/security/rkp/IRemoteProvisioning.aidl b/core/java/android/security/rkp/IRemoteProvisioning.aidl
new file mode 100644
index 0000000..23d8159
--- /dev/null
+++ b/core/java/android/security/rkp/IRemoteProvisioning.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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.security.rkp;
+
+import android.security.rkp.IRegistration;
+import android.security.rkp.IGetRegistrationCallback;
+
+/**
+ * {@link IRemoteProvisioning} is the interface provided to use the remote key
+ * provisioning functionality from the Remote Key Provisioning Daemon (RKPD).
+ * This would be the first service that RKPD clients would interact with. The
+ * intent is for the clients to get the {@link IRegistration} object from this
+ * interface and use it for actual remote provisioning work.
+ *
+ * @hide
+ */
+oneway interface IRemoteProvisioning {
+    /**
+     * Takes a remotely provisioned component service name and gets a
+     * registration bound to that service and the caller's UID.
+     *
+     * @param irpcName The name of the {@code IRemotelyProvisionedComponent}
+     * for which remotely provisioned keys should be managed.
+     * @param callback Receives the result of the call. A callback must only
+     * be used with one {@code getRegistration} call at a time.
+     *
+     * Notes:
+     * - This function will attempt to get the service named by irpcName. This
+     *   implies that a lazy/dynamic aidl service will be instantiated, and this
+     *   function blocks until the service is up. Upon return, any binder tokens
+     *   are dropped, allowing the lazy/dynamic service to shutdown.
+     * - The created registration object is unique per caller. If two different
+     *   UIDs call getRegistration with the same irpcName, they will receive
+     *   different registrations. This prevents two different applications from
+     *   being able to see the same keys.
+     * - This function is idempotent per calling UID. Additional calls to
+     *   getRegistration with the same parameters, from the same caller, will have
+     *   no side effects.
+     * - A callback may only be associated with one getRegistration call at a time.
+     *   If the callback is used multiple times, this API will return an error.
+     *
+     * @see IRegistration#getKey()
+     * @see IRemotelyProvisionedComponent
+     *
+     */
+    void getRegistration(String irpcName, IGetRegistrationCallback callback);
+
+    /**
+     * Cancel any active {@link getRegistration} call associated with the given
+     * callback. If no getRegistration call is currently active, this function is
+     * a noop.
+     */
+    void cancelGetRegistration(IGetRegistrationCallback callback);
+}
diff --git a/core/java/android/security/rkp/OWNERS b/core/java/android/security/rkp/OWNERS
new file mode 100644
index 0000000..fd43089
--- /dev/null
+++ b/core/java/android/security/rkp/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1084908
+
+jbires@google.com
+sethmo@google.com
+vikramgaur@google.com
diff --git a/core/java/android/security/rkp/RemotelyProvisionedKey.aidl b/core/java/android/security/rkp/RemotelyProvisionedKey.aidl
new file mode 100644
index 0000000..207f18f
--- /dev/null
+++ b/core/java/android/security/rkp/RemotelyProvisionedKey.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2022, 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.security.rkp;
+
+/**
+ * A {@link RemotelyProvisionedKey} holds an attestation key and the
+ * corresponding remotely provisioned certificate chain.
+ *
+ * @hide
+ */
+@RustDerive(Eq=true, PartialEq=true)
+parcelable RemotelyProvisionedKey {
+    /**
+     * The remotely-provisioned key that may be used to sign attestations. The
+     * format of this key is opaque, and need only be understood by the
+     * IRemotelyProvisionedComponent that generated it.
+     *
+     * Any private key material contained within this blob must be encrypted.
+     *
+     * @see IRemotelyProvisionedComponent
+     */
+    byte[] keyBlob;
+
+    /**
+     * Sequence of DER-encoded X.509 certificates that make up the attestation
+     * key's certificate chain. This is the binary encoding for a chain that is
+     * supported by Java's CertificateFactory.generateCertificates API.
+     */
+    byte[] encodedCertChain;
+}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index d9a310f..745f36d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -332,7 +332,6 @@
     }
 
     @Override
-    /** @hide */
     protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("Service component: "); pw.println(
                 ComponentName.flattenToShortString(mServiceComponentName));
diff --git a/core/java/android/window/WindowContainerToken.java b/core/java/android/window/WindowContainerToken.java
index 22b90b2..b914cb0 100644
--- a/core/java/android/window/WindowContainerToken.java
+++ b/core/java/android/window/WindowContainerToken.java
@@ -48,7 +48,6 @@
     }
 
     @Override
-    /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeStrongBinder(mRealToken.asBinder());
     }
@@ -68,7 +67,6 @@
             };
 
     @Override
-    /** @hide */
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 7dc039d..ce1e7d2 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -781,7 +781,6 @@
     }
 
     @Override
-    /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeMap(mChanges);
         dest.writeTypedList(mHierarchyOps);
@@ -790,7 +789,6 @@
     }
 
     @Override
-    /** @hide */
     public int describeContents() {
         return 0;
     }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 312b692..d3a3492 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1278,68 +1278,77 @@
   }
   closedir(dir);
 
-  // Prepare default dirs for user 0 as user 0 always exists.
-  int result = symlink("/data/data", "/data/user/0");
-  if (result != 0) {
-    fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
-  }
-  PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION,
-      AID_ROOT, AID_ROOT, fail_fn);
-
-  for (int i = 0; i < size; i += 3) {
-    std::string const & packageName = merged_data_info_list[i];
-    std::string const & volUuid  = merged_data_info_list[i + 1];
-    std::string const & inode = merged_data_info_list[i + 2];
-
-    std::string::size_type sz;
-    long long ceDataInode = std::stoll(inode, &sz);
-
-    std::string actualCePath, actualDePath;
-    if (volUuid.compare("null") != 0) {
-      // Volume that is stored in /mnt/expand
-      char volPath[PATH_MAX];
-      char volCePath[PATH_MAX];
-      char volDePath[PATH_MAX];
-      char volCeUserPath[PATH_MAX];
-      char volDeUserPath[PATH_MAX];
-
-      snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
-      snprintf(volCePath, PATH_MAX, "%s/user", volPath);
-      snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
-      snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
-      snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
-
-      PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-      PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-
-      actualCePath = volCeUserPath;
-      actualDePath = volDeUserPath;
-    } else {
-      // Internal volume that stored in /data
-      char internalCeUserPath[PATH_MAX];
-      char internalDeUserPath[PATH_MAX];
-      snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
-      snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
-      // If it's not user 0, create /data/user/$USER.
-      if (userId == 0) {
-        actualCePath = internalLegacyCePath;
-      } else {
-        PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-            AID_ROOT, AID_ROOT, fail_fn);
-        actualCePath = internalCeUserPath;
-      }
-      PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-          AID_ROOT, AID_ROOT, fail_fn);
-      actualDePath = internalDeUserPath;
+  // No bind mounting of app data should occur in the case of a sandbox process since SDK sandboxes
+  // should not be able to read app data. Tmpfs was mounted however since a sandbox should not have
+  // access to app data.
+  appid_t appId = multiuser_get_app_id(uid);
+  bool isSdkSandboxProcess =
+          (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END);
+  if (!isSdkSandboxProcess) {
+    // Prepare default dirs for user 0 as user 0 always exists.
+    int result = symlink("/data/data", "/data/user/0");
+    if (result != 0) {
+      fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
     }
-    isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode,
-        actualCePath, actualDePath, fail_fn);
+    PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                           fail_fn);
+
+    for (int i = 0; i < size; i += 3) {
+      std::string const& packageName = merged_data_info_list[i];
+      std::string const& volUuid = merged_data_info_list[i + 1];
+      std::string const& inode = merged_data_info_list[i + 2];
+
+      std::string::size_type sz;
+      long long ceDataInode = std::stoll(inode, &sz);
+
+      std::string actualCePath, actualDePath;
+      if (volUuid.compare("null") != 0) {
+        // Volume that is stored in /mnt/expand
+        char volPath[PATH_MAX];
+        char volCePath[PATH_MAX];
+        char volDePath[PATH_MAX];
+        char volCeUserPath[PATH_MAX];
+        char volDeUserPath[PATH_MAX];
+
+        snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
+        snprintf(volCePath, PATH_MAX, "%s/user", volPath);
+        snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
+        snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
+        snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
+
+        PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                               fail_fn);
+        PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                               fail_fn);
+
+        actualCePath = volCeUserPath;
+        actualDePath = volDeUserPath;
+      } else {
+        // Internal volume that stored in /data
+        char internalCeUserPath[PATH_MAX];
+        char internalDeUserPath[PATH_MAX];
+        snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
+        snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
+        // If it's not user 0, create /data/user/$USER.
+        if (userId == 0) {
+          actualCePath = internalLegacyCePath;
+        } else {
+          PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT,
+                                 AID_ROOT, fail_fn);
+          actualCePath = internalCeUserPath;
+        }
+        PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                               fail_fn);
+        actualDePath = internalDeUserPath;
+      }
+      isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode, actualCePath,
+                               actualDePath, fail_fn);
+    }
   }
+
   // We set the label AFTER everything is done, as we are applying
   // the file operations on tmpfs. If we set the label when we mount
   // tmpfs, SELinux will not happy as we are changing system_data_files.
@@ -1380,6 +1389,165 @@
   freecon(dataFileContext);
 }
 
+/**
+ * Without sdk sandbox data isolation, the sandbox could detect if another app is installed on the
+ * system by "touching" other data directories like /data/misc_ce/0/sdksandbox/com.whatsapp, similar
+ * to apps without app data isolation (see {@link #isolateAppData()}).
+ *
+ * To prevent this, tmpfs is mounted onto misc_ce and misc_de directories on all possible volumes in
+ * a separate mount namespace. The sandbox directory path is then created containing the name of the
+ * client app package associated with the sdk sandbox. The contents for this (sdk level storage and
+ * shared sdk storage) are bind mounted from the sandbox data mirror.
+ */
+static void isolateSdkSandboxData(JNIEnv* env, jobjectArray pkg_data_info_list, uid_t uid,
+                                  const char* process_name, jstring managed_nice_name,
+                                  fail_fn_t fail_fn) {
+  const userid_t userId = multiuser_get_user_id(uid);
+
+  int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+  // The sandbox should only have information of one associated client app (package, uuid, inode)
+  if (size != 3) {
+    fail_fn(CREATE_ERROR("Unable to isolate sandbox data, incorrect associated app information"));
+  }
+
+  auto extract_fn = [env, process_name, managed_nice_name, pkg_data_info_list](int info_list_idx) {
+      jstring jstr = (jstring)(env->GetObjectArrayElement(pkg_data_info_list, info_list_idx));
+      return ExtractJString(env, process_name, managed_nice_name, jstr).value();
+  };
+  std::string packageName = extract_fn(0);
+  std::string volUuid = extract_fn(1);
+
+  char internalCePath[PATH_MAX];
+  char internalDePath[PATH_MAX];
+  char externalPrivateMountPath[PATH_MAX];
+  snprintf(internalCePath, PATH_MAX, "/data/misc_ce");
+  snprintf(internalDePath, PATH_MAX, "/data/misc_de");
+  snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
+
+  char ceUserPath[PATH_MAX];
+  char deUserPath[PATH_MAX];
+  if (volUuid != "null") {
+    snprintf(ceUserPath, PATH_MAX, "%s/%s/misc_ce/%d", externalPrivateMountPath, volUuid.c_str(),
+             userId);
+    snprintf(deUserPath, PATH_MAX, "%s/%s/misc_de/%d", externalPrivateMountPath, volUuid.c_str(),
+             userId);
+  } else {
+    snprintf(ceUserPath, PATH_MAX, "%s/%d", internalCePath, userId);
+    snprintf(deUserPath, PATH_MAX, "%s/%d", internalDePath, userId);
+  }
+
+  char ceSandboxPath[PATH_MAX];
+  char deSandboxPath[PATH_MAX];
+  snprintf(ceSandboxPath, PATH_MAX, "%s/sdksandbox", ceUserPath);
+  snprintf(deSandboxPath, PATH_MAX, "%s/sdksandbox", deUserPath);
+
+  // If the client app using the sandbox has been installed when the device is locked and the
+  // sandbox starts up when the device is locked, sandbox storage might not have been created.
+  // In that case, mount tmpfs for data isolation, but don't bind mount.
+  bool bindMountCeSandboxDataDirs = true;
+  bool bindMountDeSandboxDataDirs = true;
+  if (access(ceSandboxPath, F_OK) != 0) {
+    bindMountCeSandboxDataDirs = false;
+  }
+  if (access(deSandboxPath, F_OK) != 0) {
+    bindMountDeSandboxDataDirs = false;
+  }
+
+  char* context = nullptr;
+  char* userContext = nullptr;
+  char* sandboxContext = nullptr;
+  if (getfilecon(internalDePath, &context) < 0) {
+    fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath, strerror(errno)));
+  }
+  if (bindMountDeSandboxDataDirs) {
+    if (getfilecon(deUserPath, &userContext) < 0) {
+      fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deUserPath, strerror(errno)));
+    }
+    if (getfilecon(deSandboxPath, &sandboxContext) < 0) {
+      fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deSandboxPath, strerror(errno)));
+    }
+  }
+
+  MountAppDataTmpFs(internalCePath, fail_fn);
+  MountAppDataTmpFs(internalDePath, fail_fn);
+
+  // Mount tmpfs on all external volumes
+  DIR* dir = opendir(externalPrivateMountPath);
+  if (dir == nullptr) {
+    fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+  }
+  struct dirent* ent;
+  while ((ent = readdir(dir))) {
+    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+    if (ent->d_type != DT_DIR) {
+      fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, ent->d_name));
+    }
+    auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+    auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+    auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+
+    WaitUntilDirReady(externalCePath.c_str(), fail_fn);
+    MountAppDataTmpFs(externalCePath.c_str(), fail_fn);
+    WaitUntilDirReady(externalDePath.c_str(), fail_fn);
+    MountAppDataTmpFs(externalDePath.c_str(), fail_fn);
+  }
+  closedir(dir);
+
+  char mirrorCeSandboxPath[PATH_MAX];
+  char mirrorDeSandboxPath[PATH_MAX];
+  snprintf(mirrorCeSandboxPath, PATH_MAX, "/data_mirror/misc_ce/%s/%d/sdksandbox", volUuid.c_str(),
+           userId);
+  snprintf(mirrorDeSandboxPath, PATH_MAX, "/data_mirror/misc_de/%s/%d/sdksandbox", volUuid.c_str(),
+           userId);
+
+  if (bindMountCeSandboxDataDirs) {
+    PrepareDir(ceUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+    PrepareDir(ceSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+    // TODO(b/231322885): Use inode numbers to find the correct app path when the device locked.
+    createAndMountAppData(packageName, packageName, mirrorCeSandboxPath, ceSandboxPath, fail_fn,
+                          true /*call_fail_fn*/);
+
+    relabelDir(ceSandboxPath, sandboxContext, fail_fn);
+    relabelDir(ceUserPath, userContext, fail_fn);
+  }
+  if (bindMountDeSandboxDataDirs) {
+    PrepareDir(deUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+    PrepareDir(deSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+    createAndMountAppData(packageName, packageName, mirrorDeSandboxPath, deSandboxPath, fail_fn,
+                          true /*call_fail_fn*/);
+
+    relabelDir(deSandboxPath, sandboxContext, fail_fn);
+    relabelDir(deUserPath, userContext, fail_fn);
+  }
+
+  // We set the label AFTER everything is done, as we are applying
+  // the file operations on tmpfs. If we set the label when we mount
+  // tmpfs, SELinux will not happy as we are changing system_data_files.
+  relabelDir(internalCePath, context, fail_fn);
+  relabelDir(internalDePath, context, fail_fn);
+
+  // Relabel CE and DE dirs under /mnt/expand
+  dir = opendir(externalPrivateMountPath);
+  if (dir == nullptr) {
+    fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+  }
+  while ((ent = readdir(dir))) {
+    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+    auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+    auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+    auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+    relabelDir(externalCePath.c_str(), context, fail_fn);
+    relabelDir(externalDePath.c_str(), context, fail_fn);
+  }
+  closedir(dir);
+
+  if (bindMountDeSandboxDataDirs) {
+    freecon(sandboxContext);
+    freecon(userContext);
+  }
+  freecon(context);
+}
+
 static void insertPackagesToMergedList(JNIEnv* env,
   std::vector<std::string>& merged_data_info_list,
   jobjectArray data_info_list, const char* process_name,
@@ -1445,6 +1613,13 @@
   MountAppDataTmpFs(kCurProfileDirPath, fail_fn);
   MountAppDataTmpFs(kRefProfileDirPath, fail_fn);
 
+  // Sandbox processes do not have JIT profile, so no data needs to be bind mounted. However, it
+  // should still not have access to JIT profile, so tmpfs is mounted.
+  appid_t appId = multiuser_get_app_id(uid);
+  if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+    return;
+  }
+
   // Create profile directory for this user.
   std::string actualCurUserProfile = StringPrintf("%s/%d", kCurProfileDirPath, user_id);
   PrepareDir(actualCurUserProfile, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
@@ -1597,9 +1772,15 @@
     // Make sure app is running in its own mount namespace before isolating its data directories.
     ensureInAppMountNamespace(fail_fn);
 
-    // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
-    // mount all related packages separately.
+    // Isolate app data, jit profile and sandbox data directories by overlaying a tmpfs on those
+    // dirs and bind mount all related packages separately.
     if (mount_data_dirs) {
+        // Sdk sandbox data isolation does not need to occur for app processes since sepolicy
+        // prevents access to sandbox data anyway.
+        appid_t appId = multiuser_get_app_id(uid);
+        if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+            isolateSdkSandboxData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+        }
         isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name,
                        managed_nice_name, fail_fn);
         isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f244ce4..83d6816 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5775,4 +5775,8 @@
     <string-array name="config_serviceStateLocationAllowedPackages">
         <item>"com.android.phone"</item>
     </string-array>
+
+    <!-- List of certificate to be used for font fs-verity integrity verification -->
+    <string-array translatable="false" name="config_fontManagerServiceCerts">
+    </string-array>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 596d89a..bc2191e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2273,6 +2273,7 @@
   <java-symbol type="id" name="media_actions" />
 
   <java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
+  <java-symbol type="array" name="config_fontManagerServiceCerts" />
 
     <!-- From SystemUI -->
   <java-symbol type="anim" name="push_down_in" />
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index 47358be..05f3c5a 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -54,7 +54,11 @@
     private final int mProgramId;
     private final ULocale mLanguage;
 
-    /** @hide */
+    /**
+     * The ContentClassifier int definitions represent the AudioPresentation content
+     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
+     * @hide
+     */
     @IntDef(
         value = {
         CONTENT_UNKNOWN,
@@ -67,11 +71,6 @@
         CONTENT_EMERGENCY,
         CONTENT_VOICEOVER,
     })
-
-    /**
-     * The ContentClassifier int definitions represent the AudioPresentation content
-     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
-    */
     @Retention(RetentionPolicy.SOURCE)
     public @interface ContentClassifier {}
 
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 472586b..7f970f7 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -277,7 +277,7 @@
     }
 
     private void initializeImageReader(int width, int height, int imageFormat, int maxImages,
-            long usage, int hardwareBufferFormat, int dataSpace, boolean useLegacyImageFormat) {
+            long usage, int hardwareBufferFormat, int dataSpace) {
         if (width < 1 || height < 1) {
             throw new IllegalArgumentException(
                 "The image dimensions must be positive");
@@ -306,8 +306,7 @@
         // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
         // size.
         mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
-            width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
-            /*buffer count*/ 1);
+                width, height, imageFormat, /*buffer count*/ 1);
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
@@ -322,28 +321,26 @@
         // retrieve hal Format and hal dataspace from imageFormat
         mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mFormat);
         mDataSpace = PublicFormatUtils.getHalDataspace(mFormat);
-        mUseLegacyImageFormat = true;
         mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
 
         initializeImageReader(width, height, imageFormat, maxImages, usage, mHardwareBufferFormat,
-                mDataSpace, mUseLegacyImageFormat);
+                mDataSpace);
     }
 
     private ImageReader(int width, int height, int maxImages, long usage,
             MultiResolutionImageReader parent, int hardwareBufferFormat, int dataSpace) {
         mWidth = width;
         mHeight = height;
-        mFormat = ImageFormat.UNKNOWN; // set default image format value as UNKNOWN
         mUsage = usage;
         mMaxImages = maxImages;
         mParent = parent;
         mHardwareBufferFormat = hardwareBufferFormat;
         mDataSpace = dataSpace;
-        mUseLegacyImageFormat = false;
         mNumPlanes = ImageUtils.getNumPlanesForHardwareBufferFormat(mHardwareBufferFormat);
+        mFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
 
         initializeImageReader(width, height, mFormat, maxImages, usage, hardwareBufferFormat,
-                dataSpace, mUseLegacyImageFormat);
+                dataSpace);
     }
 
     /**
@@ -537,12 +534,7 @@
      * @hide
      */
     public Image acquireNextImageNoThrowISE() {
-        SurfaceImage si;
-        if (mUseLegacyImageFormat) {
-            si = new SurfaceImage(mFormat);
-        } else {
-            si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
-        }
+        SurfaceImage si = new SurfaceImage(mFormat);
         return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
     }
 
@@ -565,7 +557,7 @@
             // A null image will eventually be returned if ImageReader is already closed.
             int status = ACQUIRE_NO_BUFS;
             if (mIsReaderValid) {
-                status = nativeImageSetup(si, mUseLegacyImageFormat);
+                status = nativeImageSetup(si);
             }
 
             switch (status) {
@@ -619,11 +611,7 @@
         // Initialize with reader format, but can be overwritten by native if the image
         // format is different from the reader format.
         SurfaceImage si;
-        if (mUseLegacyImageFormat) {
-            si = new SurfaceImage(mFormat);
-        } else {
-            si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
-        }
+        si = new SurfaceImage(mFormat);
         int status = acquireNextSurfaceImage(si);
 
         switch (status) {
@@ -1094,8 +1082,6 @@
 
     private final @NamedDataSpace int mDataSpace;
 
-    private final boolean mUseLegacyImageFormat;
-
     /**
      * This field is used by native code, do not access or modify.
      */
@@ -1136,12 +1122,6 @@
             mDataSpace = ImageReader.this.mDataSpace;
         }
 
-        SurfaceImage(int hardwareBufferFormat, int dataSpace) {
-            mHardwareBufferFormat = hardwareBufferFormat;
-            mDataSpace = dataSpace;
-            mFormat = PublicFormatUtils.getPublicFormat(mHardwareBufferFormat, mDataSpace);
-        }
-
         @Override
         public void close() {
             synchronized (this.mCloseLock) {
@@ -1159,12 +1139,10 @@
             // update mFormat only if ImageReader is initialized by factory pattern.
             // if using builder pattern, mFormat has been updated upon initialization.
             // no need update here.
-            if (ImageReader.this.mUseLegacyImageFormat) {
-                int readerFormat = ImageReader.this.getImageFormat();
-                // Assume opaque reader always produce opaque images.
-                mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
-                    nativeGetFormat(readerFormat);
-            }
+            int readerFormat = ImageReader.this.getImageFormat();
+            // Assume opaque reader always produce opaque images.
+            mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
+                nativeGetFormat(readerFormat);
             return mFormat;
         }
 
@@ -1263,8 +1241,8 @@
             throwISEIfImageIsInvalid();
 
             if (mPlanes == null) {
-                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat,
-                        ImageReader.this.mUsage);
+                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes,
+                        ImageReader.this.mHardwareBufferFormat, ImageReader.this.mUsage);
             }
             // Shallow copy is fine.
             return mPlanes.clone();
@@ -1395,7 +1373,7 @@
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
-                int readerFormat, long readerUsage);
+                int hardwareBufferFormat, long readerUsage);
         private synchronized native int nativeGetWidth();
         private synchronized native int nativeGetHeight();
         private synchronized native int nativeGetFormat(int readerFormat);
@@ -1418,7 +1396,7 @@
      * @see #ACQUIRE_NO_BUFS
      * @see #ACQUIRE_MAX_IMAGES
      */
-    private synchronized native int nativeImageSetup(Image i, boolean legacyValidateImageFormat);
+    private synchronized native int nativeImageSetup(Image i);
 
     /**
      * @hide
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 9f52bf1..0291f64 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -29,7 +29,6 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.HardwareBuffer.Usage;
 import android.hardware.SyncFence;
-import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -249,7 +248,7 @@
     }
 
     private void initializeImageWriter(Surface surface, int maxImages,
-            boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat,
+            boolean useSurfaceImageFormatInfo, int imageFormat,
             int hardwareBufferFormat, int dataSpace, int width, int height, long usage) {
         if (surface == null || maxImages < 1) {
             throw new IllegalArgumentException("Illegal input argument: surface " + surface
@@ -265,32 +264,11 @@
         if (useSurfaceImageFormatInfo) {
             // nativeInit internally overrides UNKNOWN format. So does surface format query after
             // nativeInit and before getEstimatedNativeAllocBytes().
-            imageFormat = SurfaceUtils.getSurfaceFormat(surface);
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+            mHardwareBufferFormat = hardwareBufferFormat = SurfaceUtils.getSurfaceFormat(surface);
+            mDataSpace = dataSpace = SurfaceUtils.getSurfaceDataspace(surface);
+            imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
         }
 
-        // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
-        // allocation estimation sequence depends on the public formats values. To avoid
-        // possible errors, convert where necessary.
-        if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
-            int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
-            switch (surfaceDataspace) {
-                case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_JPEG;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_HEIF:
-                    imageFormat = ImageFormat.HEIC;
-                    break;
-                default:
-                    imageFormat = ImageFormat.JPEG;
-            }
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
-        }
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
@@ -301,19 +279,20 @@
         mWidth = width == -1 ? surfSize.getWidth() : width;
         mHeight = height == -1 ? surfSize.getHeight() : height;
 
-        mEstimatedNativeAllocBytes =
-            ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
-                useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
+        mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+                imageFormat, /*buffer count*/ 1);
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
             int imageFormat, int width, int height) {
         mMaxImages = maxImages;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
-        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
+        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage);
     }
 
@@ -321,10 +300,12 @@
             int imageFormat, int width, int height, long usage) {
         mMaxImages = maxImages;
         mUsage = usage;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
-        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
+        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage);
     }
 
@@ -337,15 +318,13 @@
         // and retrieve corresponding hardwareBufferFormat and dataSpace here.
         if (useSurfaceImageFormatInfo) {
             imageFormat = ImageFormat.UNKNOWN;
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
         } else {
             imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
             mHardwareBufferFormat = hardwareBufferFormat;
             mDataSpace = dataSpace;
         }
 
-        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false,
+        initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo,
                 imageFormat, hardwareBufferFormat, dataSpace, width, height, usage);
     }
 
@@ -764,13 +743,15 @@
         // need do some cleanup to make sure no orphaned
         // buffer caused leak.
         Rect crop = image.getCropRect();
+        int hardwareBufferFormat = PublicFormatUtils.getHalFormat(image.getFormat());
         if (image.getNativeContext() != 0) {
-            nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
-                    image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
-                    crop.bottom, image.getTransform(), image.getScalingMode());
+            nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(),
+                    hardwareBufferFormat, image.getTimestamp(), image.getDataSpace(),
+                    crop.left, crop.top, crop.right, crop.bottom, image.getTransform(),
+                    image.getScalingMode());
         } else {
             GraphicBuffer gb = GraphicBuffer.createFromHardwareBuffer(image.getHardwareBuffer());
-            nativeAttachAndQueueGraphicBuffer(mNativeContext, gb, image.getFormat(),
+            nativeAttachAndQueueGraphicBuffer(mNativeContext, gb, hardwareBufferFormat,
                     image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
                     crop.bottom, image.getTransform(), image.getScalingMode());
             gb.destroy();
@@ -1161,8 +1142,7 @@
 
             if (mPlanes == null) {
                 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat());
-                mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(),
-                        getOwner().getDataSpace());
+                mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat());
             }
 
             return mPlanes.clone();
@@ -1270,8 +1250,7 @@
         }
 
         // Create the SurfacePlane object and fill the information
-        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt,
-                int dataSpace);
+        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
 
         private synchronized native int nativeGetWidth();
 
@@ -1298,10 +1277,10 @@
             int transform, int scalingMode);
 
     private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
-            long imageNativeBuffer, int imageFormat, long timestampNs, int dataSpace,
+            long imageNativeBuffer, int hardwareBufferFormat, long timestampNs, int dataSpace,
             int left, int top, int right, int bottom, int transform, int scalingMode);
     private synchronized native int nativeAttachAndQueueGraphicBuffer(long nativeCtx,
-            GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int dataSpace,
+            GraphicBuffer graphicBuffer, int hardwareBufferFormat, long timestampNs, int dataSpace,
             int left, int top, int right, int bottom, int transform, int scalingMode);
 
     private synchronized native void cancelImage(long nativeCtx, Image image);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 62c0d55..3b93b07 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -375,11 +375,11 @@
 }
 
 static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
-                             jint maxImages, jlong ndkUsage, jint nativeFormat, jint dataSpace) {
+                             jint maxImages, jlong ndkUsage, jint nativeHalFormat, jint dataSpace) {
     status_t res;
 
-    ALOGV("%s: width:%d, height: %d, nativeFormat: %d, maxImages:%d",
-          __FUNCTION__, width, height, nativeFormat, maxImages);
+    ALOGV("%s: width:%d, height: %d, nativeHalFormat: %d, maxImages:%d",
+          __FUNCTION__, width, height, nativeHalFormat, maxImages);
 
     android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
 
@@ -395,7 +395,7 @@
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
     sp<BufferItemConsumer> bufferConsumer;
     String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
-            width, height, nativeFormat, maxImages, getpid(),
+            width, height, nativeHalFormat, maxImages, getpid(),
             createProcessUniqueId());
     uint64_t consumerUsage =
             android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage);
@@ -404,8 +404,8 @@
             /*controlledByApp*/true);
     if (bufferConsumer == nullptr) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                "Failed to allocate native buffer consumer for format 0x%x and usage 0x%x",
-                nativeFormat, consumerUsage);
+                "Failed to allocate native buffer consumer for hal format 0x%x and usage 0x%x",
+                nativeHalFormat, consumerUsage);
         return;
     }
 
@@ -419,7 +419,7 @@
     ctx->setProducer(gbProducer);
     bufferConsumer->setFrameAvailableListener(ctx);
     ImageReader_setNativeContext(env, thiz, ctx);
-    ctx->setBufferFormat(nativeFormat);
+    ctx->setBufferFormat(nativeHalFormat);
     ctx->setBufferDataspace(nativeDataspace);
     ctx->setBufferWidth(width);
     ctx->setBufferHeight(height);
@@ -428,14 +428,14 @@
     res = bufferConsumer->setDefaultBufferSize(width, height);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                          "Failed to set buffer consumer default size (%dx%d) for format 0x%x",
-                          width, height, nativeFormat);
+                          "Failed to set buffer consumer default size (%dx%d) for Hal format 0x%x",
+                          width, height, nativeHalFormat);
         return;
     }
-    res = bufferConsumer->setDefaultBufferFormat(nativeFormat);
+    res = bufferConsumer->setDefaultBufferFormat(nativeHalFormat);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
-                          "Failed to set buffer consumer default format 0x%x", nativeFormat);
+                          "Failed to set buffer consumer default Halformat 0x%x", nativeHalFormat);
         return;
     }
     res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
@@ -522,8 +522,7 @@
     ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
 }
 
-static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image,
-                                   jboolean legacyValidateImageFormat) {
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
     ALOGV("%s:", __FUNCTION__);
     JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
     if (ctx == NULL) {
@@ -577,29 +576,29 @@
         int outputWidth = getBufferWidth(buffer);
         int outputHeight = getBufferHeight(buffer);
 
-        int imgReaderFmt = ctx->getBufferFormat();
+        int imgReaderHalFmt = ctx->getBufferFormat();
         int imageReaderWidth = ctx->getBufferWidth();
         int imageReaderHeight = ctx->getBufferHeight();
         int bufferFormat = buffer->mGraphicBuffer->getPixelFormat();
-        if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
+        if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderHalFmt != HAL_PIXEL_FORMAT_BLOB) &&
                 (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
             ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
                     __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
         }
-        if (legacyValidateImageFormat && imgReaderFmt != bufferFormat) {
-            if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+        if (imgReaderHalFmt != bufferFormat) {
+            if (imgReaderHalFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
                     isPossiblyYUV(bufferFormat)) {
                 // Treat formats that are compatible with flexible YUV
                 // (HAL_PIXEL_FORMAT_YCbCr_420_888) as HAL_PIXEL_FORMAT_YCbCr_420_888.
                 ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCbCr_420_888",
                         __FUNCTION__, bufferFormat);
-            } else if (imgReaderFmt == HAL_PIXEL_FORMAT_YCBCR_P010 &&
+            } else if (imgReaderHalFmt == HAL_PIXEL_FORMAT_YCBCR_P010 &&
                     isPossibly10BitYUV(bufferFormat)) {
                 // Treat formats that are compatible with flexible 10-bit YUV
                 // (HAL_PIXEL_FORMAT_YCBCR_P010) as HAL_PIXEL_FORMAT_YCBCR_P010.
                 ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCBCR_P010",
                         __FUNCTION__, bufferFormat);
-            } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB &&
+            } else if (imgReaderHalFmt == HAL_PIXEL_FORMAT_BLOB &&
                     bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
                 // Using HAL_PIXEL_FORMAT_RGBA_8888 Gralloc buffers containing JPEGs to get around
                 // SW write limitations for (b/17379185).
@@ -842,7 +841,7 @@
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
-        int numPlanes, int readerFormat, uint64_t ndkReaderUsage)
+        int numPlanes, int halReaderFormat, uint64_t ndkReaderUsage)
 {
     ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
     int rowStride = 0;
@@ -851,9 +850,6 @@
     uint32_t dataSize = 0;
     jobject byteBuffer = NULL;
 
-    PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
-    int halReaderFormat = mapPublicFormatToHalFormat(publicReaderFormat);
-
     if (isFormatOpaque(halReaderFormat) && numPlanes > 0) {
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
@@ -963,7 +959,7 @@
     {"nativeInit",             "(Ljava/lang/Object;IIIJII)V",   (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
     {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
-    {"nativeImageSetup",       "(Landroid/media/Image;Z)I",   (void*)ImageReader_imageSetup },
+    {"nativeImageSetup",       "(Landroid/media/Image;)I",   (void*)ImageReader_imageSetup },
     {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
     {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
     {"nativeCreateImagePlanes",
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 6c6fccb..2c498e5 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -415,7 +415,9 @@
 
     // Get the dimension and format of the producer.
     sp<ANativeWindow> anw = producer;
-    int32_t width, height, surfaceFormat;
+    int32_t width, height, surfaceHalFormat;
+    int32_t surfaceFormat = 0;
+    int32_t surfaceDataspace = 0;
     if (userWidth < 0) {
         if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
             ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res);
@@ -451,11 +453,18 @@
     // Query surface format if no valid user format is specified, otherwise, override surface format
     // with user format.
     if (useSurfaceImageFormatInfo) {
-        if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &surfaceFormat)) != OK) {
+        // retrieve hal format
+        if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &surfaceHalFormat)) != OK) {
             ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
             jniThrowRuntimeException(env, "Failed to query Surface format");
             return 0;
         }
+        if ((res = anw->query(
+                anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &surfaceDataspace)) != OK) {
+            ALOGE("%s: Query Surface dataspace failed: %s (%d)", __FUNCTION__, strerror(-res), res);
+            jniThrowRuntimeException(env, "Failed to query Surface dataspace");
+            return 0;
+        }
     } else {
         // Set consumer buffer format to user specified format
         android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
@@ -475,17 +484,22 @@
             return 0;
         }
         ctx->setBufferDataSpace(nativeDataspace);
-        surfaceFormat = static_cast<int32_t>(mapHalFormatDataspaceToPublicFormat(
-            hardwareBufferFormat, nativeDataspace));
+        surfaceDataspace = dataSpace;
+        surfaceHalFormat = hardwareBufferFormat;
     }
 
-    ctx->setBufferFormat(surfaceFormat);
+    ctx->setBufferFormat(surfaceHalFormat);
+    ctx->setBufferDataSpace(static_cast<android_dataspace>(surfaceDataspace));
+
+    // update class.mWriterFormat
+    surfaceFormat = static_cast<int32_t>(mapHalFormatDataspaceToPublicFormat(
+                surfaceHalFormat, static_cast<android_dataspace>(surfaceDataspace)));
     env->SetIntField(thiz,
             gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
 
     // ndkUsage == -1 means setUsage in ImageWriter class is not called.
     // skip usage setting if setUsage in ImageWriter is not called and imageformat is opaque.
-    if (!(ndkUsage == -1 && isFormatOpaque(surfaceFormat))) {
+    if (!(ndkUsage == -1 && isFormatOpaque(surfaceHalFormat))) {
         if (ndkUsage == -1) {
             ndkUsage = GRALLOC_USAGE_SW_WRITE_OFTEN;
         }
@@ -809,7 +823,7 @@
 }
 
 static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx,
-        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint dataSpace,
+        jlong nativeBuffer, jint nativeHalFormat, jlong timestampNs, jint dataSpace,
         jint left, jint top, jint right, jint bottom, jint transform, jint scalingMode) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
@@ -820,7 +834,7 @@
     }
 
     sp<Surface> surface = ctx->getProducer();
-    if (isFormatOpaque(imageFormat) != isFormatOpaque(ctx->getBufferFormat())) {
+    if (isFormatOpaque(ctx->getBufferFormat()) != isFormatOpaque(nativeHalFormat)) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
         return -1;
@@ -840,8 +854,8 @@
 }
 
 static jint ImageWriter_attachAndQueueGraphicBuffer(JNIEnv* env, jobject thiz, jlong nativeCtx,
-        jobject buffer, jint format, jlong timestampNs, jint dataSpace, jint left, jint top,
-        jint right, jint bottom, jint transform, jint scalingMode) {
+        jobject buffer, jint nativeHalFormat, jlong timestampNs, jint dataSpace,
+        jint left, jint top, jint right, jint bottom, jint transform, jint scalingMode) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
     if (ctx == NULL || thiz == NULL) {
@@ -851,7 +865,7 @@
     }
 
     sp<Surface> surface = ctx->getProducer();
-    if (isFormatOpaque(format) != isFormatOpaque(ctx->getBufferFormat())) {
+    if (isFormatOpaque(ctx->getBufferFormat()) != isFormatOpaque(nativeHalFormat)) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
         return -1;
@@ -1028,32 +1042,32 @@
 }
 
 static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
-        int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
+        int32_t halFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
     ALOGV("%s", __FUNCTION__);
 
-    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
+    status_t res = getLockedImageInfo(buffer, idx, halFormat, base, size,
             pixelStride, rowStride);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                             "Pixel format: 0x%x is unsupported", writerFormat);
+                             "Pixel format: 0x%x is unsupported", halFormat);
         return false;
     }
     return true;
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
-        int numPlanes, int writerFormat, int dataSpace) {
+        int numPlanes, int writerFormat) {
     ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
     int rowStride, pixelStride;
     uint8_t *pData;
     uint32_t dataSize;
     jobject byteBuffer;
+    int halFormat = mapPublicFormatToHalFormat(static_cast<PublicFormat>(writerFormat));
 
-    int format = Image_getFormat(env, thiz, dataSpace);
-    if (isFormatOpaque(format) && numPlanes > 0) {
+    if (isFormatOpaque(halFormat) && numPlanes > 0) {
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
-                " must be 0", format, numPlanes);
+                " must be 0", writerFormat, numPlanes);
         jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
         return NULL;
     }
@@ -1065,7 +1079,8 @@
                 " probably out of memory");
         return NULL;
     }
-    if (isFormatOpaque(format)) {
+
+    if (isFormatOpaque(halFormat)) {
         return surfacePlanes;
     }
 
@@ -1074,10 +1089,8 @@
     Image_getLockedImage(env, thiz, &lockedImg);
 
     // Create all SurfacePlanes
-    PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
-    writerFormat = mapPublicFormatToHalFormat(publicWriterFormat);
     for (int i = 0; i < numPlanes; i++) {
-        if (!Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
+        if (!Image_getLockedImageInfo(env, &lockedImg, i, halFormat,
                 &pData, &dataSize, &pixelStride, &rowStride)) {
             return NULL;
         }
@@ -1119,7 +1132,7 @@
 };
 
 static JNINativeMethod gImageMethods[] = {
-    {"nativeCreatePlanes",      "(III)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
+    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
                                                                (void*)Image_createSurfacePlanes },
     {"nativeGetWidth",          "()I",                         (void*)Image_getWidth },
     {"nativeGetHeight",         "()I",                         (void*)Image_getHeight },
diff --git a/services/Android.bp b/services/Android.bp
index 4d38b06..2e2e51b 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -176,6 +176,7 @@
         "framework-tethering.stubs.module_lib",
         "service-art.stubs.system_server",
         "service-permission.stubs.system_server",
+        "service-rkp.stubs.system_server",
         "service-sdksandbox.stubs.system_server",
     ],
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d35c07f..9268fc0 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -131,6 +131,7 @@
         "app-compat-annotations",
         "framework-tethering.stubs.module_lib",
         "service-permission.stubs.system_server",
+        "service-rkp.stubs.system_server",
         "service-sdksandbox.stubs.system_server",
     ],
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index ec8745a..fdfcfa3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -732,6 +732,7 @@
     private static final int H_COMPLETE_UNLOCK_USER = 14;
     private static final int H_VOLUME_STATE_CHANGED = 15;
     private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
+    private static final int H_SECURE_KEYGUARD_STATE_CHANGED = 17;
 
     class StorageManagerServiceHandler extends Handler {
         public StorageManagerServiceHandler(Looper looper) {
@@ -871,6 +872,14 @@
                     }
                     break;
                 }
+                case H_SECURE_KEYGUARD_STATE_CHANGED: {
+                    try {
+                        mVold.onSecureKeyguardStateChanged((boolean) msg.obj);
+                    } catch (Exception e) {
+                        Slog.wtf(TAG, e);
+                    }
+                    break;
+                }
             }
         }
     }
@@ -888,7 +897,15 @@
                 if (Intent.ACTION_USER_ADDED.equals(action)) {
                     final UserManager um = mContext.getSystemService(UserManager.class);
                     final int userSerialNumber = um.getUserSerialNumber(userId);
-                    mVold.onUserAdded(userId, userSerialNumber);
+                    final UserInfo userInfo = um.getUserInfo(userId);
+                    if (userInfo.isCloneProfile()) {
+                        // Only clone profiles share storage with their parent
+                        mVold.onUserAdded(userId, userSerialNumber,
+                                userInfo.profileGroupId /* sharesStorageWithUserId */);
+                    } else {
+                        mVold.onUserAdded(userId, userSerialNumber,
+                                -1 /* shareStorageWithUserId */);
+                    }
                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                     synchronized (mVolumes) {
                         final int size = mVolumes.size();
@@ -1137,7 +1154,11 @@
 
                 // Tell vold about all existing and started users
                 for (UserInfo user : users) {
-                    mVold.onUserAdded(user.id, user.serialNumber);
+                    if (user.isCloneProfile()) {
+                        mVold.onUserAdded(user.id, user.serialNumber, user.profileGroupId);
+                    } else {
+                        mVold.onUserAdded(user.id, user.serialNumber, -1);
+                    }
                 }
                 for (int userId : systemUnlockedUsers) {
                     mVold.onUserStarted(userId);
@@ -1330,12 +1351,12 @@
     public void onKeyguardStateChanged(boolean isShowing) {
         // Push down current secure keyguard status so that we ignore malicious
         // USB devices while locked.
-        mSecureKeyguardShowing = isShowing
+        boolean isSecureKeyguardShowing = isShowing
                 && mContext.getSystemService(KeyguardManager.class).isDeviceSecure(mCurrentUserId);
-        try {
-            mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
+        if (mSecureKeyguardShowing != isSecureKeyguardShowing) {
+            mSecureKeyguardShowing = isSecureKeyguardShowing;
+            mHandler.obtainMessage(H_SECURE_KEYGUARD_STATE_CHANGED, mSecureKeyguardShowing)
+                    .sendToTarget();
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index eb6a3b3..5893d44 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2202,16 +2202,25 @@
             Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
             boolean bindMountAppStorageDirs = false;
             boolean bindMountAppsData = mAppDataIsolationEnabled
-                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
+                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid)
+                        || app.isSdkSandbox)
                     && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
 
             // Get all packages belongs to the same shared uid. sharedPackages is empty array
             // if it doesn't have shared uid.
             final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
-            final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
-                    app.info.packageName, app.userId);
-            final String[] targetPackagesList = sharedPackages.length == 0
-                    ? new String[]{app.info.packageName} : sharedPackages;
+
+            // In the case of sdk sandbox, the pkgDataInfoMap of only the client app associated with
+            // the sandbox is required to handle app visibility restrictions for the sandbox.
+            final String[] targetPackagesList;
+            if (app.isSdkSandbox) {
+                targetPackagesList = new String[]{app.sdkSandboxClientAppPackage};
+            } else {
+                final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+                        app.info.packageName, app.userId);
+                targetPackagesList = sharedPackages.length == 0
+                        ? new String[]{app.info.packageName} : sharedPackages;
+            }
 
             final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
 
@@ -2237,7 +2246,7 @@
                 bindMountAppsData = false;
             }
 
-            if (!hasAppStorage) {
+            if (!hasAppStorage && !app.isSdkSandbox) {
                 bindMountAppsData = false;
                 pkgDataInfoMap = null;
                 allowlistedAppDataInfoMap = null;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bc9bc03..4fcde97 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -3475,6 +3475,8 @@
                 return;
             } else {
                 mActiveNetwork = null;
+                mUnderlyingNetworkCapabilities = null;
+                mUnderlyingLinkProperties = null;
             }
 
             if (mScheduledHandleNetworkLostFuture != null) {
@@ -3664,9 +3666,6 @@
                 scheduleRetryNewIkeSession();
             }
 
-            mUnderlyingNetworkCapabilities = null;
-            mUnderlyingLinkProperties = null;
-
             // Close all obsolete state, but keep VPN alive incase a usable network comes up.
             // (Mirrors VpnService behavior)
             Log.d(TAG, "Resetting state for token: " + mCurrentToken);
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index ae9c64b4..ad27c45 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -26,6 +26,7 @@
 import android.graphics.fonts.FontManager;
 import android.graphics.fonts.FontUpdateRequest;
 import android.graphics.fonts.SystemFonts;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.ResultReceiver;
 import android.os.SharedMemory;
@@ -35,8 +36,10 @@
 import android.util.AndroidException;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
+import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.graphics.fonts.IFontManager;
 import com.android.internal.security.VerityUtils;
@@ -47,7 +50,9 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.nio.ByteBuffer;
 import java.nio.DirectByteBuffer;
@@ -154,9 +159,30 @@
     }
 
     private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil {
+
+        private final String[] mDerCertPaths;
+
+        FsverityUtilImpl(String[] derCertPaths) {
+            mDerCertPaths = derCertPaths;
+        }
+
         @Override
-        public boolean hasFsverity(String filePath) {
-            return VerityUtils.hasFsverity(filePath);
+        public boolean isFromTrustedProvider(String fontPath, byte[] pkcs7Signature) {
+            final byte[] digest = VerityUtils.getFsverityDigest(fontPath);
+            if (digest == null) {
+                Log.w(TAG, "Failed to get fs-verity digest for " + fontPath);
+                return false;
+            }
+            for (String certPath : mDerCertPaths) {
+                try (InputStream is = new FileInputStream(certPath)) {
+                    if (VerityUtils.verifyPkcs7DetachedSignature(pkcs7Signature, digest, is)) {
+                        return true;
+                    }
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed to read certificate file: " + certPath);
+                }
+            }
+            return false;
         }
 
         @Override
@@ -174,11 +200,15 @@
     @NonNull
     private final Context mContext;
 
+    private final boolean mIsSafeMode;
+
     private final Object mUpdatableFontDirLock = new Object();
 
+    private String mDebugCertFilePath = null;
+
     @GuardedBy("mUpdatableFontDirLock")
     @Nullable
-    private final UpdatableFontDir mUpdatableFontDir;
+    private UpdatableFontDir mUpdatableFontDir;
 
     // mSerializedFontMapLock can be acquired while holding mUpdatableFontDirLock.
     // mUpdatableFontDirLock should not be newly acquired while holding mSerializedFontMapLock.
@@ -194,22 +224,43 @@
             UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
         }
         mContext = context;
-        mUpdatableFontDir = createUpdatableFontDir(safeMode);
+        mIsSafeMode = safeMode;
         initialize();
     }
 
     @Nullable
-    private static UpdatableFontDir createUpdatableFontDir(boolean safeMode) {
+    private UpdatableFontDir createUpdatableFontDir() {
         // Never read updatable font files in safe mode.
-        if (safeMode) return null;
+        if (mIsSafeMode) return null;
         // If apk verity is supported, fs-verity should be available.
         if (!VerityUtils.isFsVeritySupported()) return null;
+
+        String[] certs = mContext.getResources().getStringArray(
+                R.array.config_fontManagerServiceCerts);
+
+        if (mDebugCertFilePath != null && (Build.IS_USERDEBUG || Build.IS_ENG)) {
+            String[] tmp = new String[certs.length + 1];
+            System.arraycopy(certs, 0, tmp, 0, certs.length);
+            tmp[certs.length] = mDebugCertFilePath;
+            certs = tmp;
+        }
+
         return new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser(),
-                new FsverityUtilImpl(), new File(CONFIG_XML_FILE));
+                new FsverityUtilImpl(certs), new File(CONFIG_XML_FILE));
+    }
+
+    /**
+     * Add debug certificate to the cert list. This must be called only on userdebug/eng
+     * build.
+     * @param debugCertPath a debug certificate file path
+     */
+    public void addDebugCertificate(@Nullable String debugCertPath) {
+        mDebugCertFilePath = debugCertPath;
     }
 
     private void initialize() {
         synchronized (mUpdatableFontDirLock) {
+            mUpdatableFontDir = createUpdatableFontDir();
             if (mUpdatableFontDir == null) {
                 setSerializedFontMap(serializeSystemServerFontMap());
                 return;
@@ -232,12 +283,12 @@
 
     /* package */ void update(int baseVersion, List<FontUpdateRequest> requests)
             throws SystemFontException {
-        if (mUpdatableFontDir == null) {
-            throw new SystemFontException(
-                    FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
-                    "The font updater is disabled.");
-        }
         synchronized (mUpdatableFontDirLock) {
+            if (mUpdatableFontDir == null) {
+                throw new SystemFontException(
+                        FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
+                        "The font updater is disabled.");
+            }
             // baseVersion == -1 only happens from shell command. This is filtered and treated as
             // error from SystemApi call.
             if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) {
@@ -272,10 +323,10 @@
     }
 
     /* package */ Map<String, File> getFontFileMap() {
-        if (mUpdatableFontDir == null) {
-            return Collections.emptyMap();
-        }
         synchronized (mUpdatableFontDirLock) {
+            if (mUpdatableFontDir == null) {
+                return Collections.emptyMap();
+            }
             return mUpdatableFontDir.getPostScriptMap();
         }
     }
@@ -301,10 +352,10 @@
      * Returns an active system font configuration.
      */
     public @NonNull FontConfig getSystemFontConfig() {
-        if (mUpdatableFontDir == null) {
-            return SystemFonts.getSystemPreinstalledFontConfig();
-        }
         synchronized (mUpdatableFontDirLock) {
+            if (mUpdatableFontDir == null) {
+                return SystemFonts.getSystemPreinstalledFontConfig();
+            }
             return mUpdatableFontDir.getSystemFontConfig();
         }
     }
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
index 3fecef7..9478344 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -28,6 +28,7 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.os.Binder;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.ShellCommand;
@@ -103,6 +104,10 @@
         w.println("update-family [family definition XML path]");
         w.println("    Update font families with the new definitions.");
         w.println();
+        w.println("install-debug-cert [cert file path]");
+        w.println("    Install debug certificate file. This command can be used only on userdebug");
+        w.println("    or eng device with root user.");
+        w.println();
         w.println("clear");
         w.println("    Remove all installed font files and reset to the initial state.");
         w.println();
@@ -322,6 +327,33 @@
         return 0;
     }
 
+    private int installCert(ShellCommand shell) throws SystemFontException {
+        if (!(Build.IS_USERDEBUG || Build.IS_ENG)) {
+            throw new SecurityException("Only userdebug/eng device can add debug certificate");
+        }
+        if (Binder.getCallingUid() != Process.ROOT_UID) {
+            throw new SecurityException("Only root can add debug certificate");
+        }
+
+        String certPath = shell.getNextArg();
+        if (certPath == null) {
+            throw new SystemFontException(
+                    FontManager.RESULT_ERROR_INVALID_DEBUG_CERTIFICATE,
+                    "Cert file path argument is required.");
+        }
+        File file = new File(certPath);
+        if (!file.isFile()) {
+            throw new SystemFontException(
+                    FontManager.RESULT_ERROR_INVALID_DEBUG_CERTIFICATE,
+                    "Cert file (" + file + ") is not found");
+        }
+
+        mService.addDebugCertificate(certPath);
+        mService.restart();
+        shell.getOutPrintWriter().println("Success");
+        return 0;
+    }
+
     private int update(ShellCommand shell) throws SystemFontException {
         String fontPath = shell.getNextArg();
         if (fontPath == null) {
@@ -494,6 +526,8 @@
                     return restart(shell);
                 case "status":
                     return status(shell);
+                case "install-debug-cert":
+                    return installCert(shell);
                 default:
                     return shell.handleDefaultCommands(cmd);
             }
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 743b4d9..457d5b7 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -40,6 +40,8 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -59,6 +61,8 @@
     private static final String TAG = "UpdatableFontDir";
     private static final String RANDOM_DIR_PREFIX = "~~";
 
+    private static final String FONT_SIGNATURE_FILE = "font.fsv_sig";
+
     /** Interface to mock font file access in tests. */
     interface FontFileParser {
         String getPostScriptName(File file) throws IOException;
@@ -72,7 +76,7 @@
 
     /** Interface to mock fs-verity in tests. */
     interface FsverityUtil {
-        boolean hasFsverity(String path);
+        boolean isFromTrustedProvider(String path, byte[] pkcs7Signature);
 
         void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException;
 
@@ -188,12 +192,35 @@
                     FileUtils.deleteContentsAndDir(dir);
                     continue;
                 }
+
+                File signatureFile = new File(dir, FONT_SIGNATURE_FILE);
+                if (!signatureFile.exists()) {
+                    Slog.i(TAG, "The signature file is missing.");
+                    FileUtils.deleteContentsAndDir(dir);
+                    continue;
+                }
+                byte[] signature;
+                try {
+                    signature = Files.readAllBytes(Paths.get(signatureFile.getAbsolutePath()));
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to read signature file.");
+                    return;
+                }
+
                 File[] files = dir.listFiles();
-                if (files == null || files.length != 1) {
+                if (files == null || files.length != 2) {
                     Slog.e(TAG, "Unexpected files in dir: " + dir);
                     return;
                 }
-                FontFileInfo fontFileInfo = validateFontFile(files[0]);
+
+                File fontFile;
+                if (files[0].equals(signatureFile)) {
+                    fontFile = files[1];
+                } else {
+                    fontFile = files[0];
+                }
+
+                FontFileInfo fontFileInfo = validateFontFile(fontFile, signature);
                 if (fontConfig == null) {
                     fontConfig = getSystemFontConfig();
                 }
@@ -359,9 +386,25 @@
             } catch (ErrnoException e) {
                 throw new SystemFontException(
                         FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
-                        "Failed to change mode to 711", e);
+                        "Failed to change font file mode to 644", e);
             }
-            FontFileInfo fontFileInfo = validateFontFile(newFontFile);
+            File signatureFile = new File(newDir, FONT_SIGNATURE_FILE);
+            try (FileOutputStream out = new FileOutputStream(signatureFile)) {
+                out.write(pkcs7Signature);
+            } catch (IOException e) {
+                // TODO: Do we need new error code for signature write failure?
+                throw new SystemFontException(
+                        FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
+                        "Failed to write font signature file to storage.", e);
+            }
+            try {
+                Os.chmod(signatureFile.getAbsolutePath(), 0600);
+            } catch (ErrnoException e) {
+                throw new SystemFontException(
+                        FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
+                        "Failed to change the signature file mode to 600", e);
+            }
+            FontFileInfo fontFileInfo = validateFontFile(newFontFile, pkcs7Signature);
 
             // Try to create Typeface and treat as failure something goes wrong.
             try {
@@ -478,8 +521,9 @@
      * is higher than the currently used font.
      */
     @NonNull
-    private FontFileInfo validateFontFile(File file) throws SystemFontException {
-        if (!mFsverityUtil.hasFsverity(file.getAbsolutePath())) {
+    private FontFileInfo validateFontFile(File file, byte[] pkcs7Signature)
+            throws SystemFontException {
+        if (!mFsverityUtil.isFromTrustedProvider(file.getAbsolutePath(), pkcs7Signature)) {
             throw new SystemFontException(
                     FontManager.RESULT_ERROR_VERIFICATION_FAILURE,
                     "Font validation failed. Fs-verity is not enabled: " + file);
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index f6b22bc..a03a16a 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -113,7 +113,7 @@
             mScanFlags = scanFlags;
         }
         mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
-        mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+        mSystemScanFlags = mScanFlags | SCAN_AS_SYSTEM;
         mExecutorService = ParallelPackageParser.makeExecutorService();
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 94e8ec5..85b0149 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1836,8 +1836,6 @@
         mAppDataHelper = new AppDataHelper(this);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
         mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
-        mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
-                mInjector.getSystemPartitions());
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mAppDataHelper);
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1958,6 +1956,9 @@
                         + ver.fingerprint + " to " + PackagePartitions.FINGERPRINT);
             }
 
+            mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+                mInjector.getSystemPartitions());
+
             // when upgrading from pre-M, promote system app permissions from install to runtime
             mPromoteSystemApps =
                     mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
diff --git a/services/core/java/com/android/server/security/rkp/OWNERS b/services/core/java/com/android/server/security/rkp/OWNERS
new file mode 100644
index 0000000..348f940
--- /dev/null
+++ b/services/core/java/com/android/server/security/rkp/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
new file mode 100644
index 0000000..65a4b38
--- /dev/null
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 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.security.rkp;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IGetRegistrationCallback;
+import android.security.rkp.IRegistration;
+import android.security.rkp.IRemoteProvisioning;
+import android.security.rkp.service.RegistrationProxy;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+import java.time.Duration;
+
+/**
+ * Implements the remote provisioning system service. This service is backed by a mainline
+ * module, allowing the underlying implementation to be updated. The code here is a thin
+ * proxy for the code in android.security.rkp.service.
+ *
+ * @hide
+ */
+public class RemoteProvisioningService extends SystemService {
+    public static final String TAG = "RemoteProvisionSysSvc";
+    private static final Duration CREATE_REGISTRATION_TIMEOUT = Duration.ofSeconds(10);
+    private final RemoteProvisioningImpl mBinderImpl = new RemoteProvisioningImpl();
+
+    /** @hide */
+    public RemoteProvisioningService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.REMOTE_PROVISIONING_SERVICE, mBinderImpl);
+    }
+
+    private final class RemoteProvisioningImpl extends IRemoteProvisioning.Stub {
+
+        final class RegistrationBinder extends IRegistration.Stub {
+            static final String TAG = RemoteProvisioningService.TAG;
+            private final RegistrationProxy mRegistration;
+
+            RegistrationBinder(RegistrationProxy registration) {
+                mRegistration = registration;
+            }
+
+            @Override
+            public void getKey(int keyId, IGetKeyCallback callback) {
+                Log.e(TAG, "RegistrationBinder.getKey NOT YET IMPLEMENTED");
+            }
+
+            @Override
+            public void cancelGetKey(IGetKeyCallback callback) {
+                Log.e(TAG, "RegistrationBinder.cancelGetKey NOT YET IMPLEMENTED");
+            }
+
+            @Override
+            public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) {
+                Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED");
+            }
+        }
+
+        @Override
+        public void getRegistration(String irpcName, IGetRegistrationCallback callback)
+                throws RemoteException {
+            final int callerUid = Binder.getCallingUidOrThrow();
+            final long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                Log.i(TAG, "getRegistration(" + irpcName + ")");
+                RegistrationProxy.createAsync(
+                        getContext(),
+                        callerUid,
+                        irpcName,
+                        CREATE_REGISTRATION_TIMEOUT,
+                        getContext().getMainExecutor(),
+                        new OutcomeReceiver<>() {
+                            @Override
+                            public void onResult(RegistrationProxy registration) {
+                                try {
+                                    callback.onSuccess(new RegistrationBinder(registration));
+                                } catch (RemoteException e) {
+                                    Log.e(TAG, "Error calling success callback", e);
+                                }
+                            }
+
+                            @Override
+                            public void onError(Exception error) {
+                                try {
+                                    callback.onError(error.toString());
+                                } catch (RemoteException e) {
+                                    Log.e(TAG, "Error calling error callback", e);
+                                }
+                            }
+                        });
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        }
+
+        @Override
+        public void cancelGetRegistration(IGetRegistrationCallback callback)
+                throws RemoteException {
+            Log.i(TAG, "cancelGetRegistration()");
+            callback.onError("cancelGetRegistration not yet implemented");
+        }
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a953bcb..0ceda79 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -186,6 +186,7 @@
 import com.android.server.security.FileIntegrityService;
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
+import com.android.server.security.rkp.RemoteProvisioningService;
 import com.android.server.sensorprivacy.SensorPrivacyService;
 import com.android.server.sensors.SensorService;
 import com.android.server.signedconfig.SignedConfigService;
@@ -1392,11 +1393,16 @@
         mSystemServiceManager.startService(BugreportManagerService.class);
         t.traceEnd();
 
-        // Serivce for GPU and GPU driver.
+        // Service for GPU and GPU driver.
         t.traceBegin("GpuService");
         mSystemServiceManager.startService(GpuService.class);
         t.traceEnd();
 
+        // Handles system process requests for remotely provisioned keys & data.
+        t.traceBegin("StartRemoteProvisioningService");
+        mSystemServiceManager.startService(RemoteProvisioningService.class);
+        t.traceEnd();
+
         t.traceEnd(); // startCoreServices
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index f9b8373..9672085 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -108,7 +108,7 @@
         }
 
         @Override
-        public boolean hasFsverity(String path) {
+        public boolean isFromTrustedProvider(String path, byte[] signature) {
             return mHasFsverityPaths.contains(path);
         }
 
@@ -291,6 +291,32 @@
     }
 
     @Test
+    public void construct_missingSignatureFile() throws Exception {
+        UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+                mUpdatableFontFilesDir, mParser, mFakeFsverityUtil,
+                mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+        dirForPreparation.loadFontFileMap();
+        dirForPreparation.update(Arrays.asList(
+                newFontUpdateRequest("foo.ttf,1,foo", GOOD_SIGNATURE)));
+        assertThat(mUpdatableFontFilesDir.list()).hasLength(1);
+
+        // Remove signature file next to the font file.
+        File fontDir = dirForPreparation.getPostScriptMap().get("foo");
+        File sigFile = new File(fontDir.getParentFile(), "font.fsv_sig");
+        assertThat(sigFile.exists()).isTrue();
+        sigFile.delete();
+
+        UpdatableFontDir dir = new UpdatableFontDir(
+                mUpdatableFontFilesDir, mParser, mFakeFsverityUtil,
+                mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+        dir.loadFontFileMap();
+        // The font file should be removed and should not be loaded.
+        assertThat(dir.getPostScriptMap()).isEmpty();
+        assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
+        assertThat(dir.getFontFamilyMap()).isEmpty();
+    }
+
+    @Test
     public void construct_olderThanPreinstalledFont() throws Exception {
         Function<Map<String, File>, FontConfig> configSupplier = (map) -> {
             FontConfig.Font fooFont = new FontConfig.Font(
@@ -782,8 +808,8 @@
         UpdatableFontDir.FsverityUtil fakeFsverityUtil = new UpdatableFontDir.FsverityUtil() {
 
             @Override
-            public boolean hasFsverity(String path) {
-                return mFakeFsverityUtil.hasFsverity(path);
+            public boolean isFromTrustedProvider(String path, byte[] signature) {
+                return mFakeFsverityUtil.isFromTrustedProvider(path, signature);
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index ce322f7..8bd6fcd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
@@ -47,7 +48,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
-import com.android.activitycontext.ActivityContext;
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.server.LocalServices;
@@ -611,34 +611,23 @@
         mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
 
         Bundle options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
-        IBinder result = ActivityContext.getWithContext(activity -> {
-            try {
-                IBinder targetTask = activity.getActivityToken();
-                mCrossProfileAppsServiceImpl.startActivityAsUser(
-                        mIApplicationThread,
-                        PACKAGE_ONE,
-                        FEATURE_ID,
-                        ACTIVITY_COMPONENT,
-                        UserHandle.of(PRIMARY_USER).getIdentifier(),
-                        true,
-                        targetTask,
-                        options);
-                return targetTask;
-            } catch (Exception re) {
-                return null;
-            }
-        });
-        if (result == null) {
-            throw new Exception();
-        }
-
+        Binder targetTask = new Binder();
+        mCrossProfileAppsServiceImpl.startActivityAsUser(
+                mIApplicationThread,
+                PACKAGE_ONE,
+                FEATURE_ID,
+                ACTIVITY_COMPONENT,
+                UserHandle.of(PRIMARY_USER).getIdentifier(),
+                true,
+                targetTask,
+                options);
         verify(mActivityTaskManagerInternal)
                 .startActivityAsUser(
                         nullable(IApplicationThread.class),
                         eq(PACKAGE_ONE),
                         eq(FEATURE_ID),
                         any(Intent.class),
-                        eq(result),
+                        eq(targetTask),
                         anyInt(),
                         eq(options),
                         eq(PRIMARY_USER));
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 8ec500b..7eccd1a 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -49,7 +49,6 @@
             POLICY_RULE_DO_NOT_DELETE,
             POLICY_RULE_DELETE_AFTER_DISABLING
     })
-    /** @hide */
     public @interface PolicyRule {}
     /** Once this profile is enabled, it cannot be disabled. */
     public static final int POLICY_RULE_DO_NOT_DISABLE = 1;
@@ -66,7 +65,6 @@
             PROFILE_CLASS_OPERATIONAL,
             PROFILE_CLASS_UNSET
     })
-    /** @hide */
     public @interface ProfileClass {}
     /** Testing profiles */
     public static final int PROFILE_CLASS_TESTING = 0;
@@ -87,7 +85,6 @@
             PROFILE_STATE_ENABLED,
             PROFILE_STATE_UNSET
     })
-    /** @hide */
     public @interface ProfileState {}
     /** Disabled profiles */
     public static final int PROFILE_STATE_DISABLED = 0;
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 0a2bb3d..2f8316e 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -75,7 +75,6 @@
             CANCEL_REASON_TIMEOUT,
             CANCEL_REASON_PPR_NOT_ALLOWED
     })
-    /** @hide */
     public @interface CancelReason {
     }
 
@@ -105,7 +104,6 @@
             RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
             RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS
     })
-    /** @hide */
     public @interface ResetOption {
     }
 
diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java
index c348cff..be0048f 100644
--- a/telephony/java/android/telephony/euicc/EuiccNotification.java
+++ b/telephony/java/android/telephony/euicc/EuiccNotification.java
@@ -44,7 +44,6 @@
             EVENT_DISABLE,
             EVENT_DELETE
     })
-    /** @hide */
     public @interface Event {}
 
     /** A profile is downloaded and installed. */
diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
index d5a05ae..1c6b6b6 100644
--- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
+++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
@@ -42,7 +42,6 @@
     @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
             POLICY_RULE_FLAG_CONSENT_REQUIRED
     })
-    /** @hide */
     public @interface PolicyRuleFlag {}
 
     /** User consent is required to install the profile. */
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index cbe13d9..650686f 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -373,6 +373,10 @@
         try (InputStream is = new FileInputStream(certPath)) {
             result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
         }
+        // /data/local/tmp is not readable by system server. Copy a cert file to /data/fonts
+        final String copiedCert = "/data/fonts/debug_cert.der";
+        runShellCommand("cp " + certPath + " " + copiedCert, null);
+        runShellCommand("cmd font install-debug-cert " + copiedCert, null);
         // Assert that there are no errors.
         assertThat(result.second).isEmpty();
         String keyId = result.first.trim();
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 133c176..cc3781a 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -246,6 +246,12 @@
     }
 
     @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, Bundle options) {
+        sendBroadcast(intent);
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         sendBroadcast(intent);
     }