summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/Android.bp1
-rw-r--r--cmds/bootanimation/BootAnimation.cpp5
-rw-r--r--core/java/Android.bp14
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/graphics/fonts/FontManager.java9
-rw-r--r--core/java/android/os/OWNERS3
-rw-r--r--core/java/android/security/rkp/IGetKeyCallback.aidl49
-rw-r--r--core/java/android/security/rkp/IGetRegistrationCallback.aidl49
-rw-r--r--core/java/android/security/rkp/IRegistration.aidl85
-rw-r--r--core/java/android/security/rkp/IRemoteProvisioning.aidl68
-rw-r--r--core/java/android/security/rkp/OWNERS5
-rw-r--r--core/java/android/security/rkp/RemotelyProvisionedKey.aidl44
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java1
-rw-r--r--core/java/android/window/WindowContainerToken.java2
-rw-r--r--core/java/android/window/WindowContainerTransaction.java2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp301
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--media/java/android/media/AudioPresentation.java11
-rw-r--r--media/java/android/media/ImageReader.java54
-rw-r--r--media/java/android/media/ImageWriter.java75
-rw-r--r--media/java/android/media/projection/OWNERS1
-rw-r--r--media/jni/android_media_ImageReader.cpp44
-rw-r--r--media/jni/android_media_ImageWriter.cpp59
-rw-r--r--media/tests/projection/OWNERS1
-rw-r--r--services/Android.bp1
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java35
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java21
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java5
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java87
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java34
-rw-r--r--services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java58
-rw-r--r--services/core/java/com/android/server/media/projection/OWNERS3
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/core/java/com/android/server/security/rkp/OWNERS1
-rw-r--r--services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java126
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java35
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.java3
-rw-r--r--telephony/java/android/telephony/euicc/EuiccCardManager.java2
-rw-r--r--telephony/java/android/telephony/euicc/EuiccNotification.java1
-rw-r--r--telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java1
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java4
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java6
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);
}