diff options
48 files changed, 1084 insertions, 284 deletions
diff --git a/api/Android.bp b/api/Android.bp index ef8879096e4b..fe283e1a95c6 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -116,6 +116,7 @@ combined_apis {      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 33739f39aaa4..e840739399df 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1114,6 +1114,11 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)  {          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 83ffa2405688..d2e7536a8a5a 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -376,6 +376,20 @@ aidl_interface {      },  } +// 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 cc42a4c11036..415469aec3b1 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5907,6 +5907,14 @@ public abstract class Context {      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 24480e954a64..beb7f36142c7 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -198,6 +198,15 @@ public class FontManager {       */      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 1924dc6b651b..4899a4d6a85b 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -71,5 +71,8 @@ per-file Vintf* = file:/platform/system/libvintf:/OWNERS  # 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 000000000000..85ceae62aadc --- /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 000000000000..e375a6f97b31 --- /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 000000000000..6522a458de4e --- /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 000000000000..23d8159f7b28 --- /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 000000000000..fd430899fc5f --- /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 000000000000..207f18f2f947 --- /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 d9a310f7a6a3..745f36db15e8 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -332,7 +332,6 @@ public abstract class AugmentedAutofillService extends Service {      }      @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 22b90b260f05..b914cb0dfd75 100644 --- a/core/java/android/window/WindowContainerToken.java +++ b/core/java/android/window/WindowContainerToken.java @@ -48,7 +48,6 @@ public final class WindowContainerToken implements Parcelable {      }      @Override -    /** @hide */      public void writeToParcel(@NonNull Parcel dest, int flags) {          dest.writeStrongBinder(mRealToken.asBinder());      } @@ -68,7 +67,6 @@ public final class WindowContainerToken implements Parcelable {              };      @Override -    /** @hide */      public int describeContents() {          return 0;      } diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 7dc039d44f95..ce1e7d2af48b 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -781,7 +781,6 @@ public final class WindowContainerTransaction implements Parcelable {      }      @Override -    /** @hide */      public void writeToParcel(@NonNull Parcel dest, int flags) {          dest.writeMap(mChanges);          dest.writeTypedList(mHierarchyOps); @@ -790,7 +789,6 @@ public final class WindowContainerTransaction implements Parcelable {      }      @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 312b692e08ab..d3a34923c5b9 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1278,68 +1278,77 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d    }    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; +  // 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))); +    } +    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 { -        PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION, -            AID_ROOT, AID_ROOT, fail_fn); -        actualCePath = internalCeUserPath; +        // 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;        } -      PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION, -          AID_ROOT, AID_ROOT, fail_fn); -      actualDePath = internalDeUserPath; +      isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode, actualCePath, +                               actualDePath, fail_fn);      } -    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 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d    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 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list,    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 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,      // 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 f244ce412d5e..83d6816d174d 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 596d89af99a6..bc2191e4bf20 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 47358be3e926..05f3c5a3512b 100644 --- a/media/java/android/media/AudioPresentation.java +++ b/media/java/android/media/AudioPresentation.java @@ -54,7 +54,11 @@ public final class AudioPresentation {      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 @@ public final class AudioPresentation {          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 472586b5e519..7f970f79b1cf 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -277,7 +277,7 @@ public class ImageReader implements AutoCloseable {      }      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 @@ public class ImageReader implements AutoCloseable {          // 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 @@ public class ImageReader implements AutoCloseable {          // 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 @@ public class ImageReader implements AutoCloseable {       * @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 @@ public class ImageReader implements AutoCloseable {              // 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 @@ public class ImageReader implements AutoCloseable {          // 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 @@ public class ImageReader implements AutoCloseable {      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 @@ public class ImageReader implements AutoCloseable {              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 @@ public class ImageReader implements AutoCloseable {              // 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 @@ public class ImageReader implements AutoCloseable {              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 @@ public class ImageReader implements AutoCloseable {          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 @@ public class ImageReader implements AutoCloseable {       * @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 9f52bf18f4e3..0291f64c0640 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -29,7 +29,6 @@ import android.hardware.DataSpace.NamedDataSpace;  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 @@ public class ImageWriter implements AutoCloseable {      }      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 @@ public class ImageWriter implements AutoCloseable {          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 @@ public class ImageWriter implements AutoCloseable {          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 @@ public class ImageWriter implements AutoCloseable {              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 @@ public class ImageWriter implements AutoCloseable {          // 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 @@ public class ImageWriter implements AutoCloseable {          // 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 @@ public class ImageWriter implements AutoCloseable {              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 @@ public class ImageWriter implements AutoCloseable {          }          // 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 @@ public class ImageWriter implements AutoCloseable {              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/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS index 9ca391013aa3..96532d00831b 100644 --- a/media/java/android/media/projection/OWNERS +++ b/media/java/android/media/projection/OWNERS @@ -1,2 +1,3 @@  michaelwr@google.com  santoscordon@google.com +chaviw@google.com diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 62c0d55951af..3b93b07b98bc 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -375,11 +375,11 @@ static void ImageReader_classInit(JNIEnv* env, jclass clazz)  }  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 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w      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 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w              /*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 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w      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 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w      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 @@ static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)      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 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image,          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 ImageReader_createImagePlanes(JNIEnv* env, jobject /*thiz*/,  }  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 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,      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 @@ static const JNINativeMethod gImageReaderMethods[] = {      {"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 6c6fccb59216..2c498e5bb4ef 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -415,7 +415,9 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje      // 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 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje      // 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 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje              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 status_t attachAndQeueuGraphicBuffer(JNIEnv* env, JNIImageWriterContext *  }  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 @@ static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat      }      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_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat  }  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 @@ static jint ImageWriter_attachAndQueueGraphicBuffer(JNIEnv* env, jobject thiz, j      }      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 void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image)  }  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 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,                  " probably out of memory");          return NULL;      } -    if (isFormatOpaque(format)) { + +    if (isFormatOpaque(halFormat)) {          return surfacePlanes;      } @@ -1074,10 +1089,8 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,      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 gImageWriterMethods[] = {  };  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/media/tests/projection/OWNERS b/media/tests/projection/OWNERS new file mode 100644 index 000000000000..832bcd9d70e6 --- /dev/null +++ b/media/tests/projection/OWNERS @@ -0,0 +1 @@ +include /media/java/android/media/projection/OWNERS diff --git a/services/Android.bp b/services/Android.bp index 4d38b067d3a4..2e2e51b7e86e 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -176,6 +176,7 @@ java_library {          "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 d35c07f1962a..9268fc03bd2f 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -131,6 +131,7 @@ java_library_static {          "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 ec8745aa7371..fdfcfa3b43c9 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -732,6 +732,7 @@ class StorageManagerService extends IStorageManager.Stub      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 @@ class StorageManagerService extends IStorageManager.Stub                      }                      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 @@ class StorageManagerService extends IStorageManager.Stub                  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 @@ class StorageManagerService extends IStorageManager.Stub                  // 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 @@ class StorageManagerService extends IStorageManager.Stub      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 eb6a3b3a3cea..5893d44987b3 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 @@ public final class ProcessList {              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 @@ public final class ProcessList {                  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 bc9bc031ca35..4fcde97fc772 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 @@ public class Vpn {                  return;              } else {                  mActiveNetwork = null; +                mUnderlyingNetworkCapabilities = null; +                mUnderlyingLinkProperties = null;              }              if (mScheduledHandleNetworkLostFuture != null) { @@ -3664,9 +3666,6 @@ public class Vpn {                  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 ae9c64b48006..ad27c45df6d4 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.FontFamily;  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.text.FontConfig;  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 com.android.server.SystemService;  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 @@ public final class FontManagerService extends IFontManager.Stub {      }      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 @@ public final class FontManagerService extends IFontManager.Stub {      @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 @@ public final class FontManagerService extends IFontManager.Stub {              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 @@ public final class FontManagerService extends IFontManager.Stub {      /* 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 @@ public final class FontManagerService extends IFontManager.Stub {      }      /* 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 @@ public final class FontManagerService extends IFontManager.Stub {       * 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 3fecef703613..94783449b0d5 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.FontUpdateRequest;  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 @@ public class FontManagerShellCommand extends ShellCommand {          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 @@ public class FontManagerShellCommand extends ShellCommand {          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 @@ public class FontManagerShellCommand extends ShellCommand {                      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 743b4d90dd73..457d5b7afe84 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.FileDescriptor;  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 @@ final class UpdatableFontDir {      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 @@ final class UpdatableFontDir {      /** 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 @@ final class UpdatableFontDir {                      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 @@ final class UpdatableFontDir {              } 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 @@ final class UpdatableFontDir {       * 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/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS index 9ca391013aa3..832bcd9d70e6 100644 --- a/services/core/java/com/android/server/media/projection/OWNERS +++ b/services/core/java/com/android/server/media/projection/OWNERS @@ -1,2 +1 @@ -michaelwr@google.com -santoscordon@google.com +include /media/java/android/media/projection/OWNERS diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java index f6b22bc38939..a03a16ad7bc3 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 @@ final class InitAppsHelper {              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 94e8ec5c434d..85b01491a8b7 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 @@ public class PackageManagerService implements PackageSender, TestUtilityService          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 @@ public class PackageManagerService implements PackageSender, TestUtilityService                          + 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 000000000000..348f94048311 --- /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 000000000000..65a4b38629b6 --- /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 a953bcbe5453..0ceda79ae84d 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.AttestationVerificationManagerService;  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 @@ public final class SystemServer implements Dumpable {          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 f9b8373cc79e..9672085b8f3a 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 @@ public final class UpdatableFontDirTest {          }          @Override -        public boolean hasFsverity(String path) { +        public boolean isFromTrustedProvider(String path, byte[] signature) {              return mHasFsverityPaths.contains(path);          } @@ -291,6 +291,32 @@ public final class UpdatableFontDirTest {      }      @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 @@ public final class UpdatableFontDirTest {          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/media/projection/OWNERS b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS new file mode 100644 index 000000000000..832bcd9d70e6 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS @@ -0,0 +1 @@ +include /media/java/android/media/projection/OWNERS 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 ce322f7cb6e6..8bd6fcdbb9c2 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.PackageManager;  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.permission.PermissionManager;  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 @@ public class CrossProfileAppsServiceImplTest {          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 8ec500b4d49d..7eccd1a4482f 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -49,7 +49,6 @@ public final class EuiccProfileInfo implements Parcelable {              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 @@ public final class EuiccProfileInfo implements Parcelable {              PROFILE_CLASS_OPERATIONAL,              PROFILE_CLASS_UNSET      }) -    /** @hide */      public @interface ProfileClass {}      /** Testing profiles */      public static final int PROFILE_CLASS_TESTING = 0; @@ -87,7 +85,6 @@ public final class EuiccProfileInfo implements Parcelable {              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 0a2bb3d16f24..2f8316e38363 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -75,7 +75,6 @@ public class EuiccCardManager {              CANCEL_REASON_TIMEOUT,              CANCEL_REASON_PPR_NOT_ALLOWED      }) -    /** @hide */      public @interface CancelReason {      } @@ -105,7 +104,6 @@ public class EuiccCardManager {              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 c348cff25052..be0048f73bf4 100644 --- a/telephony/java/android/telephony/euicc/EuiccNotification.java +++ b/telephony/java/android/telephony/euicc/EuiccNotification.java @@ -44,7 +44,6 @@ public final class EuiccNotification implements Parcelable {              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 d5a05ae2dbb8..1c6b6b6e83fc 100644 --- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java +++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java @@ -42,7 +42,6 @@ public final class EuiccRulesAuthTable implements Parcelable {      @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 cbe13d9aa149..650686ff3b85 100644 --- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java +++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java @@ -373,6 +373,10 @@ public class UpdatableSystemFontTest {          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 133c1767c9b4..cc3781a0bfb3 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 @@ public class BroadcastInterceptingContext extends ContextWrapper {      }      @Override +    public void sendBroadcastAsUser(Intent intent, UserHandle user, +            String receiverPermission, Bundle options) { +        sendBroadcast(intent); +    } + +    @Override      public void sendStickyBroadcast(Intent intent) {          sendBroadcast(intent);      }  |