Merge "Ensure WAIT packet upon HELO in --suspend mode"
diff --git a/Android.bp b/Android.bp
index 8e09157..0c9b82e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -106,6 +106,7 @@
":android.security.maintenance-java-source",
":android.security.metrics-java-source",
":android.system.keystore2-V3-java-source",
+ ":android.hardware.cas-V1-java-source",
":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
@@ -196,6 +197,7 @@
"updatable-driver-protos",
"ota_metadata_proto_java",
"android.hidl.base-V1.0-java",
+ "android.hardware.cas-V1-java", // AIDL
"android.hardware.cas-V1.0-java",
"android.hardware.cas-V1.1-java",
"android.hardware.cas-V1.2-java",
@@ -617,3 +619,12 @@
"ProtoLibraries.bp",
"TestProtoLibraries.bp",
]
+
+java_api_contribution {
+ name: "api-stubs-docs-non-updatable-public-stubs",
+ api_surface: "public",
+ api_file: "core/api/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
diff --git a/BROADCASTS_OWNERS b/BROADCASTS_OWNERS
new file mode 100644
index 0000000..1ea610b
--- /dev/null
+++ b/BROADCASTS_OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 316181
+ctate@android.com
+jsharkey@android.com
+jsharkey@google.com
+sudheersai@google.com
+yamasani@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 272b4f6..fc046fb 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -378,6 +378,67 @@
},
}
+java_library {
+ name: "android_stubs_private_jar",
+ defaults: ["android.jar_defaults"],
+ visibility: [
+ "//visibility:override",
+ "//visibility:private",
+ ],
+ static_libs: [
+ "stable.core.platform.api.stubs",
+ "core-lambda-stubs-for-system-modules",
+ "core-generated-annotation-stubs",
+ "framework",
+ "ext",
+ "framework-res-package-jar",
+ // The order of this matters, it has to be last to provide a
+ // package-private androidx.annotation.RecentlyNonNull without
+ // overriding the public android.annotation.Nullable in framework.jar
+ // with its own package-private android.annotation.Nullable.
+ "private-stub-annotations-jar",
+ ],
+}
+
+java_genrule {
+ name: "android_stubs_private_hjar",
+ visibility: ["//visibility:private"],
+ srcs: [":android_stubs_private_jar{.hjar}"],
+ out: ["android_stubs_private.jar"],
+ cmd: "cp $(in) $(out)",
+}
+
+java_library {
+ name: "android_stubs_private",
+ defaults: ["android_stubs_dists_default"],
+ visibility: ["//visibility:private"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["android_stubs_private_hjar"],
+ dist: {
+ dir: "apistubs/android/private",
+ },
+}
+
+java_genrule {
+ name: "android_stubs_private_framework_aidl",
+ visibility: ["//visibility:private"],
+ tools: ["sdkparcelables"],
+ srcs: [":android_stubs_private"],
+ out: ["framework.aidl"],
+ cmd: "rm -f $(genDir)/framework.aidl.merged && " +
+ "for i in $(in); do " +
+ " rm -f $(genDir)/framework.aidl.tmp && " +
+ " $(location sdkparcelables) $$i $(genDir)/framework.aidl.tmp && " +
+ " cat $(genDir)/framework.aidl.tmp >> $(genDir)/framework.aidl.merged; " +
+ "done && " +
+ "sort -u $(genDir)/framework.aidl.merged > $(out)",
+ dist: {
+ targets: ["sdk"],
+ dir: "apistubs/android/private",
+ },
+}
+
////////////////////////////////////////////////////////////////////////
// api-versions.xml generation, for public and system. This API database
// also contains the android.test.* APIs.
@@ -537,3 +598,12 @@
],
visibility: ["//visibility:public"],
}
+
+java_api_contribution {
+ name: "frameworks-base-core-api-module-lib-stubs",
+ api_surface: "module-lib",
+ api_file: "core/api/module-lib-current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
diff --git a/boot/Android.bp b/boot/Android.bp
index 24ad9de..851294c 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -23,6 +23,18 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+soong_config_module_type {
+ name: "custom_platform_bootclasspath",
+ module_type: "platform_bootclasspath",
+ config_namespace: "AUTO",
+ bool_variables: [
+ "car_bootclasspath_fragment",
+ ],
+ properties: [
+ "fragments",
+ ],
+}
+
// This module provides access to information Soong has related to the
// whole platform bootclasspath. Currently, that information is provided solely
// through configuration but additional information will be added here.
@@ -41,7 +53,7 @@
//
// This module needs to be present in the build for the above processing to be
// done correctly.
-platform_bootclasspath {
+custom_platform_bootclasspath {
name: "platform-bootclasspath",
// The bootclasspath_fragments that contribute to the platform
@@ -115,17 +127,24 @@
apex: "com.android.wifi",
module: "com.android.wifi-bootclasspath-fragment",
},
- // only used for auto
- {
- apex: "com.android.car.framework",
- module: "com.android.car.framework-bootclasspath-fragment",
- },
{
apex: "com.android.virt",
module: "com.android.virt-bootclasspath-fragment",
},
],
+ soong_config_variables: {
+ car_bootclasspath_fragment: {
+ fragments: [
+ // only used for auto
+ {
+ apex: "com.android.car.framework",
+ module: "com.android.car.framework-bootclasspath-fragment",
+ },
+ ],
+ },
+ },
+
// Additional information needed by hidden api processing.
hidden_api: {
unsupported: [
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 7d80493..26e20f6 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -29,12 +29,18 @@
import java.util.function.Consumer;
import java.util.concurrent.Executor;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
public class UsbCommand extends Svc.Command {
public UsbCommand() {
super("usb");
}
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
@Override
public String shortHelp() {
return "Control Usb state";
@@ -92,8 +98,10 @@
if ("setFunctions".equals(args[1])) {
try {
+ int operationId = sUsbOperationCount.incrementAndGet();
+ System.out.println("setCurrentFunctions opId:" + operationId);
usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString(
- args.length >= 3 ? args[2] : ""));
+ args.length >= 3 ? args[2] : ""), operationId);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/core/api/current.txt b/core/api/current.txt
index c9b5af5..4a8f048 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6024,7 +6024,7 @@
}
public static class Notification.Action implements android.os.Parcelable {
- ctor @Deprecated public Notification.Action(int, CharSequence, android.app.PendingIntent);
+ ctor @Deprecated public Notification.Action(int, CharSequence, @Nullable android.app.PendingIntent);
method public android.app.Notification.Action clone();
method public int describeContents();
method public boolean getAllowGeneratedReplies();
@@ -6054,8 +6054,8 @@
}
public static final class Notification.Action.Builder {
- ctor @Deprecated public Notification.Action.Builder(int, CharSequence, android.app.PendingIntent);
- ctor public Notification.Action.Builder(android.graphics.drawable.Icon, CharSequence, android.app.PendingIntent);
+ ctor @Deprecated public Notification.Action.Builder(int, CharSequence, @Nullable android.app.PendingIntent);
+ ctor public Notification.Action.Builder(android.graphics.drawable.Icon, CharSequence, @Nullable android.app.PendingIntent);
ctor public Notification.Action.Builder(android.app.Notification.Action);
method @NonNull public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
@@ -7890,6 +7890,7 @@
method public int getNetworkId();
method public boolean isEnabled();
method public boolean isFallbackToDefaultConnectionAllowed();
+ method public boolean shouldBlockNonMatchingNetworks();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.PreferentialNetworkServiceConfig> CREATOR;
field public static final int PREFERENTIAL_NETWORK_ID_1 = 1; // 0x1
@@ -7907,6 +7908,7 @@
method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed(boolean);
method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setIncludedUids(@NonNull int[]);
method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setNetworkId(int);
+ method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setShouldBlockNonMatchingNetworks(boolean);
}
public class SecurityLog {
@@ -11938,6 +11940,7 @@
field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS = "android.hardware.identity_credential_direct_access";
field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
+ field public static final String FEATURE_IPSEC_TUNNEL_MIGRATION = "android.software.ipsec_tunnel_migration";
field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
field public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
field public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY = "android.hardware.keystore.limited_use_key";
@@ -17087,8 +17090,8 @@
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
- method public android.hardware.Sensor getDefaultSensor(int);
- method public android.hardware.Sensor getDefaultSensor(int, boolean);
+ method @Nullable public android.hardware.Sensor getDefaultSensor(int);
+ method @Nullable public android.hardware.Sensor getDefaultSensor(int, boolean);
method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
method public static float getInclination(float[]);
method public static float[] getOrientation(float[], float[]);
@@ -21141,6 +21144,7 @@
field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
+ field public static final int SCRAMBLING_MODE_AES_CBC = 14; // 0xe
field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa
field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb
field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6
@@ -30766,7 +30770,8 @@
method public static void scaleM(float[], int, float, float, float);
method public static void setIdentityM(float[], int);
method public static void setLookAtM(float[], int, float, float, float, float, float, float, float, float, float);
- method public static void setRotateEulerM(float[], int, float, float, float);
+ method @Deprecated public static void setRotateEulerM(float[], int, float, float, float);
+ method public static void setRotateEulerM2(@NonNull float[], int, float, float, float);
method public static void setRotateM(float[], int, float, float, float, float);
method public static void translateM(float[], int, float[], int, float, float, float);
method public static void translateM(float[], int, float, float, float);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 8d53959..3a94198 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -120,6 +120,7 @@
field public static final int GADGET_HAL_V1_0 = 10; // 0xa
field public static final int GADGET_HAL_V1_1 = 11; // 0xb
field public static final int GADGET_HAL_V1_2 = 12; // 0xc
+ field public static final int GADGET_HAL_V2_0 = 20; // 0x14
field public static final int USB_DATA_TRANSFER_RATE_10G = 10240; // 0x2800
field public static final int USB_DATA_TRANSFER_RATE_20G = 20480; // 0x5000
field public static final int USB_DATA_TRANSFER_RATE_40G = 40960; // 0xa000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9ff0afe..8a1d6f2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6189,6 +6189,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method public boolean isAudioServerRunning();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isBluetoothVariableLatencyEnabled();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable();
method @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND) public boolean isUltrasoundSupported();
@@ -6207,6 +6208,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setActiveAssistantServiceUids(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
@@ -6214,6 +6216,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean supportsBluetoothVariableLatency();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterMuteAwaitConnectionCallback(@NonNull android.media.AudioManager.MuteAwaitConnectionCallback);
@@ -9117,14 +9120,20 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
+ field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
+ field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
+ field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
}
public static interface NfcAdapter.ControllerAlwaysOnListener {
@@ -14959,6 +14968,7 @@
field public static final String SERVICE_ID_POST_CALL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
field public static final String SERVICE_ID_SHARED_MAP = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
field public static final String SERVICE_ID_SHARED_SKETCH = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+ field public static final String SERVICE_ID_SLM = "org.openmobilealliance:StandaloneMsg";
field public static final String TUPLE_BASIC_STATUS_CLOSED = "closed";
field public static final String TUPLE_BASIC_STATUS_OPEN = "open";
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f320b74..b316b19 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1783,7 +1783,7 @@
* @deprecated Use {@link android.app.Notification.Action.Builder}.
*/
@Deprecated
- public Action(int icon, CharSequence title, PendingIntent intent) {
+ public Action(int icon, CharSequence title, @Nullable PendingIntent intent) {
this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true,
SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */);
}
@@ -1908,10 +1908,12 @@
* which may display them in other contexts, for example on a wearable device.
* @param icon icon to show for this action
* @param title the title of the action
- * @param intent the {@link PendingIntent} to fire when users trigger this action
+ * @param intent the {@link PendingIntent} to fire when users trigger this action. May
+ * be null, in which case the action may be rendered in a disabled presentation by the
+ * system UI.
*/
@Deprecated
- public Builder(int icon, CharSequence title, PendingIntent intent) {
+ public Builder(int icon, CharSequence title, @Nullable PendingIntent intent) {
this(Icon.createWithResource("", icon), title, intent);
}
@@ -1940,9 +1942,11 @@
*
* @param icon icon to show for this action
* @param title the title of the action
- * @param intent the {@link PendingIntent} to fire when users trigger this action
+ * @param intent the {@link PendingIntent} to fire when users trigger this action. May
+ * be null, in which case the action may be rendered in a disabled presentation by the
+ * system UI.
*/
- public Builder(Icon icon, CharSequence title, PendingIntent intent) {
+ public Builder(Icon icon, CharSequence title, @Nullable PendingIntent intent) {
this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false);
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f2eced3..20869e0 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -47,6 +47,9 @@
# AppOps
per-file *AppOp* = file:/core/java/android/permission/OWNERS
+# Backup and Restore
+per-file IBackupAgent.aidl = file:/services/backup/OWNERS
+
# LocaleManager
per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 34c91c3..bfab8c9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2391,6 +2391,7 @@
* applied (cross profile intent filters updated). Only usesd for CTS tests.
* @hide
*/
+ @SuppressLint("ActionValue")
@TestApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED =
@@ -2401,6 +2402,7 @@
* has been changed.
* @hide
*/
+ @SuppressLint("ActionValue")
@TestApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED =
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
index 63c9839..1e0d062 100644
--- a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -50,6 +50,7 @@
final boolean mIsEnabled;
final int mNetworkId;
final boolean mAllowFallbackToDefaultConnection;
+ final boolean mShouldBlockNonMatchingNetworks;
final int[] mIncludedUids;
final int[] mExcludedUids;
@@ -63,6 +64,8 @@
"preferential_network_service_network_id";
private static final String TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION =
"allow_fallback_to_default_connection";
+ private static final String TAG_BLOCK_NON_MATCHING_NETWORKS =
+ "block_non_matching_networks";
private static final String TAG_INCLUDED_UIDS = "included_uids";
private static final String TAG_EXCLUDED_UIDS = "excluded_uids";
private static final String ATTR_VALUE = "value";
@@ -110,10 +113,12 @@
}
private PreferentialNetworkServiceConfig(boolean isEnabled,
- boolean allowFallbackToDefaultConnection, int[] includedUids,
+ boolean allowFallbackToDefaultConnection, boolean shouldBlockNonMatchingNetworks,
+ int[] includedUids,
int[] excludedUids, @PreferentialNetworkPreferenceId int networkId) {
mIsEnabled = isEnabled;
mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection;
+ mShouldBlockNonMatchingNetworks = shouldBlockNonMatchingNetworks;
mIncludedUids = includedUids;
mExcludedUids = excludedUids;
mNetworkId = networkId;
@@ -122,6 +127,7 @@
private PreferentialNetworkServiceConfig(Parcel in) {
mIsEnabled = in.readBoolean();
mAllowFallbackToDefaultConnection = in.readBoolean();
+ mShouldBlockNonMatchingNetworks = in.readBoolean();
mNetworkId = in.readInt();
mIncludedUids = in.createIntArray();
mExcludedUids = in.createIntArray();
@@ -136,9 +142,18 @@
}
/**
- * is fallback to default network allowed. This boolean configures whether default connection
- * (default internet or wifi) should be used or not if a preferential network service
- * connection is not available.
+ * Whether fallback to the device-wide default network is allowed.
+ *
+ * This boolean configures whether the default connection (e.g. general cell network or wifi)
+ * should be used if no preferential network service connection is available. If true, the
+ * default connection will be used when no preferential service is available. If false, the
+ * UIDs subject to this configuration will have no default network.
+ * Note that while this boolean determines whether the UIDs subject to this configuration have
+ * a default network in the absence of a preferential service, apps can still explicitly decide
+ * to use another network than their default network by requesting them from the system. This
+ * boolean does not determine whether the UIDs are blocked from using such other networks.
+ * See {@link #shouldBlockNonMatchingNetworks()} for that configuration.
+ *
* @return true if fallback is allowed, else false.
*/
public boolean isFallbackToDefaultConnectionAllowed() {
@@ -146,6 +161,21 @@
}
/**
+ * Whether to block UIDs from using other networks than the preferential service.
+ *
+ * Apps can inspect the list of available networks on the device and choose to use multiple
+ * of them concurrently for performance, privacy or other reasons.
+ * This boolean configures whether the concerned UIDs should be blocked from using
+ * networks that do not match the configured preferential network service even if these
+ * networks are otherwise open to all apps.
+ *
+ * @return true if UIDs should be blocked from using the other networks, else false.
+ */
+ public boolean shouldBlockNonMatchingNetworks() {
+ return mShouldBlockNonMatchingNetworks;
+ }
+
+ /**
* Get the array of uids that are applicable for the profile preference.
*
* {@see #getExcludedUids()}
@@ -189,6 +219,7 @@
return "PreferentialNetworkServiceConfig{"
+ "mIsEnabled=" + isEnabled()
+ "mAllowFallbackToDefaultConnection=" + isFallbackToDefaultConnectionAllowed()
+ + "mBlockNonMatchingNetworks=" + shouldBlockNonMatchingNetworks()
+ "mIncludedUids=" + Arrays.toString(mIncludedUids)
+ "mExcludedUids=" + Arrays.toString(mExcludedUids)
+ "mNetworkId=" + mNetworkId
@@ -202,6 +233,7 @@
final PreferentialNetworkServiceConfig that = (PreferentialNetworkServiceConfig) o;
return mIsEnabled == that.mIsEnabled
&& mAllowFallbackToDefaultConnection == that.mAllowFallbackToDefaultConnection
+ && mShouldBlockNonMatchingNetworks == that.mShouldBlockNonMatchingNetworks
&& mNetworkId == that.mNetworkId
&& Arrays.equals(mIncludedUids, that.mIncludedUids)
&& Arrays.equals(mExcludedUids, that.mExcludedUids);
@@ -210,7 +242,8 @@
@Override
public int hashCode() {
return Objects.hash(mIsEnabled, mAllowFallbackToDefaultConnection,
- Arrays.hashCode(mIncludedUids), Arrays.hashCode(mExcludedUids), mNetworkId);
+ mShouldBlockNonMatchingNetworks, Arrays.hashCode(mIncludedUids),
+ Arrays.hashCode(mExcludedUids), mNetworkId);
}
/**
@@ -221,6 +254,7 @@
boolean mIsEnabled = false;
int mNetworkId = 0;
boolean mAllowFallbackToDefaultConnection = true;
+ boolean mShouldBlockNonMatchingNetworks = false;
int[] mIncludedUids = new int[0];
int[] mExcludedUids = new int[0];
@@ -242,10 +276,21 @@
}
/**
- * Set whether the default connection should be used as fallback.
- * This boolean configures whether the default connection (default internet or wifi)
- * should be used if a preferential network service connection is not available.
- * Default value is true
+ * Set whether fallback to the device-wide default network is allowed.
+ *
+ * This boolean configures whether the default connection (e.g. general cell network or
+ * wifi) should be used if no preferential network service connection is available. If true,
+ * the default connection will be used when no preferential service is available. If false,
+ * the UIDs subject to this configuration will have no default network.
+ * Note that while this boolean determines whether the UIDs subject to this configuration
+ * have a default network in the absence of a preferential service, apps can still
+ * explicitly decide to use another network than their default network by requesting them
+ * from the system. This boolean does not determine whether the UIDs are blocked from using
+ * such other networks.
+ * Use {@link #setShouldBlockNonMatchingNetworks(boolean)} to specify this.
+ *
+ * The default value is true.
+ *
* @param allowFallbackToDefaultConnection true if fallback is allowed else false
* @return The builder to facilitate chaining.
*/
@@ -258,6 +303,31 @@
}
/**
+ * Set whether to block UIDs from using other networks than the preferential service.
+ *
+ * Apps can inspect the list of available networks on the device and choose to use multiple
+ * of them concurrently for performance, privacy or other reasons.
+ * This boolean configures whether the concerned UIDs should be blocked from using
+ * networks that do not match the configured preferential network service even if these
+ * networks are otherwise open to all apps.
+ *
+ * The default value is false. This value can only be set to {@code true} if
+ * {@link #setFallbackToDefaultConnectionAllowed(boolean)} is set to {@code false}, because
+ * allowing fallback but blocking it does not make sense. Failure to comply with this
+ * constraint will throw when building the object.
+ *
+ * @param blockNonMatchingNetworks true if UIDs should be blocked from using non-matching
+ * networks.
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public PreferentialNetworkServiceConfig.Builder setShouldBlockNonMatchingNetworks(
+ boolean blockNonMatchingNetworks) {
+ mShouldBlockNonMatchingNetworks = blockNonMatchingNetworks;
+ return this;
+ }
+
+ /**
* Set the array of uids whose network access will go through this preferential
* network service.
* {@see #setExcludedUids(int[])}
@@ -305,8 +375,13 @@
throw new IllegalStateException("Both includedUids and excludedUids "
+ "cannot be nonempty");
}
+ if (mShouldBlockNonMatchingNetworks && mAllowFallbackToDefaultConnection) {
+ throw new IllegalStateException("A config cannot both allow fallback and "
+ + "block non-matching networks");
+ }
return new PreferentialNetworkServiceConfig(mIsEnabled,
- mAllowFallbackToDefaultConnection, mIncludedUids, mExcludedUids, mNetworkId);
+ mAllowFallbackToDefaultConnection, mShouldBlockNonMatchingNetworks,
+ mIncludedUids, mExcludedUids, mNetworkId);
}
/**
@@ -331,6 +406,7 @@
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
dest.writeBoolean(mIsEnabled);
dest.writeBoolean(mAllowFallbackToDefaultConnection);
+ dest.writeBoolean(mShouldBlockNonMatchingNetworks);
dest.writeInt(mNetworkId);
dest.writeIntArray(mIncludedUids);
dest.writeIntArray(mExcludedUids);
@@ -422,6 +498,9 @@
} else if (TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION.equals(tagDAM)) {
resultBuilder.setFallbackToDefaultConnectionAllowed(parser.getAttributeBoolean(
null, ATTR_VALUE, true));
+ } else if (TAG_BLOCK_NON_MATCHING_NETWORKS.equals(tagDAM)) {
+ resultBuilder.setShouldBlockNonMatchingNetworks(parser.getAttributeBoolean(
+ null, ATTR_VALUE, false));
} else if (TAG_INCLUDED_UIDS.equals(tagDAM)) {
resultBuilder.setIncludedUids(readStringListToIntArray(parser, TAG_UID));
} else if (TAG_EXCLUDED_UIDS.equals(tagDAM)) {
@@ -442,6 +521,8 @@
writeAttributeValueToXml(out, TAG_NETWORK_ID, getNetworkId());
writeAttributeValueToXml(out, TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION,
isFallbackToDefaultConnectionAllowed());
+ writeAttributeValueToXml(out, TAG_BLOCK_NON_MATCHING_NETWORKS,
+ shouldBlockNonMatchingNetworks());
writeAttributeValuesToXml(out, TAG_INCLUDED_UIDS, TAG_UID,
intArrayToStringList(getIncludedUids()));
writeAttributeValuesToXml(out, TAG_EXCLUDED_UIDS, TAG_UID,
@@ -459,6 +540,8 @@
pw.println(mIsEnabled);
pw.print("allowFallbackToDefaultConnection=");
pw.println(mAllowFallbackToDefaultConnection);
+ pw.print("blockNonMatchingNetworks=");
+ pw.println(mShouldBlockNonMatchingNetworks);
pw.print("includedUids=");
pw.println(mIncludedUids);
pw.print("excludedUids=");
diff --git a/core/java/android/app/admin/Provisioning_OWNERS b/core/java/android/app/admin/Provisioning_OWNERS
index c59a9dc..2e5c2df 100644
--- a/core/java/android/app/admin/Provisioning_OWNERS
+++ b/core/java/android/app/admin/Provisioning_OWNERS
@@ -1,5 +1,5 @@
# Assign bugs to android-enterprise-triage@google.com
-petuska@google.com
-nupursn@google.com
-shreyacsingh@google.com
-alexkershaw@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
+mdb.ae-provisioning-reviews@google.com
+petuska@google.com #{LAST_RESORT_SUGGESTION}
+nupursn@google.com #{LAST_RESORT_SUGGESTION}
+shreyacsingh@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 1c9713d..2cde539 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -13,3 +13,4 @@
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
per-file ComponentCallbacksController = file:/services/core/java/com/android/server/wm/OWNERS
per-file ComponentCallbacksController = charlesccchen@google.com
+per-file Broadcast* = file:/BROADCASTS_OWNERS
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7d9ed29..d83ad3d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4058,6 +4058,17 @@
public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * the requisite kernel support for migrating IPsec tunnels to new source/destination addresses.
+ *
+ * <p>This feature implies that the device supports XFRM Migration (CONFIG_XFRM_MIGRATE) and has
+ * the kernel fixes to support cross-address-family IPsec tunnel migration
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_IPSEC_TUNNEL_MIGRATION =
+ "android.software.ipsec_tunnel_migration";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports a system interface for the user to select
* and bind device control services provided by applications.
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 3b6a564..d2a2f12 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -16,3 +16,6 @@
# Buffers
per-file HardwareBuffer* = file:/graphics/java/android/graphics/OWNERS
per-file DataSpace* = file:/graphics/java/android/graphics/OWNERS
+
+# OverlayProperties
+per-file OverlayProperties* = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index dec424c..6d8c4a9 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
@@ -496,7 +497,7 @@
* @see #getSensorList(int)
* @see Sensor
*/
- public Sensor getDefaultSensor(int type) {
+ public @Nullable Sensor getDefaultSensor(int type) {
// TODO: need to be smarter, for now, just return the 1st sensor
List<Sensor> l = getSensorList(type);
boolean wakeUpSensor = false;
@@ -544,7 +545,7 @@
* and the application has the necessary permissions, or null otherwise.
* @see Sensor#isWakeUpSensor()
*/
- public Sensor getDefaultSensor(int type, boolean wakeUp) {
+ public @Nullable Sensor getDefaultSensor(int type, boolean wakeUp) {
List<Sensor> l = getSensorList(type);
for (Sensor sensor : l) {
if (sensor.isWakeUpSensor() == wakeUp) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 468e604..5abe677 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -88,8 +88,8 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -1027,6 +1027,19 @@
return fixedFaceRectangles;
}
+ private boolean setLensShadingMap(LensShadingMap lensShadingMap) {
+ if (lensShadingMap == null) {
+ return false;
+ }
+ float[] lsmArray = new float[lensShadingMap.getGainFactorCount()];
+ lensShadingMap.copyGainFactors(lsmArray, 0);
+ setBase(CaptureResult.STATISTICS_LENS_SHADING_MAP, lsmArray);
+
+ Size s = new Size(lensShadingMap.getRowCount(), lensShadingMap.getColumnCount());
+ setBase(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE, s);
+ return true;
+ }
+
private LensShadingMap getLensShadingMap() {
float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
@@ -1851,6 +1864,13 @@
metadata.setAERegions(value);
}
});
+ sSetCommandMap.put(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setLensShadingMap((LensShadingMap) value);
+ }
+ });
}
private boolean setAvailableFormats(int[] value) {
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 5a44244..1e147ec 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -111,10 +111,10 @@
boolean isFunctionEnabled(String function);
/* Sets the current USB function. */
- void setCurrentFunctions(long functions);
+ void setCurrentFunctions(long functions, int operationId);
/* Compatibility version of setCurrentFunctions(long). */
- void setCurrentFunction(String function, boolean usbDataUnlocked);
+ void setCurrentFunction(String function, boolean usbDataUnlocked, int operationId);
/* Gets the current USB functions. */
long getCurrentFunctions();
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 60d8cac..7c2e518 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -108,6 +108,34 @@
}
/**
+ * This is meant to be called by UsbRequest's queue() in order to synchronize on
+ * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueRequest(UsbRequest request, ByteBuffer buffer, int length) {
+ synchronized (mLock) {
+ if (!isOpen()) {
+ return false;
+ }
+
+ return request.queueIfConnectionOpen(buffer, length);
+ }
+ }
+
+ /**
+ * This is meant to be called by UsbRequest's queue() in order to synchronize on
+ * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueRequest(UsbRequest request, @Nullable ByteBuffer buffer) {
+ synchronized (mLock) {
+ if (!isOpen()) {
+ return false;
+ }
+
+ return request.queueIfConnectionOpen(buffer);
+ }
+ }
+
+ /**
* Releases all system resources related to the device.
* Once the object is closed it cannot be used again.
* The client must call {@link UsbManager#openDevice} again
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 2c38f70..9d672bb 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -38,6 +38,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -52,6 +53,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class allows you to access the state of USB and communicate with USB devices.
@@ -95,7 +97,7 @@
* If the sticky intent has not been found, that indicates USB is disconnected,
* USB is not configued, MTP function is enabled, and all the other functions are disabled.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String ACTION_USB_STATE =
@@ -172,7 +174,7 @@
* <p>For more information about communicating with USB accessory handshake, refer to
* <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
*
- * {@hide}
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@SystemApi
@@ -184,7 +186,7 @@
* Boolean extra indicating whether USB is connected or disconnected.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_CONNECTED = "connected";
@@ -193,7 +195,7 @@
* Boolean extra indicating whether USB is connected or disconnected as host.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
public static final String USB_HOST_CONNECTED = "host_connected";
@@ -201,7 +203,7 @@
* Boolean extra indicating whether USB is configured.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_CONFIGURED = "configured";
@@ -212,7 +214,7 @@
* has explicitly asked for this data to be unlocked.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String USB_DATA_UNLOCKED = "unlocked";
@@ -221,7 +223,7 @@
* A placeholder indicating that no USB function is being specified.
* Used for compatibility with old init scripts to indicate no functions vs. charging function.
*
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage
public static final String USB_FUNCTION_NONE = "none";
@@ -230,7 +232,7 @@
* Name of the adb USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_ADB = "adb";
@@ -238,7 +240,7 @@
* Name of the RNDIS ethernet USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_FUNCTION_RNDIS = "rndis";
@@ -247,7 +249,7 @@
* Name of the MTP USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_MTP = "mtp";
@@ -255,7 +257,7 @@
* Name of the PTP USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_PTP = "ptp";
@@ -263,7 +265,7 @@
* Name of the audio source USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
@@ -271,7 +273,7 @@
* Name of the MIDI USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_MIDI = "midi";
@@ -279,7 +281,7 @@
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_ACCESSORY = "accessory";
@@ -287,7 +289,7 @@
* Name of the NCM USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_FUNCTION_NCM = "ncm";
@@ -295,32 +297,39 @@
/**
* Name of Gadget Hal Not Present;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_UNKNOWN = "unknown";
/**
* Name of the USB Gadget Hal Version v1.0;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_0 = "V1_0";
/**
* Name of the USB Gadget Hal Version v1.1;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_1 = "V1_1";
/**
* Name of the USB Gadget Hal Version v1.2;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_2 = "V1_2";
/**
+ * Name of the USB Gadget Hal Version v2.0;
+ *
+ * @hide
+ */
+ public static final String GADGET_HAL_VERSION_2_0 = "V2_0";
+
+ /**
* Name of extra for {@link #ACTION_USB_PORT_CHANGED}
* containing the {@link UsbPort} object for the port.
*
@@ -356,7 +365,7 @@
* This is obtained with SystemClock.elapsedRealtime()
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_UEVENT_TIME =
@@ -370,7 +379,7 @@
* between communicating with USB accessory handshake, refer to
* <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_STRING_COUNT =
@@ -380,7 +389,7 @@
* Boolean extra indicating whether got start accessory or not
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_START =
@@ -392,7 +401,7 @@
* sending {@link #ACTION_USB_ACCESSORY_HANDSHAKE}.
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_HANDSHAKE_END =
@@ -426,7 +435,7 @@
/**
* The Value for USB gadget hal is not presented.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_NOT_SUPPORTED = -1;
@@ -434,7 +443,7 @@
/**
* Value for Gadget Hal Version v1.0.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_0 = 10;
@@ -442,7 +451,7 @@
/**
* Value for Gadget Hal Version v1.1.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_1 = 11;
@@ -450,15 +459,23 @@
/**
* Value for Gadget Hal Version v1.2.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_2 = 12;
/**
+ * Value for Gadget Hal Version v2.0.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int GADGET_HAL_V2_0 = 20;
+
+ /**
* Value for USB_STATE is not configured.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1;
@@ -466,7 +483,7 @@
/**
* Value for USB Transfer Rate of Low Speed in Mbps (real value is 1.5Mbps).
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2;
@@ -474,7 +491,7 @@
/**
* Value for USB Transfer Rate of Full Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_FULL_SPEED = 12;
@@ -482,7 +499,7 @@
/**
* Value for USB Transfer Rate of High Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_HIGH_SPEED = 480;
@@ -490,7 +507,7 @@
/**
* Value for USB Transfer Rate of Super Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_5G = 5 * 1024;
@@ -498,7 +515,7 @@
/**
* Value for USB Transfer Rate of 10G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_10G = 10 * 1024;
@@ -506,7 +523,7 @@
/**
* Value for USB Transfer Rate of 20G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_20G = 20 * 1024;
@@ -514,7 +531,7 @@
/**
* Value for USB Transfer Rate of 40G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
@@ -530,7 +547,7 @@
/**
* The Value for USB hal is not presented.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_NOT_SUPPORTED = -1;
@@ -538,7 +555,7 @@
/**
* Value for USB Hal Version v1.0.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_0 = 10;
@@ -546,7 +563,7 @@
/**
* Value for USB Hal Version v1.1.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_1 = 11;
@@ -554,7 +571,7 @@
/**
* Value for USB Hal Version v1.2.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_2 = 12;
@@ -562,7 +579,7 @@
/**
* Value for USB Hal Version v1.3.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_3 = 13;
@@ -577,63 +594,63 @@
/**
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_NONE = 0;
/**
* Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_MTP = GadgetFunction.MTP;
/**
* Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_PTP = GadgetFunction.PTP;
/**
* Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
/**
* Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
/**
* Code for the accessory usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
/**
* Code for the audio source usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
/**
* Code for the adb usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_ADB = GadgetFunction.ADB;
/**
* Code for the ncm source usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_NCM = 1 << 10;
@@ -643,6 +660,11 @@
private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
static {
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP);
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP);
@@ -674,6 +696,7 @@
GADGET_HAL_V1_0,
GADGET_HAL_V1_1,
GADGET_HAL_V1_2,
+ GADGET_HAL_V2_0,
})
public @interface UsbGadgetHalVersion {}
@@ -692,7 +715,7 @@
private final IUsbManager mService;
/**
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public UsbManager(Context context, IUsbManager service) {
@@ -803,7 +826,7 @@
* {@link #FUNCTION_PTP} are supported.
* @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
*
- * {@hide}
+ * @hide
*/
public ParcelFileDescriptor getControlFd(long function) {
try {
@@ -921,7 +944,7 @@
* Only system components can call this function.
* @param device to request permissions for
*
- * {@hide}
+ * @hide
*/
public void grantPermission(UsbDevice device) {
grantPermission(device, Process.myUid());
@@ -933,7 +956,7 @@
* @param device to request permissions for
* @uid uid to give permission
*
- * {@hide}
+ * @hide
*/
public void grantPermission(UsbDevice device, int uid) {
try {
@@ -949,7 +972,7 @@
* @param device to request permissions for
* @param packageName of package to grant permissions
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -974,7 +997,7 @@
* @param function name of the USB function
* @return true if the USB function is enabled
*
- * {@hide}
+ * @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1006,14 +1029,17 @@
* @param functions the USB function(s) to set, as a bitwise mask.
* Must satisfy {@link UsbManager#areSettableFunctions}
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
public void setCurrentFunctions(@UsbFunctionMode long functions) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
- mService.setCurrentFunctions(functions);
+ mService.setCurrentFunctions(functions, operationId);
} catch (RemoteException e) {
+ Log.e(TAG, "setCurrentFunctions: failed to call setCurrentFunctions. functions:"
+ + functions + ", opId:" + operationId, e);
throw e.rethrowFromSystemServer();
}
}
@@ -1025,14 +1051,17 @@
* @param functions the USB function(s) to set.
* @param usbDataUnlocked unused
- * {@hide}
+ * @hide
*/
@Deprecated
@UnsupportedAppUsage
public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
- mService.setCurrentFunction(functions, usbDataUnlocked);
+ mService.setCurrentFunction(functions, usbDataUnlocked, operationId);
} catch (RemoteException e) {
+ Log.e(TAG, "setCurrentFunction: failed to call setCurrentFunction. functions:"
+ + functions + ", opId:" + operationId, e);
throw e.rethrowFromSystemServer();
}
}
@@ -1047,7 +1076,7 @@
* @return The currently enabled functions, in a bitwise mask.
* A zero mask indicates that the current function is the charging function.
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1073,7 +1102,7 @@
* @param functions functions to set, in a bitwise mask.
* Must satisfy {@link UsbManager#areSettableFunctions}
*
- * {@hide}
+ * @hide
*/
public void setScreenUnlockedFunctions(long functions) {
try {
@@ -1089,7 +1118,7 @@
* @return The currently set screen enabled functions.
* A zero mask indicates that the screen unlocked functions feature is not enabled.
*
- * {@hide}
+ * @hide
*/
public long getScreenUnlockedFunctions() {
try {
@@ -1111,19 +1140,17 @@
*
* @return The value of currently USB Bandwidth.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
public int getUsbBandwidthMbps() {
int usbSpeed;
-
try {
usbSpeed = mService.getCurrentUsbSpeed();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
return usbSpeedToBandwidth(usbSpeed);
}
@@ -1135,7 +1162,7 @@
*
* @return a integer {@code GADGET_HAL_*} represent hal version.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1155,7 +1182,7 @@
*
* @return a integer {@code USB_HAL_*} represent hal version.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1451,7 +1478,7 @@
* @param usbDeviceConnectionHandler The component to handle usb connections,
* {@code null} to unset.
*
- * {@hide}
+ * @hide
*/
public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
try {
@@ -1470,7 +1497,7 @@
*
* @return Whether the mask is settable.
*
- * {@hide}
+ * @hide
*/
public static boolean areSettableFunctions(long functions) {
return functions == FUNCTION_NONE
@@ -1484,7 +1511,7 @@
*
* @return String representation of given mask
*
- * {@hide}
+ * @hide
*/
public static String usbFunctionsToString(long functions) {
StringJoiner joiner = new StringJoiner(",");
@@ -1520,7 +1547,7 @@
*
* @return A mask of all valid functions in the string
*
- * {@hide}
+ * @hide
*/
public static long usbFunctionsFromString(String functions) {
if (functions == null || functions.equals(USB_FUNCTION_NONE)) {
@@ -1542,7 +1569,7 @@
*
* @return a value of USB bandwidth
*
- * {@hide}
+ * @hide
*/
public static int usbSpeedToBandwidth(int speed) {
switch (speed) {
@@ -1576,12 +1603,14 @@
*
* @return String representation of Usb Gadget Hal Version
*
- * {@hide}
+ * @hide
*/
public static @NonNull String usbGadgetHalVersionToString(int version) {
String halVersion;
- if (version == GADGET_HAL_V1_2) {
+ if (version == GADGET_HAL_V2_0) {
+ halVersion = GADGET_HAL_VERSION_2_0;
+ } else if (version == GADGET_HAL_V1_2) {
halVersion = GADGET_HAL_VERSION_1_2;
} else if (version == GADGET_HAL_V1_1) {
halVersion = GADGET_HAL_VERSION_1_1;
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 6ac5e8d..beb0f8d 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -113,11 +113,13 @@
* Releases all resources related to this request.
*/
public void close() {
- if (mNativeContext != 0) {
- mEndpoint = null;
- mConnection = null;
- native_close();
- mCloseGuard.close();
+ synchronized (mLock) {
+ if (mNativeContext != 0) {
+ mEndpoint = null;
+ mConnection = null;
+ native_close();
+ mCloseGuard.close();
+ }
}
}
@@ -191,10 +193,32 @@
*/
@Deprecated
public boolean queue(ByteBuffer buffer, int length) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new NullPointerException("invalid connection");
+ }
+
+ // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+ // the connection being closed while queueing.
+ return connection.queueRequest(this, buffer, length);
+ }
+
+ /**
+ * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+ * there, to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueIfConnectionOpen(ByteBuffer buffer, int length) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null || !connection.isOpen()) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new NullPointerException("invalid connection");
+ }
+
boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
boolean result;
- if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
&& length > MAX_USBFS_BUFFER_SIZE) {
length = MAX_USBFS_BUFFER_SIZE;
}
@@ -243,6 +267,28 @@
* @return true if the queueing operation succeeded
*/
public boolean queue(@Nullable ByteBuffer buffer) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new IllegalStateException("invalid connection");
+ }
+
+ // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+ // the connection being closed while queueing.
+ return connection.queueRequest(this, buffer);
+ }
+
+ /**
+ * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+ * there, to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueIfConnectionOpen(@Nullable ByteBuffer buffer) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null || !connection.isOpen()) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new IllegalStateException("invalid connection");
+ }
+
// Request need to be initialized
Preconditions.checkState(mNativeContext != 0, "request is not initialized");
@@ -260,7 +306,7 @@
mIsUsingNewQueue = true;
wasQueued = native_queue(null, 0, 0);
} else {
- if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+ if (connection.getContext().getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.P) {
// Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
@@ -363,11 +409,12 @@
* @return true if cancelling succeeded
*/
public boolean cancel() {
- if (mConnection == null) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
return false;
}
- return mConnection.cancelRequest(this);
+ return connection.cancelRequest(this);
}
/**
@@ -382,7 +429,8 @@
* @return true if cancelling succeeded.
*/
/* package */ boolean cancelIfOpen() {
- if (mNativeContext == 0 || (mConnection != null && !mConnection.isOpen())) {
+ UsbDeviceConnection connection = mConnection;
+ if (mNativeContext == 0 || (connection != null && !connection.isOpen())) {
Log.w(TAG,
"Detected attempt to cancel a request on a connection which isn't open");
return false;
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index de107a2..8a30ef4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -80,4 +80,10 @@
boolean isControllerAlwaysOnSupported();
void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
void unregisterControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+ boolean isTagIntentAppPreferenceSupported();
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+ Map getTagIntentAppPreferenceForUser(int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+ int setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow);
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 935374d1..911aaf3 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -122,7 +122,7 @@
Binder token;
public NfcActivityState(Activity activity) {
- if (activity.getWindow().isDestroyed()) {
+ if (activity.isDestroyed()) {
throw new IllegalStateException("activity is already destroyed");
}
// Check if activity is resumed right now, as we will not
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 0c7f529..a980158 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -17,12 +17,14 @@
package android.nfc;
import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.OnActivityPausedListener;
@@ -46,9 +48,14 @@
import android.util.Log;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -371,6 +378,45 @@
public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
"android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+ /**
+ * The requested app is correctly added to the Tag intent app preference.
+ *
+ * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
+ * @hide
+ */
+ @SystemApi
+ public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0;
+
+ /**
+ * The requested app is not installed on the device.
+ *
+ * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
+ * @hide
+ */
+ @SystemApi
+ public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1;
+
+ /**
+ * The NfcService is not available.
+ *
+ * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
+ * @hide
+ */
+ @SystemApi
+ public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2;
+
+ /**
+ * Possible response codes from {@link #setTagIntentAppPreferenceForUser}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "TAG_INTENT_APP_PREF_RESULT" }, value = {
+ TAG_INTENT_APP_PREF_RESULT_SUCCESS,
+ TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND,
+ TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TagIntentAppPreferenceResult {}
+
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
@@ -2408,4 +2454,133 @@
@NonNull ControllerAlwaysOnListener listener) {
mControllerAlwaysOnListener.unregister(listener);
}
+
+
+ /**
+ * Sets whether we dispatch NFC Tag intents to the package.
+ *
+ * <p>{@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
+ * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
+ * disallowed.
+ * <p>An app is added to the preference list with the allowed flag set to {@code true}
+ * when a Tag intent is dispatched to the package for the first time. This API is called
+ * by settings to note that the user wants to change this default preference.
+ *
+ * @param userId the user to whom this package name will belong to
+ * @param pkg the full name (i.e. com.google.android.tag) of the package that will be added to
+ * the preference list
+ * @param allow {@code true} to allow dispatching Tag intents to the package's activity,
+ * {@code false} otherwise
+ * @return the {@link #TagIntentAppPreferenceResult} value
+ * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
+ * {@code false}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @TagIntentAppPreferenceResult
+ public int setTagIntentAppPreferenceForUser(@UserIdInt int userId,
+ @NonNull String pkg, boolean allow) {
+ Objects.requireNonNull(pkg, "pkg cannot be null");
+ if (!isTagIntentAppPreferenceSupported()) {
+ Log.e(TAG, "TagIntentAppPreference is not supported");
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ try {
+ return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE;
+ }
+ }
+
+
+ /**
+ * Get the Tag dispatch preference list of the UserId.
+ *
+ * <p>This returns a mapping of package names for this user id to whether we dispatch Tag
+ * intents to the package. {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
+ * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
+ * disallowed.
+ *
+ * @param userId the user to whom this preference list will belong to
+ * @return a map of the UserId which indicates the mapping from package name to
+ * boolean(allow status), otherwise return an empty map
+ * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
+ * {@code false}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @NonNull
+ public Map<String, Boolean> getTagIntentAppPreferenceForUser(@UserIdInt int userId) {
+ if (!isTagIntentAppPreferenceSupported()) {
+ Log.e(TAG, "TagIntentAppPreference is not supported");
+ throw new UnsupportedOperationException();
+ }
+ try {
+ Map<String, Boolean> result = (Map<String, Boolean>) sService
+ .getTagIntentAppPreferenceForUser(userId);
+ return result;
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return Collections.emptyMap();
+ }
+ try {
+ Map<String, Boolean> result = (Map<String, Boolean>) sService
+ .getTagIntentAppPreferenceForUser(userId);
+ return result;
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return Collections.emptyMap();
+ }
+ }
+
+ /**
+ * Checks if the device supports Tag application preference.
+ *
+ * @return {@code true} if the device supports Tag application preference, {@code false}
+ * otherwise
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean isTagIntentAppPreferenceSupported() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.isTagIntentAppPreferenceSupported();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.isTagIntentAppPreferenceSupported();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
}
diff --git a/core/java/android/nfc/OWNERS b/core/java/android/nfc/OWNERS
index 6aaf039..9a2e446 100644
--- a/core/java/android/nfc/OWNERS
+++ b/core/java/android/nfc/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 48448
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
diff --git a/core/java/android/nfc/TechListParcel.java b/core/java/android/nfc/TechListParcel.java
index 90645dd..9f01559 100644
--- a/core/java/android/nfc/TechListParcel.java
+++ b/core/java/android/nfc/TechListParcel.java
@@ -53,7 +53,7 @@
int count = source.readInt();
String[][] techLists = new String[count][];
for (int i = 0; i < count; i++) {
- techLists[i] = source.readStringArray();
+ techLists[i] = source.createStringArray();
}
return new TechListParcel(techLists);
}
diff --git a/core/java/android/nfc/cardemulation/OWNERS b/core/java/android/nfc/cardemulation/OWNERS
index 6aaf039..9a2e446 100644
--- a/core/java/android/nfc/cardemulation/OWNERS
+++ b/core/java/android/nfc/cardemulation/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 48448
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
diff --git a/core/java/android/nfc/dta/OWNERS b/core/java/android/nfc/dta/OWNERS
index 6aaf039..9a2e446 100644
--- a/core/java/android/nfc/dta/OWNERS
+++ b/core/java/android/nfc/dta/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 48448
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
diff --git a/core/java/android/nfc/tech/OWNERS b/core/java/android/nfc/tech/OWNERS
index 6aaf039..9a2e446 100644
--- a/core/java/android/nfc/tech/OWNERS
+++ b/core/java/android/nfc/tech/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 48448
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index aa56105..0cb7df7 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -358,16 +358,16 @@
* Return the Linux UID assigned to the process that sent the transaction
* currently being processed.
*
- * Logs WTF if the current thread is not currently
+ * Slog.wtf if the current thread is not currently
* executing an incoming transaction and the calling identity has not been
* explicitly set with {@link #clearCallingIdentity()}
*
* @hide
*/
- public static final int getCallingUidOrWtf() {
+ public static final int getCallingUidOrWtf(String message) {
if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
- Log.wtfStack(TAG,
- "Thread is not in a binder transaction, "
+ Slog.wtf(TAG,
+ message + ": Thread is not in a binder transaction, "
+ "and the calling identity has not been "
+ "explicitly set with clearCallingIdentity");
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7db6130..b377c92 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3344,9 +3344,26 @@
}
}
- // Fetch all flags for the namespace at once for caching purposes
- Bundle b = cp.call(cr.getAttributionSource(),
- mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
+ Bundle b;
+ // b/252663068: if we're in system server and the caller did not call
+ // clearCallingIdentity, the read would fail due to mismatched AttributionSources.
+ // TODO(b/256013480): remove this bypass after fixing the callers in system server.
+ if (namespace.equals(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER)
+ && Settings.isInSystemServer()
+ && Binder.getCallingUid() != Process.myUid()) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Fetch all flags for the namespace at once for caching purposes
+ b = cp.call(cr.getAttributionSource(),
+ mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ // Fetch all flags for the namespace at once for caching purposes
+ b = cp.call(cr.getAttributionSource(),
+ mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
+ }
if (b == null) {
// Invalid response, return an empty map
return keyValues;
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 5ff9263..0c9eaa4 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4803,10 +4803,24 @@
"phone_number_source_ims";
/**
+ * TelephonyProvider column name for last used TP - message Reference
+ *
+ * @hide
+ */
+ public static final String COLUMN_TP_MESSAGE_REF = "tp_message_ref";
+
+ /**
* TelephonyProvider column name for the device's preferred usage setting.
*
* @hide
*/
public static final String COLUMN_USAGE_SETTING = "usage_setting";
+
+ /**
+ * TelephonyProvider column name for user handle associated with this sim.
+ *
+ * @hide
+ */
+ public static final String COLUMN_USER_HANDLE = "user_handle";
}
}
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index cfb195b..13f7e5d 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -18,6 +18,7 @@
import android.os.Environment;
import android.os.UserHandle;
+
import java.io.File;
/**
@@ -32,11 +33,20 @@
private final File mUserRemovedCaDir;
private SystemCertificateSource() {
- super(new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts"));
+ super(getDirectory());
File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
mUserRemovedCaDir = new File(configDir, "cacerts-removed");
}
+ private static File getDirectory() {
+ // TODO(miguelaranda): figure out correct code path.
+ File updatable_dir = new File("/apex/com.android.conscrypt/cacerts");
+ if (updatable_dir.exists() && !(updatable_dir.list().length == 0)) {
+ return updatable_dir;
+ }
+ return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+ }
+
public static SystemCertificateSource getInstance() {
return NoPreloadHolder.INSTANCE;
}
diff --git a/core/java/android/security/rkp/IRegistration.aidl b/core/java/android/security/rkp/IRegistration.aidl
index 6522a45..8ec13b9 100644
--- a/core/java/android/security/rkp/IRegistration.aidl
+++ b/core/java/android/security/rkp/IRegistration.aidl
@@ -17,6 +17,7 @@
package android.security.rkp;
import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IStoreUpgradedKeyCallback;
/**
* This interface is associated with the registration of an
@@ -70,16 +71,18 @@
* 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,
+ * needs to be told about the new blob. After calling storeUpgradedKeyAsync,
* 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.
+ * the same time it would have if storeUpgradedKeyAsync 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}.
+ * @param callback Receives the result of the call. A callback must only
+ * be used with one {@code storeUpgradedKeyAsync} call at a time.
*/
- void storeUpgradedKey(in byte[] oldKeyBlob, in byte[] newKeyBlob);
+ void storeUpgradedKeyAsync(
+ in byte[] oldKeyBlob, in byte[] newKeyBlob, IStoreUpgradedKeyCallback callback);
}
diff --git a/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl b/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl
new file mode 100644
index 0000000..7f72fa0
--- /dev/null
+++ b/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * Callback interface for storing an upgraded remotely provisioned key blob.
+ * {@link IRegistration}.
+ *
+ * @hide
+ */
+oneway interface IStoreUpgradedKeyCallback {
+ /**
+ * Called in response to {@link IRegistration.storeUpgradedKeyAsync}, indicating
+ * a remotely-provisioned key is available.
+ */
+ void onSuccess();
+
+ /**
+ * Called when an error has occurred while trying to store an upgraded
+ * remotely provisioned key.
+ *
+ * @param error A description of what failed, suitable for logging.
+ */
+ void onError(String error);
+}
diff --git a/core/java/android/service/chooser/OWNERS b/core/java/android/service/chooser/OWNERS
index a5acba5..dcd4a7b 100644
--- a/core/java/android/service/chooser/OWNERS
+++ b/core/java/android/service/chooser/OWNERS
@@ -1,4 +1,3 @@
-asc@google.com
-mpietal@google.com
-dsandler@android.com
-dsandler@google.com
+mrcasey@google.com
+ayepin@google.com
+joshtrask@google.com
diff --git a/core/java/android/service/quickaccesswallet/OWNERS b/core/java/android/service/quickaccesswallet/OWNERS
new file mode 100644
index 0000000..232ee02
--- /dev/null
+++ b/core/java/android/service/quickaccesswallet/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 802986
+asc@google.com
+juliacr@google.com
+steell@google.com
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 3833976..56da8e0 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -2,6 +2,8 @@
per-file *Resolver* = file:/packages/SystemUI/OWNERS
per-file *Chooser* = file:/packages/SystemUI/OWNERS
per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
+per-file AbstractMultiProfilePagerAdapter.java = file:/packages/SystemUI/OWNERS
+per-file *EmptyStateProvider.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
@@ -11,4 +13,4 @@
per-file *Voice* = file:/core/java/android/service/voice/OWNERS
# System language settings
-per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS
\ No newline at end of file
+per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 5f4a9cd..473134e 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -172,14 +172,14 @@
@Override
public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
- prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
+ TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
return true;
}
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
- prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
+ TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
activity.startActivityAsUser(mResolvedIntent, options, user);
return false;
}
@@ -224,13 +224,6 @@
}
};
- private static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) {
- final int currentUserId = UserHandle.myUserId();
- if (targetUserId != currentUserId) {
- intent.fixUris(currentUserId);
- }
- }
-
private DisplayResolveInfo(Parcel in) {
mDisplayLabel = in.readCharSequence();
mExtendedInfo = in.readCharSequence();
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 264e4f7..4b9b7cb 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -232,6 +232,7 @@
}
intent.setComponent(mChooserTarget.getComponentName());
intent.putExtras(mChooserTarget.getIntentExtras());
+ TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId);
// Important: we will ignore the target security checks in ActivityManager
// if and only if the ChooserTarget's target package is the same package
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
index f56ab17..7bb7ddc 100644
--- a/core/java/com/android/internal/app/chooser/TargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -130,4 +130,15 @@
* @return true if this target should be pinned to the front by the request of the user
*/
boolean isPinned();
+
+ /**
+ * Fix the URIs in {@code intent} if cross-profile sharing is required. This should be called
+ * before launching the intent as another user.
+ */
+ static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) {
+ final int currentUserId = UserHandle.myUserId();
+ if (targetUserId != currentUserId) {
+ intent.fixUris(currentUserId);
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 5f8acff..3fb2318 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -927,7 +927,8 @@
message = messages.get(i - histSize);
}
boolean isNewGroup = currentGroup == null;
- Person sender = message.getMessage().getSenderPerson();
+ Person sender =
+ message.getMessage() == null ? null : message.getMessage().getSenderPerson();
CharSequence key = getKey(sender);
isNewGroup |= !TextUtils.equals(key, currentSenderKey);
if (isNewGroup) {
@@ -1190,7 +1191,8 @@
return null;
}
final MessagingMessage messagingMessage = mMessages.get(mMessages.size() - 1);
- final CharSequence text = messagingMessage.getMessage().getText();
+ final CharSequence text = messagingMessage.getMessage() == null ? null
+ : messagingMessage.getMessage().getText();
if (text == null && messagingMessage instanceof MessagingImageMessage) {
final String unformatted =
getResources().getString(R.string.conversation_single_line_image_placeholder);
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 146cb3f..30e4099 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -492,7 +492,9 @@
int color = mSendingSpinnerContainer.getVisibility() == View.VISIBLE
? mSendingTextColor : mTextColor;
for (MessagingMessage message : mMessages) {
- message.setColor(message.getMessage().isRemoteInputHistory() ? color : mTextColor);
+ final boolean isRemoteInputHistory =
+ message.getMessage() != null && message.getMessage().isRemoteInputHistory();
+ message.setColor(isRemoteInputHistory ? color : mTextColor);
}
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 9ac6ef7..a270b28 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -470,7 +470,8 @@
message = messages.get(i - histSize);
}
boolean isNewGroup = currentGroup == null;
- Person sender = message.getMessage().getSenderPerson();
+ Person sender =
+ message.getMessage() == null ? null : message.getMessage().getSenderPerson();
CharSequence key = sender == null ? null
: sender.getKey() == null ? sender.getName() : sender.getKey();
isNewGroup |= !TextUtils.equals(key, currentSenderKey);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index 2cc0d23..5ecd3b8 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -68,6 +68,10 @@
default boolean sameAs(Notification.MessagingStyle.Message message) {
Notification.MessagingStyle.Message ownMessage = getMessage();
+ // We have to make sure both messages are not null to go further comparison
+ if (message == null || ownMessage == null) {
+ return message == ownMessage;
+ }
if (!Objects.equals(message.getText(), ownMessage.getText())) {
return false;
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 00b0105..088c001 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1521,6 +1521,8 @@
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
+ enableIpSecTunnelMigrationOnVsrUAndAbove();
+
if (isErofsSupported()) {
if (isKernelVersionAtLeast(5, 10)) {
addFeature(PackageManager.FEATURE_EROFS, 0);
@@ -1534,6 +1536,18 @@
}
}
+ // This method only enables a new Android feature added in U and will not have impact on app
+ // compatibility
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private void enableIpSecTunnelMigrationOnVsrUAndAbove() {
+ final int vsrApi =
+ SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
+ if (vsrApi > Build.VERSION_CODES.TIRAMISU) {
+ addFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION, 0);
+ }
+ }
+
private void addFeature(String name, int version) {
FeatureInfo fi = mAvailableFeatures.get(name);
if (fi == null) {
diff --git a/core/java/com/android/server/backup/OWNERS b/core/java/com/android/server/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/core/java/com/android/server/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 53594e1..c99a27a 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -70,6 +70,7 @@
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
per-file *HardwareBuffer* = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_SyncFence.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file android_hardware_OverlayProperties.cpp = file:/graphics/java/android/graphics/OWNERS
per-file android_os_GraphicsEnvironment.cpp = file:platform/frameworks/native:/opengl/OWNERS
### Text ###
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index d852265..1c6c95f 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -541,87 +541,6 @@
indices.mData, indexCount);
}
-#define I(_i, _j) ((_j)+ 4*(_i))
-
-static
-void multiplyMM(float* r, const float* lhs, const float* rhs)
-{
- for (int i=0 ; i<4 ; i++) {
- const float rhs_i0 = rhs[ I(i,0) ];
- float ri0 = lhs[ I(0,0) ] * rhs_i0;
- float ri1 = lhs[ I(0,1) ] * rhs_i0;
- float ri2 = lhs[ I(0,2) ] * rhs_i0;
- float ri3 = lhs[ I(0,3) ] * rhs_i0;
- for (int j=1 ; j<4 ; j++) {
- const float rhs_ij = rhs[ I(i,j) ];
- ri0 += lhs[ I(j,0) ] * rhs_ij;
- ri1 += lhs[ I(j,1) ] * rhs_ij;
- ri2 += lhs[ I(j,2) ] * rhs_ij;
- ri3 += lhs[ I(j,3) ] * rhs_ij;
- }
- r[ I(i,0) ] = ri0;
- r[ I(i,1) ] = ri1;
- r[ I(i,2) ] = ri2;
- r[ I(i,3) ] = ri3;
- }
-}
-
-static
-void util_multiplyMM(JNIEnv *env, jclass clazz,
- jfloatArray result_ref, jint resultOffset,
- jfloatArray lhs_ref, jint lhsOffset,
- jfloatArray rhs_ref, jint rhsOffset) {
-
- FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
- FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
- FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
-
- bool checkOK = resultMat.check() && lhs.check() && rhs.check();
-
- if ( !checkOK ) {
- return;
- }
-
- resultMat.bind();
- lhs.bind();
- rhs.bind();
-
- multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
-
- resultMat.commitChanges();
-}
-
-static
-void multiplyMV(float* r, const float* lhs, const float* rhs)
-{
- mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
-}
-
-static
-void util_multiplyMV(JNIEnv *env, jclass clazz,
- jfloatArray result_ref, jint resultOffset,
- jfloatArray lhs_ref, jint lhsOffset,
- jfloatArray rhs_ref, jint rhsOffset) {
-
- FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
- FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
- FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
-
- bool checkOK = resultV.check() && lhs.check() && rhs.check();
-
- if ( !checkOK ) {
- return;
- }
-
- resultV.bind();
- lhs.bind();
- rhs.bind();
-
- multiplyMV(resultV.mData, lhs.mData, rhs.mData);
-
- resultV.commitChanges();
-}
-
// ---------------------------------------------------------------------------
// The internal format is no longer the same as pixel format, per Table 2 in
@@ -1009,11 +928,6 @@
* JNI registration
*/
-static const JNINativeMethod gMatrixMethods[] = {
- { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
- { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
-};
-
static const JNINativeMethod gVisibilityMethods[] = {
{ "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
{ "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
@@ -1046,7 +960,6 @@
} ClassRegistrationInfo;
static const ClassRegistrationInfo gClasses[] = {
- {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
{"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
{"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
{"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 77317d1..47057a4 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2952,6 +2952,30 @@
return jStatus;
}
+static jboolean android_media_AudioSystem_supportsBluetoothVariableLatency(JNIEnv *env,
+ jobject thiz) {
+ bool supports;
+ if (AudioSystem::supportsBluetoothVariableLatency(&supports) != NO_ERROR) {
+ supports = false;
+ }
+ return supports;
+}
+
+static int android_media_AudioSystem_setBluetoothVariableLatencyEnabled(JNIEnv *env, jobject thiz,
+ jboolean enabled) {
+ return (jint)check_AudioSystem_Command(
+ AudioSystem::setBluetoothVariableLatencyEnabled(enabled));
+}
+
+static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIEnv *env,
+ jobject thiz) {
+ bool enabled;
+ if (AudioSystem::isBluetoothVariableLatencyEnabled(&enabled) != NO_ERROR) {
+ enabled = false;
+ }
+ return enabled;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] =
@@ -3104,7 +3128,13 @@
(void *)android_media_AudioSystem_getDirectPlaybackSupport},
{"getDirectProfilesForAttributes",
"(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getDirectProfilesForAttributes}};
+ (void *)android_media_AudioSystem_getDirectProfilesForAttributes},
+ {"supportsBluetoothVariableLatency", "()Z",
+ (void *)android_media_AudioSystem_supportsBluetoothVariableLatency},
+ {"setBluetoothVariableLatencyEnabled", "(Z)I",
+ (void *)android_media_AudioSystem_setBluetoothVariableLatencyEnabled},
+ {"isBluetoothVariableLatencyEnabled", "()Z",
+ (void *)android_media_AudioSystem_isBluetoothVariableLatencyEnabled}};
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e027332..5bcba48 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -257,6 +257,7 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" />
diff --git a/core/res/OWNERS b/core/res/OWNERS
index b878189..bce500c 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -23,8 +23,8 @@
# WindowManager team
# TODO(262451702): Move WindowManager configs out of config.xml in a separate file
-per-file core/res/res/values/config.xml = file:/services/core/java/com/android/server/wm/OWNERS
-per-file core/res/res/values/symbols.xml = file:/services/core/java/com/android/server/wm/OWNERS
+per-file res/values/config.xml = file:/services/core/java/com/android/server/wm/OWNERS
+per-file res/values/symbols.xml = file:/services/core/java/com/android/server/wm/OWNERS
# Resources finalization
per-file res/xml/public-staging.xml = file:/tools/aapt2/OWNERS
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 855ecfb..73c201c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -136,9 +136,9 @@
<!-- Displayed when a SIM PUK password is too short. -->
<string name="invalidPuk">Type a PUK that is 8 numbers or longer.</string>
<!-- Displayed to prompt the user to type the PUK password to unlock
- the SIM card. -->
- <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
- <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
+ the SIM. -->
+ <string name="needPuk">Your SIM is PUK-locked. Type the PUK code to unlock it.</string>
+ <string name="needPuk2">Type PUK2 to unblock SIM.</string>
<!-- Displayed when user attempts to change SIM PIN1 without enabling PIN1. -->
<string name="enablePin">Unsuccessful, enable SIM/RUIM Lock.</string>
<!-- Displayed when a SIM PIN/PUK is entered incorrectly. -->
@@ -2434,23 +2434,23 @@
<!-- Shown when face unlock failed multiple times so we're just using the backup -->
<string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message_short">No SIM card</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="tablet">No SIM card in tablet.</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="tv">No SIM card in your Android TV device.</string>
- <!-- Shown in the lock screen when there is no SIM card. -->
- <string name="lockscreen_missing_sim_message" product="default">No SIM card in phone.</string>
- <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
- <string name="lockscreen_missing_sim_instructions">Insert a SIM card.</string>
- <!-- Shown in the lock screen to ask the user to insert a SIM card when sim is missing or not readable. -->
- <string name="lockscreen_missing_sim_instructions_long">The SIM card is missing or not readable. Insert a SIM card.</string>
- <!-- Shown in the lock screen when SIM card is permanently disabled. -->
- <string name="lockscreen_permanent_disabled_sim_message_short">Unusable SIM card.</string>
- <!-- Shown in the lock screen to inform the user to SIM card is permanently disabled. -->
- <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM card has been permanently disabled.\n
- Contact your wireless service provider for another SIM card.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message_short">No SIM</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="tablet">No SIM in tablet.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="tv">No SIM in your Android TV device.</string>
+ <!-- Shown in the lock screen when there is no SIM. -->
+ <string name="lockscreen_missing_sim_message" product="default">No SIM in phone.</string>
+ <!-- Shown in the lock screen to ask the user to add a SIM. -->
+ <string name="lockscreen_missing_sim_instructions">Add a SIM.</string>
+ <!-- Shown in the lock screen to ask the user to add a SIM when sim is missing or not readable. -->
+ <string name="lockscreen_missing_sim_instructions_long">The SIM is missing or not readable. Add a SIM.</string>
+ <!-- Shown in the lock screen when SIM is permanently disabled. -->
+ <string name="lockscreen_permanent_disabled_sim_message_short">Unusable SIM.</string>
+ <!-- Shown in the lock screen to inform the user to SIM is permanently deactivated. -->
+ <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM has been permanently deactivated.\n
+ Contact your wireless service provider for another SIM.</string>
<!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
<string name="lockscreen_transport_prev_description">Previous track</string>
@@ -2477,17 +2477,17 @@
<!-- When the user enters a wrong sim pin too many times, it becomes
PUK locked (Pin Unlock Kode) -->
- <string name="lockscreen_sim_puk_locked_message">SIM card is PUK-locked.</string>
+ <string name="lockscreen_sim_puk_locked_message">SIM is PUK-locked.</string>
<!-- Shown in the lock screen when the SIM has become PUK locked and the user must call customer care to unlock it. -->
<string name="lockscreen_sim_puk_locked_instructions">See the User Guide or contact Customer Care.</string>
<!-- Shown in the lock screen to tell the user that their SIM is locked and they must unlock it. -->
- <string name="lockscreen_sim_locked_message">SIM card is locked.</string>
+ <string name="lockscreen_sim_locked_message">SIM is locked.</string>
<!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
whether it is valid, and to unlock the sim if it is valid. we display a
progress dialog in the meantime. this is the emssage. -->
- <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- For the unlock screen, Information message shown in dialog when user has too many failed attempts at
drawing the unlock pattern -->
@@ -3781,13 +3781,13 @@
<!-- SIM swap and device reboot Dialog --> <skip />
<!-- See SIM_REMOVED_DIALOG. This is the title of that dialog. -->
- <string name="sim_removed_title">SIM card removed</string>
+ <string name="sim_removed_title">SIM removed</string>
<!-- See SIM_REMOVED_DIALOG. This is the message of that dialog. -->
- <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM card inserted.</string>
+ <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM.</string>
<!-- See SIM_REMOVED_DIALOG. This is the button of that dialog. -->
<string name="sim_done_button">Done</string>
<!-- See SIM_ADDED_DIALOG. This is the title of that dialog. -->
- <string name="sim_added_title">SIM card added</string>
+ <string name="sim_added_title">SIM added</string>
<!-- See SIM_ADDED_DIALOG. This is the message of that dialog. -->
<string name="sim_added_message">Restart your device to access the mobile network.</string>
<!-- See SIM_ADDED_DIALOG. This is the button of that dialog. -->
@@ -4611,8 +4611,8 @@
<string name="kg_puk_enter_pin_hint">Enter desired PIN code</string>
<!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen -->
<string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
- <!-- Message shown in dialog while the device is unlocking the SIM card -->
- <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <!-- Message shown in dialog while the device is unlocking the SIM -->
+ <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Message shown when the user enters the wrong PIN code -->
<string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
diff --git a/core/tests/coretests/src/android/companion/virtual/OWNERS b/core/tests/coretests/src/android/companion/virtual/OWNERS
index 1a3e927..2e475a9 100644
--- a/core/tests/coretests/src/android/companion/virtual/OWNERS
+++ b/core/tests/coretests/src/android/companion/virtual/OWNERS
@@ -1,3 +1 @@
-set noparent
-
include /services/companion/java/com/android/server/companion/virtual/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/hardware/camera2/OWNERS b/core/tests/coretests/src/android/hardware/camera2/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/camera2/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java b/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java
new file mode 100644
index 0000000..a38c040
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.LensShadingMap;
+import android.util.Size;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link CameraMetadataNative} class. */
+public class CaptureMetadataNativeTest {
+
+ @Test
+ public void setLensShadingMap() {
+ final Size s = new Size(10, 10);
+ // 4 x rows x columns
+ final float[] elements = new float[400];
+ Arrays.fill(elements, 42);
+
+ final LensShadingMap lensShadingMap =
+ new LensShadingMap(elements, s.getHeight(), s.getWidth());
+ CameraMetadataNative captureResults = new CameraMetadataNative();
+ captureResults.set(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP, lensShadingMap);
+
+ final LensShadingMap output =
+ captureResults.get(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
+
+ assertThat(output).isEqualTo(lensShadingMap);
+ }
+}
diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp
index 335cea1..c74600b 100644
--- a/core/tests/nfctests/Android.bp
+++ b/core/tests/nfctests/Android.bp
@@ -27,6 +27,7 @@
"androidx.test.ext.junit",
"androidx.test.rules",
"mockito-target-minus-junit4",
+ "truth-prebuilt",
],
libs: [
"android.test.runner",
diff --git a/core/tests/nfctests/src/android/nfc/TechListParcelTest.java b/core/tests/nfctests/src/android/nfc/TechListParcelTest.java
new file mode 100644
index 0000000..a12bbbc
--- /dev/null
+++ b/core/tests/nfctests/src/android/nfc/TechListParcelTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.nfc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class TechListParcelTest {
+
+ private static final String[] TECH_LIST_1 = new String[] { "tech1.1", "tech1.2" };
+ private static final String[] TECH_LIST_2 = new String[] { "tech2.1" };
+ private static final String[] TECH_LIST_EMPTY = new String[] {};
+
+ @Test
+ public void testWriteParcel() {
+ TechListParcel techListParcel = new TechListParcel(TECH_LIST_1, TECH_LIST_2);
+
+ Parcel parcel = Parcel.obtain();
+ techListParcel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ TechListParcel actualTechList =
+ TechListParcel.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertThat(actualTechList.getTechLists().length).isEqualTo(2);
+ assertThat(Arrays.equals(actualTechList.getTechLists()[0], TECH_LIST_1)).isTrue();
+ assertThat(Arrays.equals(actualTechList.getTechLists()[1], TECH_LIST_2)).isTrue();
+ }
+
+ @Test
+ public void testWriteParcelArrayEmpty() {
+ TechListParcel techListParcel = new TechListParcel();
+
+ Parcel parcel = Parcel.obtain();
+ techListParcel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ TechListParcel actualTechList =
+ TechListParcel.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertThat(actualTechList.getTechLists().length).isEqualTo(0);
+ }
+
+ @Test
+ public void testWriteParcelElementEmpty() {
+ TechListParcel techListParcel = new TechListParcel(TECH_LIST_EMPTY);
+
+ Parcel parcel = Parcel.obtain();
+ techListParcel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ TechListParcel actualTechList =
+ TechListParcel.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertThat(actualTechList.getTechLists().length).isEqualTo(1);
+ assertThat(Arrays.equals(actualTechList.getTechLists()[0], TECH_LIST_EMPTY)).isTrue();
+ }
+
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8ca1607..ff42fb5 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -342,10 +342,6 @@
<permission name="android.permission.SET_WALLPAPER_COMPONENT" />
<permission name="android.permission.SET_WALLPAPER_DIM_AMOUNT" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
- <!-- Permission required for CTS test - TrustTestCases -->
- <permission name="android.permission.PROVIDE_TRUST_AGENT" />
- <permission name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
- <permission name="android.permission.TRUST_LISTENER" />
<!-- Permissions required for Incremental CTS tests -->
<permission name="com.android.permission.USE_INSTALLER_V2"/>
<permission name="android.permission.LOADER_USAGE_STATS"/>
diff --git a/data/keyboards/Vendor_054c_Product_0df2.kl b/data/keyboards/Vendor_054c_Product_0df2.kl
new file mode 100644
index 0000000..a47b310
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0df2.kl
@@ -0,0 +1,73 @@
+# 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.
+
+#
+# Sony Playstation(R) DualSense Edge Controller
+#
+
+# Only use this key layout if we have HID_PLAYSTATION!
+requires_kernel_config CONFIG_HID_PLAYSTATION
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share / "half-sun"
+key 0x13a BUTTON_SELECT
+# Options / three horizontal lines
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_0df2_fallback.kl b/data/keyboards/Vendor_054c_Product_0df2_fallback.kl
new file mode 100644
index 0000000..bfebb17
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0df2_fallback.kl
@@ -0,0 +1,75 @@
+# 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.
+
+#
+# Sony Playstation(R) DualSense Edge Controller
+#
+
+# Use this if HID_PLAYSTATION is not available
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 304 BUTTON_X
+# Cross
+key 305 BUTTON_A
+# Circle
+key 306 BUTTON_B
+# Triangle
+key 307 BUTTON_Y
+
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+
+# L2 axis
+axis 0x03 LTRIGGER
+# R2 axis
+axis 0x04 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# Left stick click
+key 314 BUTTON_THUMBL
+# Right stick click
+key 315 BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share / "half-sun"
+key 312 BUTTON_SELECT
+# Options / three horizontal lines
+key 313 BUTTON_START
+# PS key
+key 316 BUTTON_MODE
+
+# Touchpad press
+key 317 BUTTON_1
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 9947d34..c55a781 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -38,6 +38,7 @@
import java.security.Security;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
+import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
@@ -221,7 +222,14 @@
}
final byte[] x509PublicCert = metadata.certificate;
- PublicKey publicKey = AndroidKeyStoreSpi.toCertificate(x509PublicCert).getPublicKey();
+ final X509Certificate parsedX509Certificate =
+ AndroidKeyStoreSpi.toCertificate(x509PublicCert);
+ if (parsedX509Certificate == null) {
+ throw new UnrecoverableKeyException("Failed to parse the X.509 certificate containing"
+ + " the public key. This likely indicates a hardware problem.");
+ }
+
+ PublicKey publicKey = parsedX509Certificate.getPublicKey();
String jcaKeyAlgorithm = publicKey.getAlgorithm();
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index c022087..404d00a 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -214,6 +214,15 @@
path: "apex/java",
}
+java_api_contribution {
+ name: "framework-graphics-public-stubs",
+ api_surface: "public",
+ api_file: "api/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
+
// ------------------------
// APEX
// ------------------------
@@ -634,7 +643,7 @@
cc_defaults {
name: "hwui_test_defaults",
defaults: ["hwui_defaults"],
- test_suites: ["device-tests"],
+ test_suites: ["general-tests"],
header_libs: ["libandroid_headers_private"],
target: {
android: {
diff --git a/libs/hwui/AndroidTest.xml b/libs/hwui/AndroidTest.xml
index 381fb9f..911315f 100644
--- a/libs/hwui/AndroidTest.xml
+++ b/libs/hwui/AndroidTest.xml
@@ -16,22 +16,22 @@
<configuration description="Config for hwuimicro">
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
- <option name="push" value="hwui_unit_tests->/data/nativetest/hwui_unit_tests" />
- <option name="push" value="hwuimicro->/data/benchmarktest/hwuimicro" />
- <option name="push" value="hwuimacro->/data/benchmarktest/hwuimacro" />
+ <option name="push" value="hwui_unit_tests->/data/local/tmp/nativetest/hwui_unit_tests" />
+ <option name="push" value="hwuimicro->/data/local/tmp/benchmarktest/hwuimicro" />
+ <option name="push" value="hwuimacro->/data/local/tmp/benchmarktest/hwuimacro" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/nativetest" />
+ <option name="native-test-device-path" value="/data/local/tmp/nativetest" />
<option name="module-name" value="hwui_unit_tests" />
</test>
<test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
- <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+ <option name="native-benchmark-device-path" value="/data/local/tmp/benchmarktest" />
<option name="benchmark-module-name" value="hwuimicro" />
<option name="file-exclusion-filter-regex" value=".*\.config$" />
</test>
<test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
- <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+ <option name="native-benchmark-device-path" value="/data/local/tmp/benchmarktest" />
<option name="benchmark-module-name" value="hwuimacro" />
<option name="file-exclusion-filter-regex" value=".*\.config$" />
</test>
diff --git a/libs/hwui/TEST_MAPPING b/libs/hwui/TEST_MAPPING
index b1719a9..03682e8 100644
--- a/libs/hwui/TEST_MAPPING
+++ b/libs/hwui/TEST_MAPPING
@@ -5,6 +5,9 @@
},
{
"name": "CtsAccelerationTestCases"
+ },
+ {
+ "name": "hwui_unit_tests"
}
],
"imports": [
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index edd3e4e..fc84abb 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -32,7 +32,8 @@
return cacheUsage;
}
-RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
+// TOOD(258700630): fix this test and re-enable
+RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, DISABLED_trimMemory) {
int32_t width = DeviceInfo::get()->getWidth();
int32_t height = DeviceInfo::get()->getHeight();
GrDirectContext* grContext = renderThread.getGrContext();
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index 098b4cc..c2d23e6 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -14,17 +14,18 @@
* limitations under the License.
*/
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
-#include "protos/graphicsstats.pb.h"
-#include "service/GraphicsStatsService.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include "protos/graphicsstats.pb.h"
+#include "service/GraphicsStatsService.h"
+
using namespace android;
using namespace android::uirenderer;
@@ -49,12 +50,14 @@
// No code left untested
TEST(GraphicsStats, findRootPath) {
-#ifdef __LP64__
- std::string expected = "/data/nativetest64/hwui_unit_tests";
-#else
- std::string expected = "/data/nativetest/hwui_unit_tests";
-#endif
- EXPECT_EQ(expected, findRootPath());
+ // Different tools/infrastructure seem to push this to different locations. It shouldn't really
+ // matter where the binary is, so add new locations here as needed. This test still seems good
+ // as it's nice to understand the possibility space, and ensure findRootPath continues working
+ // as expected.
+ std::string acceptableLocations[] = {"/data/nativetest/hwui_unit_tests",
+ "/data/nativetest64/hwui_unit_tests",
+ "/data/local/tmp/nativetest/hwui_unit_tests/" ABI_STRING};
+ EXPECT_THAT(acceptableLocations, ::testing::Contains(findRootPath()));
}
TEST(GraphicsStats, saveLoad) {
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index ff1714d..a996700 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -60,6 +60,7 @@
":libincident_aidl",
"src/IncidentReportArgs.cpp",
],
+ min_sdk_version: "29",
}
cc_library_shared {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 399650d..85911a3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -8478,6 +8478,55 @@
}
}
+ /**
+ * Requests if the implementation supports controlling the latency modes
+ * over the Bluetooth A2DP or LE Audio links.
+ *
+ * @return true if supported, false otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean supportsBluetoothVariableLatency() {
+ try {
+ return getService().supportsBluetoothVariableLatency();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enables or disables the variable Bluetooth latency control mechanism in the
+ * audio framework and the audio HAL. This does not apply to the latency mode control
+ * on the spatializer output as this is a built-in feature.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void setBluetoothVariableLatencyEnabled(boolean enabled) {
+ try {
+ getService().setBluetoothVariableLatencyEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean isBluetoothVariableLatencyEnabled() {
+ try {
+ return getService().isBluetoothVariableLatencyEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final Object mMuteAwaitConnectionListenerLock = new Object();
@GuardedBy("mMuteAwaitConnectionListenerLock")
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 097bb41..474ccc9 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2428,4 +2428,30 @@
* Keep in sync with core/jni/android_media_DeviceCallback.h.
*/
final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;
+
+
+ /**
+ * Requests if the implementation supports controlling the latency modes
+ * over the Bluetooth A2DP or LE Audio links.
+ *
+ * @return true if supported, false otherwise
+ *
+ * @hide
+ */
+ public static native boolean supportsBluetoothVariableLatency();
+
+ /**
+ * Enables or disables the variable Bluetooth latency control mechanism in the
+ * audio framework and the audio HAL. This does not apply to the latency mode control
+ * on the spatializer output as this is a built-in feature.
+ *
+ * @hide
+ */
+ public static native int setBluetoothVariableLatencyEnabled(boolean enabled);
+
+ /**
+ * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
+ * @hide
+ */
+ public static native boolean isBluetoothVariableLatencyEnabled();
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index cfcd79a..9375a0d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -517,4 +517,16 @@
boolean handlesvolumeAdjustment);
AudioHalVersionInfo getHalVersion();
+
+ @EnforcePermission("MODIFY_AUDIO_ROUTING")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ boolean supportsBluetoothVariableLatency();
+
+ @EnforcePermission("MODIFY_AUDIO_ROUTING")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void setBluetoothVariableLatencyEnabled(boolean enabled);
+
+ @EnforcePermission("MODIFY_AUDIO_ROUTING")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ boolean isBluetoothVariableLatencyEnabled();
}
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index 2f1a36c..4957300 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -255,10 +255,10 @@
case ImageFormat.RAW_SENSOR:
case ImageFormat.RAW_PRIVATE: // round estimate, real size is unknown
case ImageFormat.DEPTH16:
- case ImageFormat.YCBCR_P010:
estimatedBytePerPixel = 2.0;
break;
case PixelFormat.RGB_888:
+ case ImageFormat.YCBCR_P010:
estimatedBytePerPixel = 3.0;
break;
case PixelFormat.RGBA_8888:
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 582a28e..015602e 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -21,11 +21,12 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IMediaCasService;
+import android.hardware.cas.Status;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
-import android.hardware.cas.V1_0.ICas;
-import android.hardware.cas.V1_0.IMediaCasService;
-import android.hardware.cas.V1_2.ICasListener;
-import android.hardware.cas.V1_2.Status;
import android.media.MediaCasException.*;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -39,6 +40,7 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.util.Singleton;
@@ -47,6 +49,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -114,9 +117,10 @@
*/
public final class MediaCas implements AutoCloseable {
private static final String TAG = "MediaCas";
- private ICas mICas;
- private android.hardware.cas.V1_1.ICas mICasV11;
- private android.hardware.cas.V1_2.ICas mICasV12;
+ private ICas mICas = null;
+ private android.hardware.cas.V1_0.ICas mICasHidl = null;
+ private android.hardware.cas.V1_1.ICas mICasHidl11 = null;
+ private android.hardware.cas.V1_2.ICas mICasHidl12 = null;
private EventListener mListener;
private HandlerThread mHandlerThread;
private EventHandler mEventHandler;
@@ -133,88 +137,84 @@
*
* @hide
*/
- @IntDef(prefix = "SCRAMBLING_MODE_",
- value = {SCRAMBLING_MODE_RESERVED, SCRAMBLING_MODE_DVB_CSA1, SCRAMBLING_MODE_DVB_CSA2,
- SCRAMBLING_MODE_DVB_CSA3_STANDARD,
- SCRAMBLING_MODE_DVB_CSA3_MINIMAL, SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
- SCRAMBLING_MODE_DVB_CISSA_V1, SCRAMBLING_MODE_DVB_IDSA,
- SCRAMBLING_MODE_MULTI2, SCRAMBLING_MODE_AES128, SCRAMBLING_MODE_AES_ECB,
- SCRAMBLING_MODE_AES_SCTE52, SCRAMBLING_MODE_TDES_ECB, SCRAMBLING_MODE_TDES_SCTE52})
+ @IntDef(
+ prefix = "SCRAMBLING_MODE_",
+ value = {
+ SCRAMBLING_MODE_RESERVED,
+ SCRAMBLING_MODE_DVB_CSA1,
+ SCRAMBLING_MODE_DVB_CSA2,
+ SCRAMBLING_MODE_DVB_CSA3_STANDARD,
+ SCRAMBLING_MODE_DVB_CSA3_MINIMAL,
+ SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
+ SCRAMBLING_MODE_DVB_CISSA_V1,
+ SCRAMBLING_MODE_DVB_IDSA,
+ SCRAMBLING_MODE_MULTI2,
+ SCRAMBLING_MODE_AES128,
+ SCRAMBLING_MODE_AES_CBC,
+ SCRAMBLING_MODE_AES_ECB,
+ SCRAMBLING_MODE_AES_SCTE52,
+ SCRAMBLING_MODE_TDES_ECB,
+ SCRAMBLING_MODE_TDES_SCTE52
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ScramblingMode {}
- /**
- * DVB (Digital Video Broadcasting) reserved mode.
- */
- public static final int SCRAMBLING_MODE_RESERVED =
- android.hardware.cas.V1_2.ScramblingMode.RESERVED;
- /**
- * DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1.
- */
- public static final int SCRAMBLING_MODE_DVB_CSA1 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA1;
- /**
- * DVB CSA 2.
- */
- public static final int SCRAMBLING_MODE_DVB_CSA2 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA2;
- /**
- * DVB CSA 3 in standard mode.
- */
+ /** DVB (Digital Video Broadcasting) reserved mode. */
+ public static final int SCRAMBLING_MODE_RESERVED = android.hardware.cas.ScramblingMode.RESERVED;
+
+ /** DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1. */
+ public static final int SCRAMBLING_MODE_DVB_CSA1 = android.hardware.cas.ScramblingMode.DVB_CSA1;
+
+ /** DVB CSA 2. */
+ public static final int SCRAMBLING_MODE_DVB_CSA2 = android.hardware.cas.ScramblingMode.DVB_CSA2;
+
+ /** DVB CSA 3 in standard mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_STANDARD;
- /**
- * DVB CSA 3 in minimally enhanced mode.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_STANDARD;
+
+ /** DVB CSA 3 in minimally enhanced mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_MINIMAL;
- /**
- * DVB CSA 3 in fully enhanced mode.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_MINIMAL;
+
+ /** DVB CSA 3 in fully enhanced mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_ENHANCE;
- /**
- * DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_ENHANCE;
+
+ /** DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1. */
public static final int SCRAMBLING_MODE_DVB_CISSA_V1 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CISSA_V1;
- /**
- * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
- */
- public static final int SCRAMBLING_MODE_DVB_IDSA =
- android.hardware.cas.V1_2.ScramblingMode.DVB_IDSA;
- /**
- * A symmetric key algorithm.
- */
- public static final int SCRAMBLING_MODE_MULTI2 =
- android.hardware.cas.V1_2.ScramblingMode.MULTI2;
- /**
- * Advanced Encryption System (AES) 128-bit Encryption mode.
- */
- public static final int SCRAMBLING_MODE_AES128 =
- android.hardware.cas.V1_2.ScramblingMode.AES128;
- /**
- * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
- */
- public static final int SCRAMBLING_MODE_AES_ECB =
- android.hardware.cas.V1_2.ScramblingMode.AES_ECB;
+ android.hardware.cas.ScramblingMode.DVB_CISSA_V1;
+
+ /** ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). */
+ public static final int SCRAMBLING_MODE_DVB_IDSA = android.hardware.cas.ScramblingMode.DVB_IDSA;
+
+ /** A symmetric key algorithm. */
+ public static final int SCRAMBLING_MODE_MULTI2 = android.hardware.cas.ScramblingMode.MULTI2;
+
+ /** Advanced Encryption System (AES) 128-bit Encryption mode. */
+ public static final int SCRAMBLING_MODE_AES128 = android.hardware.cas.ScramblingMode.AES128;
+
+ /** Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode. */
+ public static final int SCRAMBLING_MODE_AES_CBC = android.hardware.cas.ScramblingMode.AES_CBC;
+
+ /** Advanced Encryption System (AES) Electronic Code Book (ECB) mode. */
+ public static final int SCRAMBLING_MODE_AES_ECB = android.hardware.cas.ScramblingMode.AES_ECB;
+
/**
* Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52
* mode.
*/
public static final int SCRAMBLING_MODE_AES_SCTE52 =
- android.hardware.cas.V1_2.ScramblingMode.AES_SCTE52;
- /**
- * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
- */
- public static final int SCRAMBLING_MODE_TDES_ECB =
- android.hardware.cas.V1_2.ScramblingMode.TDES_ECB;
+ android.hardware.cas.ScramblingMode.AES_SCTE52;
+
+ /** Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. */
+ public static final int SCRAMBLING_MODE_TDES_ECB = android.hardware.cas.ScramblingMode.TDES_ECB;
+
/**
* Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE)
* 52 mode.
*/
public static final int SCRAMBLING_MODE_TDES_SCTE52 =
- android.hardware.cas.V1_2.ScramblingMode.TDES_SCTE52;
+ android.hardware.cas.ScramblingMode.TDES_SCTE52;
/**
* Usages used to open cas sessions.
@@ -226,25 +226,21 @@
SESSION_USAGE_TIMESHIFT})
@Retention(RetentionPolicy.SOURCE)
public @interface SessionUsage {}
- /**
- * Cas session is used to descramble live streams.
- */
- public static final int SESSION_USAGE_LIVE = android.hardware.cas.V1_2.SessionIntent.LIVE;
- /**
- * Cas session is used to descramble recoreded streams.
- */
- public static final int SESSION_USAGE_PLAYBACK =
- android.hardware.cas.V1_2.SessionIntent.PLAYBACK;
- /**
- * Cas session is used to descramble live streams and encrypt local recorded content
- */
- public static final int SESSION_USAGE_RECORD = android.hardware.cas.V1_2.SessionIntent.RECORD;
+
+ /** Cas session is used to descramble live streams. */
+ public static final int SESSION_USAGE_LIVE = android.hardware.cas.SessionIntent.LIVE;
+
+ /** Cas session is used to descramble recoreded streams. */
+ public static final int SESSION_USAGE_PLAYBACK = android.hardware.cas.SessionIntent.PLAYBACK;
+
+ /** Cas session is used to descramble live streams and encrypt local recorded content */
+ public static final int SESSION_USAGE_RECORD = android.hardware.cas.SessionIntent.RECORD;
+
/**
* Cas session is used to descramble live streams , encrypt local recorded content and playback
* local encrypted content.
*/
- public static final int SESSION_USAGE_TIMESHIFT =
- android.hardware.cas.V1_2.SessionIntent.TIMESHIFT;
+ public static final int SESSION_USAGE_TIMESHIFT = android.hardware.cas.SessionIntent.TIMESHIFT;
/**
* Plugin status events sent from cas system.
@@ -261,63 +257,90 @@
* physical CAS modules.
*/
public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED =
- android.hardware.cas.V1_2.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
- /**
- * The event to indicate that the number of CAS system's session is changed.
- */
+ android.hardware.cas.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
+
+ /** The event to indicate that the number of CAS system's session is changed. */
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
- android.hardware.cas.V1_2.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
+ android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
- private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
- @Override
- protected IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get cas@1.2 service");
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
- if (serviceV12 != null) {
- return serviceV12;
- }
- } catch (Exception eV1_2) {
- Log.d(TAG, "Failed to get cas@1.2 service");
- }
-
- try {
- Log.d(TAG, "Trying to get cas@1.1 service");
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
- if (serviceV11 != null) {
- return serviceV11;
+ private static final Singleton<IMediaCasService> sService =
+ new Singleton<IMediaCasService>() {
+ @Override
+ protected IMediaCasService create() {
+ try {
+ Log.d(TAG, "Trying to get AIDL service");
+ IMediaCasService serviceAidl =
+ IMediaCasService.Stub.asInterface(
+ ServiceManager.getService(
+ IMediaCasService.DESCRIPTOR + "/default"));
+ if (serviceAidl != null) {
+ return serviceAidl;
+ }
+ } catch (Exception eAidl) {
+ Log.d(TAG, "Failed to get cas AIDL service");
}
- } catch (Exception eV1_1) {
- Log.d(TAG, "Failed to get cas@1.1 service");
- }
+ return null;
+ }
+ };
- try {
- Log.d(TAG, "Trying to get cas@1.0 service");
- return IMediaCasService.getService(true /*wait*/);
- } catch (Exception eV1_0) {
- Log.d(TAG, "Failed to get cas@1.0 service");
- }
+ private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
+ new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
+ @Override
+ protected android.hardware.cas.V1_0.IMediaCasService create() {
+ try {
+ Log.d(TAG, "Trying to get cas@1.2 service");
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.getService(
+ true /*wait*/);
+ if (serviceV12 != null) {
+ return serviceV12;
+ }
+ } catch (Exception eV1_2) {
+ Log.d(TAG, "Failed to get cas@1.2 service");
+ }
- return null;
- }
- };
+ try {
+ Log.d(TAG, "Trying to get cas@1.1 service");
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.getService(
+ true /*wait*/);
+ if (serviceV11 != null) {
+ return serviceV11;
+ }
+ } catch (Exception eV1_1) {
+ Log.d(TAG, "Failed to get cas@1.1 service");
+ }
+
+ try {
+ Log.d(TAG, "Trying to get cas@1.0 service");
+ return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
+ } catch (Exception eV1_0) {
+ Log.d(TAG, "Failed to get cas@1.0 service");
+ }
+
+ return null;
+ }
+ };
static IMediaCasService getService() {
return sService.get();
}
+ static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
+ return sServiceHidl.get();
+ }
+
private void validateInternalStates() {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new IllegalStateException();
}
}
private void cleanupAndRethrowIllegalState() {
mICas = null;
- mICasV11 = null;
- mICasV12 = null;
+ mICasHidl = null;
+ mICasHidl11 = null;
+ mICasHidl12 = null;
throw new IllegalStateException();
}
@@ -341,7 +364,7 @@
toBytes((ArrayList<Byte>) msg.obj));
} else if (msg.what == MSG_CAS_SESSION_EVENT) {
Bundle bundle = msg.getData();
- ArrayList<Byte> sessionId = toByteArray(bundle.getByteArray(SESSION_KEY));
+ byte[] sessionId = bundle.getByteArray(SESSION_KEY);
mListener.onSessionEvent(MediaCas.this,
createFromSessionId(sessionId), msg.arg1, msg.arg2,
bundle.getByteArray(DATA_KEY));
@@ -357,40 +380,94 @@
}
}
- private final ICasListener.Stub mBinder = new ICasListener.Stub() {
- @Override
- public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
- throws RemoteException {
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- EventHandler.MSG_CAS_EVENT, event, arg, data));
- }
- }
- @Override
- public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
- int event, int arg, @Nullable ArrayList<Byte> data)
- throws RemoteException {
- if (mEventHandler != null) {
- Message msg = mEventHandler.obtainMessage();
- msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
- msg.arg1 = event;
- msg.arg2 = arg;
- Bundle bundle = new Bundle();
- bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
- bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
- msg.setData(bundle);
- mEventHandler.sendMessage(msg);
- }
- }
- @Override
- public void onStatusUpdate(byte status, int arg)
- throws RemoteException {
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
- }
- }
- };
+ private final ICasListener.Stub mBinder =
+ new ICasListener.Stub() {
+ @Override
+ public void onEvent(int event, int arg, byte[] data) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_EVENT, event, arg, data));
+ }
+ }
+
+ @Override
+ public void onSessionEvent(byte[] sessionId, int event, int arg, byte[] data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ Message msg = mEventHandler.obtainMessage();
+ msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+ msg.arg1 = event;
+ msg.arg2 = arg;
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(EventHandler.SESSION_KEY, sessionId);
+ bundle.putByteArray(EventHandler.DATA_KEY, data);
+ msg.setData(bundle);
+ mEventHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onStatusUpdate(byte status, int arg) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+ }
+ }
+
+ @Override
+ public synchronized String getInterfaceHash() throws android.os.RemoteException {
+ return ICasListener.Stub.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() throws android.os.RemoteException {
+ return ICasListener.Stub.VERSION;
+ }
+ };
+
+ private final android.hardware.cas.V1_2.ICasListener.Stub mBinderHidl =
+ new android.hardware.cas.V1_2.ICasListener.Stub() {
+ @Override
+ public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_EVENT, event, arg, data));
+ }
+ }
+
+ @Override
+ public void onSessionEvent(
+ @NonNull ArrayList<Byte> sessionId,
+ int event,
+ int arg,
+ @Nullable ArrayList<Byte> data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ Message msg = mEventHandler.obtainMessage();
+ msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+ msg.arg1 = event;
+ msg.arg2 = arg;
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
+ bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
+ msg.setData(bundle);
+ mEventHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onStatusUpdate(byte status, int arg) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+ }
+ }
+ };
private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
new TunerResourceManager.ResourcesReclaimListener() {
@@ -422,6 +499,11 @@
mName = null;
}
+ PluginDescriptor(@NonNull AidlCasPluginDescriptor descriptor) {
+ mCASystemId = descriptor.caSystemId;
+ mName = descriptor.name;
+ }
+
PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) {
mCASystemId = descriptor.caSystemId;
mName = descriptor.name;
@@ -467,19 +549,20 @@
}
return data;
}
+
/**
* Class for an open session with the CA system.
*/
public final class Session implements AutoCloseable {
- final ArrayList<Byte> mSessionId;
+ final byte[] mSessionId;
boolean mIsClosed = false;
- Session(@NonNull ArrayList<Byte> sessionId) {
- mSessionId = new ArrayList<Byte>(sessionId);
+ Session(@NonNull byte[] sessionId) {
+ mSessionId = sessionId;
}
private void validateSessionInternalStates() {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new IllegalStateException();
}
if (mIsClosed) {
@@ -496,7 +579,7 @@
*/
public boolean equals(Object obj) {
if (obj instanceof Session) {
- return mSessionId.equals(((Session) obj).mSessionId);
+ return Arrays.equals(mSessionId, ((Session) obj).mSessionId);
}
return false;
}
@@ -515,8 +598,13 @@
validateSessionInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length)));
+ if (mICas != null) {
+ mICas.setSessionPrivateData(mSessionId, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.setSessionPrivateData(
+ toByteArray(mSessionId), toByteArray(data, 0, data.length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -539,8 +627,13 @@
validateSessionInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.processEcm(mSessionId, toByteArray(data, offset, length)));
+ if (mICas != null) {
+ mICas.processEcm(mSessionId, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.processEcm(
+ toByteArray(mSessionId), toByteArray(data, offset, length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -576,15 +669,23 @@
public void sendSessionEvent(int event, int arg, @Nullable byte[] data)
throws MediaCasException {
validateSessionInternalStates();
+ if (mICas != null) {
+ try {
+ mICas.sendSessionEvent(mSessionId, event, arg, data);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
- if (mICasV11 == null) {
+ if (mICasHidl11 == null) {
Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
throw new UnsupportedCasException("Send Session Event is not supported");
}
try {
MediaCasException.throwExceptionIfNeeded(
- mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
+ mICasHidl11.sendSessionEvent(
+ toByteArray(mSessionId), event, arg, toByteArray(data)));
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -600,7 +701,7 @@
@NonNull
public byte[] getSessionId() {
validateSessionInternalStates();
- return toBytes(mSessionId);
+ return mSessionId;
}
/**
@@ -613,8 +714,12 @@
public void close() {
validateSessionInternalStates();
try {
- MediaCasStateException.throwExceptionIfNeeded(
- mICas.closeSession(mSessionId));
+ if (mICas != null) {
+ mICas.closeSession(mSessionId);
+ } else {
+ MediaCasStateException.throwExceptionIfNeeded(
+ mICasHidl.closeSession(toByteArray(mSessionId)));
+ }
mIsClosed = true;
removeSessionFromResourceMap(this);
} catch (RemoteException e) {
@@ -623,8 +728,8 @@
}
}
- Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) {
- if (sessionId == null || sessionId.size() == 0) {
+ Session createFromSessionId(byte[] sessionId) {
+ if (sessionId == null || sessionId.length == 0) {
return null;
}
return new Session(sessionId);
@@ -638,12 +743,20 @@
* @return Whether the specified CA system is supported on this device.
*/
public static boolean isSystemIdSupported(int CA_system_id) {
- IMediaCasService service = getService();
-
+ IMediaCasService service = sService.get();
if (service != null) {
try {
return service.isSystemIdSupported(CA_system_id);
} catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ if (serviceHidl != null) {
+ try {
+ return serviceHidl.isSystemIdSupported(CA_system_id);
+ } catch (RemoteException e) {
}
}
return false;
@@ -655,12 +768,26 @@
* @return an array of descriptors for the available CA plugins.
*/
public static PluginDescriptor[] enumeratePlugins() {
- IMediaCasService service = getService();
-
+ IMediaCasService service = sService.get();
if (service != null) {
try {
- ArrayList<HidlCasPluginDescriptor> descriptors =
- service.enumeratePlugins();
+ AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
+ if (descriptors.length == 0) {
+ return null;
+ }
+ PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
+ for (int i = 0; i < results.length; i++) {
+ results[i] = new PluginDescriptor(descriptors[i]);
+ }
+ return results;
+ } catch (RemoteException e) {
+ }
+ }
+
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ if (serviceHidl != null) {
+ try {
+ ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
if (descriptors.size() == 0) {
return null;
}
@@ -680,29 +807,40 @@
mCasSystemId = casSystemId;
mUserId = Process.myUid();
IMediaCasService service = getService();
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
- if (serviceV12 == null) {
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
- if (serviceV11 == null) {
- Log.d(TAG, "Used cas@1_0 interface to create plugin");
- mICas = service.createPlugin(casSystemId, mBinder);
- } else {
- Log.d(TAG, "Used cas@1.1 interface to create plugin");
- mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
- }
+ if (service != null) {
+ Log.d(TAG, "Use CAS AIDL interface to create plugin");
+ mICas = service.createPlugin(casSystemId, mBinder);
} else {
- Log.d(TAG, "Used cas@1.2 interface to create plugin");
- mICas = mICasV11 = mICasV12 =
- android.hardware.cas.V1_2.ICas
- .castFrom(serviceV12.createPluginExt(casSystemId, mBinder));
+ android.hardware.cas.V1_0.IMediaCasService serviceV10 = getServiceHidl();
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.castFrom(serviceV10);
+ if (serviceV12 == null) {
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.castFrom(serviceV10);
+ if (serviceV11 == null) {
+ Log.d(TAG, "Used cas@1_0 interface to create plugin");
+ mICasHidl = serviceV10.createPlugin(casSystemId, mBinderHidl);
+ } else {
+ Log.d(TAG, "Used cas@1.1 interface to create plugin");
+ mICasHidl =
+ mICasHidl11 = serviceV11.createPluginExt(casSystemId, mBinderHidl);
+ }
+ } else {
+ Log.d(TAG, "Used cas@1.2 interface to create plugin");
+ mICasHidl =
+ mICasHidl11 =
+ mICasHidl12 =
+ android.hardware.cas.V1_2.ICas.castFrom(
+ serviceV12.createPluginExt(
+ casSystemId, mBinderHidl));
+ }
}
} catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e);
mICas = null;
+ mICasHidl = null;
} finally {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new UnsupportedCasException(
"Unsupported casSystemId " + casSystemId);
}
@@ -783,9 +921,22 @@
}
IHwBinder getBinder() {
+ if (mICas != null) {
+ return null; // Return IHwBinder only for HIDL
+ }
+
validateInternalStates();
- return mICas.asBinder();
+ return mICasHidl.asBinder();
+ }
+
+ /**
+ * Check if the HAL is an AIDL implementation
+ *
+ * @hide
+ */
+ public boolean isAidlHal() {
+ return mICas != null;
}
/**
@@ -886,8 +1037,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.setPrivateData(toByteArray(data, 0, data.length)));
+ if (mICas != null) {
+ mICas.setPrivateData(data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.setPrivateData(toByteArray(data, 0, data.length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -899,7 +1054,7 @@
@Override
public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status;
- mSession = createFromSessionId(sessionId);
+ mSession = createFromSessionId(toBytes(sessionId));
}
}
@@ -912,7 +1067,7 @@
@Override
public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status;
- mSession = createFromSessionId(sessionId);
+ mSession = createFromSessionId(toBytes(sessionId));
}
}
@@ -971,15 +1126,19 @@
int sessionResourceHandle = getSessionResourceHandle();
try {
- OpenSessionCallback cb = new OpenSessionCallback();
- mICas.openSession(cb);
- MediaCasException.throwExceptionIfNeeded(cb.mStatus);
- addSessionToResourceMap(cb.mSession, sessionResourceHandle);
- Log.d(TAG, "Write Stats Log for succeed to Open Session.");
- FrameworkStatsLog
- .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ if (mICasHidl != null) {
+ OpenSessionCallback cb = new OpenSessionCallback();
+ mICasHidl.openSession(cb);
+ MediaCasException.throwExceptionIfNeeded(cb.mStatus);
+ addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+ mUserId,
+ mCasSystemId,
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
- return cb.mSession;
+ return cb.mSession;
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1012,14 +1171,30 @@
throws MediaCasException {
int sessionResourceHandle = getSessionResourceHandle();
- if (mICasV12 == null) {
+ if (mICas != null) {
+ try {
+ byte[] sessionId = mICas.openSession(sessionUsage, scramblingMode);
+ Session session = createFromSessionId(sessionId);
+ addSessionToResourceMap(session, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+ mUserId,
+ mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
+ return session;
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+ if (mICasHidl12 == null) {
Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
throw new UnsupportedCasException("Open Session with scrambling mode is not supported");
}
try {
OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
- mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
+ mICasHidl12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
Log.d(TAG, "Write Stats Log for succeed to Open Session.");
@@ -1053,8 +1228,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.processEmm(toByteArray(data, offset, length)));
+ if (mICas != null) {
+ mICas.processEmm(Arrays.copyOfRange(data, offset, length));
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.processEmm(toByteArray(data, offset, length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1092,8 +1271,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.sendEvent(event, arg, toByteArray(data)));
+ if (mICas != null) {
+ mICas.sendEvent(event, arg, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.sendEvent(event, arg, toByteArray(data)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1114,8 +1297,11 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.provision(provisionString));
+ if (mICas != null) {
+ mICas.provision(provisionString);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(mICasHidl.provision(provisionString));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1136,8 +1322,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.refreshEntitlements(refreshType, toByteArray(refreshData)));
+ if (mICas != null) {
+ mICas.refreshEntitlements(refreshType, refreshData);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.refreshEntitlements(refreshType, toByteArray(refreshData)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1163,6 +1353,13 @@
} finally {
mICas = null;
}
+ } else if (mICasHidl != null) {
+ try {
+ mICasHidl.release();
+ } catch (RemoteException e) {
+ } finally {
+ mICasHidl = mICasHidl11 = mICasHidl12 = null;
+ }
}
if (mTunerResourceManager != null) {
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 99bd254..b4bdf93d 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -17,14 +17,26 @@
package android.media;
import android.annotation.NonNull;
-import android.hardware.cas.V1_0.*;
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.IDescrambler;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+import android.hardware.cas.V1_0.IDescramblerBase;
+import android.hardware.common.Ashmem;
+import android.hardware.common.NativeHandle;
import android.media.MediaCasException.UnsupportedCasException;
import android.os.IHwBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
import android.util.Log;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
/**
* MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
@@ -39,7 +51,198 @@
*/
public final class MediaDescrambler implements AutoCloseable {
private static final String TAG = "MediaDescrambler";
- private IDescramblerBase mIDescrambler;
+ private DescramblerWrapper mIDescrambler;
+
+ private interface DescramblerWrapper {
+
+ IHwBinder asBinder();
+
+ int descramble(
+ @NonNull ByteBuffer srcBuf,
+ @NonNull ByteBuffer dstBuf,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException;
+
+ boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException;
+
+ void setMediaCasSession(byte[] sessionId) throws RemoteException;
+
+ void release() throws RemoteException;
+ }
+ ;
+
+ private long getSubsampleInfo(
+ int numSubSamples,
+ int[] numBytesOfClearData,
+ int[] numBytesOfEncryptedData,
+ SubSample[] subSamples) {
+ long totalSize = 0;
+
+ for (int i = 0; i < numSubSamples; i++) {
+ totalSize += numBytesOfClearData[i];
+ subSamples[i].numBytesOfClearData = numBytesOfClearData[i];
+ totalSize += numBytesOfEncryptedData[i];
+ subSamples[i].numBytesOfEncryptedData = numBytesOfEncryptedData[i];
+ }
+ return totalSize;
+ }
+
+ private ParcelFileDescriptor createSharedMemory(ByteBuffer buffer, String name)
+ throws RemoteException {
+ byte[] source = buffer.array();
+ if (source.length == 0) {
+ return null;
+ }
+ ParcelFileDescriptor fd = null;
+ try {
+ SharedMemory ashmem = SharedMemory.create(name == null ? "" : name, source.length);
+ ByteBuffer ptr = ashmem.mapReadWrite();
+ ptr.put(buffer);
+ ashmem.unmap(ptr);
+ fd = ashmem.getFdDup();
+ return fd;
+ } catch (ErrnoException | IOException e) {
+ throw new RemoteException(e);
+ }
+ }
+
+ private class AidlDescrambler implements DescramblerWrapper {
+
+ IDescrambler mAidlDescrambler;
+
+ AidlDescrambler(IDescrambler aidlDescrambler) {
+ mAidlDescrambler = aidlDescrambler;
+ }
+
+ @Override
+ public IHwBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public int descramble(
+ @NonNull ByteBuffer src,
+ @NonNull ByteBuffer dst,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException {
+ SubSample[] subSamples = new SubSample[cryptoInfo.numSubSamples];
+ long totalLength =
+ getSubsampleInfo(
+ cryptoInfo.numSubSamples,
+ cryptoInfo.numBytesOfClearData,
+ cryptoInfo.numBytesOfEncryptedData,
+ subSamples);
+ SharedBuffer srcBuffer = new SharedBuffer();
+ DestinationBuffer dstBuffer;
+ srcBuffer.heapBase = new Ashmem();
+ srcBuffer.heapBase.fd = createSharedMemory(src, "Descrambler Source Buffer");
+ srcBuffer.heapBase.size = src.array().length;
+ if (dst == null) {
+ dstBuffer = DestinationBuffer.nonsecureMemory(srcBuffer);
+ } else {
+ ParcelFileDescriptor pfd =
+ createSharedMemory(dst, "Descrambler Destination Buffer");
+ NativeHandle nh = new NativeHandle();
+ nh.fds = new ParcelFileDescriptor[] {pfd};
+ nh.ints = new int[] {1}; // Mark 1 since source buffer also uses it?
+ dstBuffer = DestinationBuffer.secureMemory(nh);
+ }
+ @ScramblingControl int control = cryptoInfo.key[0];
+
+ return mAidlDescrambler.descramble(
+ (byte) control,
+ subSamples,
+ srcBuffer,
+ src.position(),
+ dstBuffer,
+ dst.position());
+ }
+
+ @Override
+ public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+ return mAidlDescrambler.requiresSecureDecoderComponent(mime);
+ }
+
+ @Override
+ public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+ mAidlDescrambler.setMediaCasSession(sessionId);
+ }
+
+ @Override
+ public void release() throws RemoteException {
+ mAidlDescrambler.release();
+ }
+ }
+
+ private class HidlDescrambler implements DescramblerWrapper {
+
+ IDescramblerBase mHidlDescrambler;
+
+ HidlDescrambler(IDescramblerBase hidlDescrambler) {
+ mHidlDescrambler = hidlDescrambler;
+ native_setup(hidlDescrambler.asBinder());
+ }
+
+ @Override
+ public IHwBinder asBinder() {
+ return mHidlDescrambler.asBinder();
+ }
+
+ @Override
+ public int descramble(
+ @NonNull ByteBuffer srcBuf,
+ @NonNull ByteBuffer dstBuf,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException {
+
+ try {
+ return native_descramble(
+ cryptoInfo.key[0],
+ cryptoInfo.key[1],
+ cryptoInfo.numSubSamples,
+ cryptoInfo.numBytesOfClearData,
+ cryptoInfo.numBytesOfEncryptedData,
+ srcBuf,
+ srcBuf.position(),
+ srcBuf.limit(),
+ dstBuf,
+ dstBuf.position(),
+ dstBuf.limit());
+ } catch (ServiceSpecificException e) {
+ MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+ return mHidlDescrambler.requiresSecureDecoderComponent(mime);
+ }
+
+ @Override
+ public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+ ArrayList<Byte> byteArray = new ArrayList<>();
+
+ if (sessionId != null) {
+ int length = sessionId.length;
+ byteArray = new ArrayList<Byte>(length);
+ for (int i = 0; i < length; i++) {
+ byteArray.add(Byte.valueOf(sessionId[i]));
+ }
+ }
+
+ MediaCasStateException.throwExceptionIfNeeded(
+ mHidlDescrambler.setMediaCasSession(byteArray));
+ }
+
+ @Override
+ public void release() throws RemoteException {
+ mHidlDescrambler.release();
+ native_release();
+ }
+ }
private final void validateInternalStates() {
if (mIDescrambler == null) {
@@ -61,7 +264,14 @@
*/
public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
try {
- mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id);
+ if (MediaCas.getService() != null) {
+ mIDescrambler =
+ new AidlDescrambler(MediaCas.getService().createDescrambler(CA_system_id));
+ } else if (MediaCas.getServiceHidl() != null) {
+ mIDescrambler =
+ new HidlDescrambler(
+ MediaCas.getServiceHidl().createDescrambler(CA_system_id));
+ }
} catch(Exception e) {
Log.e(TAG, "Failed to create descrambler: " + e);
mIDescrambler = null;
@@ -70,7 +280,6 @@
throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
}
}
- native_setup(mIDescrambler.asBinder());
}
IHwBinder getBinder() {
@@ -117,8 +326,7 @@
validateInternalStates();
try {
- MediaCasStateException.throwExceptionIfNeeded(
- mIDescrambler.setMediaCasSession(session.mSessionId));
+ mIDescrambler.setMediaCasSession(session.mSessionId);
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -126,27 +334,31 @@
/**
* Scramble control value indicating that the samples are not scrambled.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0;
+ public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = (byte) ScramblingControl.UNSCRAMBLED;
/**
* Scramble control value reserved and shouldn't be used currently.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_RESERVED = 1;
+ public static final byte SCRAMBLE_CONTROL_RESERVED = (byte) ScramblingControl.RESERVED;
/**
* Scramble control value indicating that the even key is used.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2;
+ public static final byte SCRAMBLE_CONTROL_EVEN_KEY = (byte) ScramblingControl.EVENKEY;
/**
* Scramble control value indicating that the odd key is used.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3;
+ public static final byte SCRAMBLE_CONTROL_ODD_KEY = (byte) ScramblingControl.ODDKEY;
/**
* Scramble flag for a hint indicating that the descrambling request is for
@@ -207,14 +419,7 @@
}
try {
- return native_descramble(
- cryptoInfo.key[0],
- cryptoInfo.key[1],
- cryptoInfo.numSubSamples,
- cryptoInfo.numBytesOfClearData,
- cryptoInfo.numBytesOfEncryptedData,
- srcBuf, srcBuf.position(), srcBuf.limit(),
- dstBuf, dstBuf.position(), dstBuf.limit());
+ return mIDescrambler.descramble(srcBuf, dstBuf, cryptoInfo);
} catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
} catch (RemoteException e) {
@@ -233,7 +438,6 @@
mIDescrambler = null;
}
}
- native_release();
}
@Override
@@ -256,4 +460,4 @@
}
private long mNativeContext;
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index dab188e..b11a810 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -36,7 +36,6 @@
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -325,14 +324,6 @@
}
}
- private ArrayList<Byte> toByteArray(@NonNull byte[] data) {
- ArrayList<Byte> byteArray = new ArrayList<Byte>(data.length);
- for (int i = 0; i < data.length; i++) {
- byteArray.add(i, Byte.valueOf(data[i]));
- }
- return byteArray;
- }
-
/**
* Retrieves the information about the conditional access system used to scramble
* a track.
@@ -357,7 +348,7 @@
buf.rewind();
final byte[] sessionId = new byte[buf.remaining()];
buf.get(sessionId);
- session = mMediaCas.createFromSessionId(toByteArray(sessionId));
+ session = mMediaCas.createFromSessionId(sessionId);
}
return new CasInfo(systemId, session, privateData);
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index e60d537..667a9ae 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -946,6 +946,10 @@
id = generateInputId(componentName, mTvInputHardwareInfo);
type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
isHardwareInput = true;
+ if (mTvInputHardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
+ mHdmiDeviceInfo = HdmiDeviceInfo.hardwarePort(
+ HdmiDeviceInfo.PATH_INVALID, mTvInputHardwareInfo.getHdmiPortId());
+ }
} else {
id = generateInputId(componentName);
type = TYPE_TUNER;
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d8705a7..5b0c2a2 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -2432,13 +2432,12 @@
throwExceptionAsNecessary(env, BAD_VALUE);
return;
}
- NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
- if (cryptoInfoObj == nullptr) {
- return NativeCryptoInfo{size};
- } else {
- return NativeCryptoInfo{env, cryptoInfoObj};
- }
- }();
+ auto cryptoInfo =
+ cryptoInfoObj ? NativeCryptoInfo{size} : NativeCryptoInfo{env, cryptoInfoObj};
+ if (env->ExceptionCheck()) {
+ // Creation of cryptoInfo failed. Let the exception bubble up.
+ return;
+ }
err = codec->queueEncryptedLinearBlock(
index,
memory,
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 4aa5bbf..a386923 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -1,9 +1,9 @@
LIBANDROID {
global:
- AActivityManager_addUidImportanceListener; # apex # introduced=31
- AActivityManager_removeUidImportanceListener; # apex # introduced=31
- AActivityManager_isUidActive; # apex # introduced=31
- AActivityManager_getUidImportance; # apex # introduced=31
+ AActivityManager_addUidImportanceListener; # systemapi # introduced=31
+ AActivityManager_removeUidImportanceListener; # systemapi # introduced=31
+ AActivityManager_isUidActive; # systemapi # introduced=31
+ AActivityManager_getUidImportance; # systemapi # introduced=31
AAssetDir_close;
AAssetDir_getNextFileName;
AAssetDir_rewind;
diff --git a/omapi/OWNERS b/omapi/OWNERS
index 5682fd3..1dce1e0 100644
--- a/omapi/OWNERS
+++ b/omapi/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 456592
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
jackcwyu@google.com
diff --git a/omapi/java/android/se/OWNERS b/omapi/java/android/se/OWNERS
index 5682fd3..1dce1e0 100644
--- a/omapi/java/android/se/OWNERS
+++ b/omapi/java/android/se/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 456592
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
jackcwyu@google.com
diff --git a/omapi/java/android/se/omapi/OWNERS b/omapi/java/android/se/omapi/OWNERS
index 5682fd3..1dce1e0 100644
--- a/omapi/java/android/se/omapi/OWNERS
+++ b/omapi/java/android/se/omapi/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 456592
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
alisher@google.com
jackcwyu@google.com
diff --git a/opengl/java/android/opengl/Matrix.java b/opengl/java/android/opengl/Matrix.java
index ce3f57e..5ae341b 100644
--- a/opengl/java/android/opengl/Matrix.java
+++ b/opengl/java/android/opengl/Matrix.java
@@ -16,6 +16,8 @@
package android.opengl;
+import androidx.annotation.NonNull;
+
/**
* Matrix math utilities. These methods operate on OpenGL ES format
* matrices and vectors stored in float arrays.
@@ -38,7 +40,11 @@
public class Matrix {
/** Temporary memory for operations that need temporary matrix data. */
- private final static float[] sTemp = new float[32];
+ private static final ThreadLocal<float[]> ThreadTmp = new ThreadLocal() {
+ @Override protected float[] initialValue() {
+ return new float[32];
+ }
+ };
/**
* @deprecated All methods are static, do not instantiate this class.
@@ -46,6 +52,40 @@
@Deprecated
public Matrix() {}
+ private static boolean overlap(
+ float[] a, int aStart, int aLength, float[] b, int bStart, int bLength) {
+ if (a != b) {
+ return false;
+ }
+
+ if (aStart == bStart) {
+ return true;
+ }
+
+ int aEnd = aStart + aLength;
+ int bEnd = bStart + bLength;
+
+ if (aEnd == bEnd) {
+ return true;
+ }
+
+ if (aStart < bStart && bStart < aEnd) {
+ return true;
+ }
+ if (aStart < bEnd && bEnd < aEnd) {
+ return true;
+ }
+
+ if (bStart < aStart && aStart < bEnd) {
+ return true;
+ }
+ if (bStart < aEnd && aEnd < bEnd) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Multiplies two 4x4 matrices together and stores the result in a third 4x4
* matrix. In matrix notation: result = lhs x rhs. Due to the way
@@ -53,9 +93,9 @@
* effect as first multiplying by the rhs matrix, then multiplying by
* the lhs matrix. This is the opposite of what you might expect.
* <p>
- * The same float array may be passed for result, lhs, and/or rhs. However,
- * the result element values are undefined if the result elements overlap
- * either the lhs or rhs elements.
+ * The same float array may be passed for result, lhs, and/or rhs. This
+ * operation is expected to do the correct thing if the result elements
+ * overlap with either of the lhs or rhs elements.
*
* @param result The float array that holds the result.
* @param resultOffset The offset into the result array where the result is
@@ -65,20 +105,101 @@
* @param rhs The float array that holds the right-hand-side matrix.
* @param rhsOffset The offset into the rhs array where the rhs is stored.
*
- * @throws IllegalArgumentException if result, lhs, or rhs are null, or if
- * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or
- * rhsOffset + 16 > rhs.length.
+ * @throws IllegalArgumentException under any of the following conditions:
+ * result, lhs, or rhs are null;
+ * resultOffset + 16 > result.length
+ * or lhsOffset + 16 > lhs.length
+ * or rhsOffset + 16 > rhs.length;
+ * resultOffset < 0 or lhsOffset < 0 or rhsOffset < 0
*/
- public static native void multiplyMM(float[] result, int resultOffset,
- float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);
+ public static void multiplyMM(float[] result, int resultOffset,
+ float[] lhs, int lhsOffset, float[] rhs, int rhsOffset) {
+ // error checking
+ if (result == null) {
+ throw new IllegalArgumentException("result == null");
+ }
+ if (lhs == null) {
+ throw new IllegalArgumentException("lhs == null");
+ }
+ if (rhs == null) {
+ throw new IllegalArgumentException("rhs == null");
+ }
+ if (resultOffset < 0) {
+ throw new IllegalArgumentException("resultOffset < 0");
+ }
+ if (lhsOffset < 0) {
+ throw new IllegalArgumentException("lhsOffset < 0");
+ }
+ if (rhsOffset < 0) {
+ throw new IllegalArgumentException("rhsOffset < 0");
+ }
+ if (result.length < resultOffset + 16) {
+ throw new IllegalArgumentException("result.length < resultOffset + 16");
+ }
+ if (lhs.length < lhsOffset + 16) {
+ throw new IllegalArgumentException("lhs.length < lhsOffset + 16");
+ }
+ if (rhs.length < rhsOffset + 16) {
+ throw new IllegalArgumentException("rhs.length < rhsOffset + 16");
+ }
+
+ // Check for overlap between rhs and result or lhs and result
+ if ( overlap(result, resultOffset, 16, lhs, lhsOffset, 16)
+ || overlap(result, resultOffset, 16, rhs, rhsOffset, 16) ) {
+ float[] tmp = ThreadTmp.get();
+ for (int i=0; i<4; i++) {
+ final float rhs_i0 = rhs[ 4*i + 0 + rhsOffset ];
+ float ri0 = lhs[ 0 + lhsOffset ] * rhs_i0;
+ float ri1 = lhs[ 1 + lhsOffset ] * rhs_i0;
+ float ri2 = lhs[ 2 + lhsOffset ] * rhs_i0;
+ float ri3 = lhs[ 3 + lhsOffset ] * rhs_i0;
+ for (int j=1; j<4; j++) {
+ final float rhs_ij = rhs[ 4*i + j + rhsOffset];
+ ri0 += lhs[ 4*j + 0 + lhsOffset ] * rhs_ij;
+ ri1 += lhs[ 4*j + 1 + lhsOffset ] * rhs_ij;
+ ri2 += lhs[ 4*j + 2 + lhsOffset ] * rhs_ij;
+ ri3 += lhs[ 4*j + 3 + lhsOffset ] * rhs_ij;
+ }
+ tmp[ 4*i + 0 ] = ri0;
+ tmp[ 4*i + 1 ] = ri1;
+ tmp[ 4*i + 2 ] = ri2;
+ tmp[ 4*i + 3 ] = ri3;
+ }
+
+ // copy from tmp to result
+ for (int i=0; i < 16; i++) {
+ result[ i + resultOffset ] = tmp[ i ];
+ }
+
+ } else {
+ for (int i=0; i<4; i++) {
+ final float rhs_i0 = rhs[ 4*i + 0 + rhsOffset ];
+ float ri0 = lhs[ 0 + lhsOffset ] * rhs_i0;
+ float ri1 = lhs[ 1 + lhsOffset ] * rhs_i0;
+ float ri2 = lhs[ 2 + lhsOffset ] * rhs_i0;
+ float ri3 = lhs[ 3 + lhsOffset ] * rhs_i0;
+ for (int j=1; j<4; j++) {
+ final float rhs_ij = rhs[ 4*i + j + rhsOffset];
+ ri0 += lhs[ 4*j + 0 + lhsOffset ] * rhs_ij;
+ ri1 += lhs[ 4*j + 1 + lhsOffset ] * rhs_ij;
+ ri2 += lhs[ 4*j + 2 + lhsOffset ] * rhs_ij;
+ ri3 += lhs[ 4*j + 3 + lhsOffset ] * rhs_ij;
+ }
+ result[ 4*i + 0 + resultOffset ] = ri0;
+ result[ 4*i + 1 + resultOffset ] = ri1;
+ result[ 4*i + 2 + resultOffset ] = ri2;
+ result[ 4*i + 3 + resultOffset ] = ri3;
+ }
+ }
+ }
/**
* Multiplies a 4 element vector by a 4x4 matrix and stores the result in a
* 4-element column vector. In matrix notation: result = lhs x rhs
* <p>
* The same float array may be passed for resultVec, lhsMat, and/or rhsVec.
- * However, the resultVec element values are undefined if the resultVec
- * elements overlap either the lhsMat or rhsVec elements.
+ * This operation is expected to do the correct thing if the result elements
+ * overlap with either of the lhs or rhs elements.
*
* @param resultVec The float array that holds the result vector.
* @param resultVecOffset The offset into the result array where the result
@@ -89,14 +210,67 @@
* @param rhsVecOffset The offset into the rhs vector where the rhs vector
* is stored.
*
- * @throws IllegalArgumentException if resultVec, lhsMat,
- * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length
- * or lhsMatOffset + 16 > lhsMat.length or
- * rhsVecOffset + 4 > rhsVec.length.
+ * @throws IllegalArgumentException under any of the following conditions:
+ * resultVec, lhsMat, or rhsVec are null;
+ * resultVecOffset + 4 > resultVec.length
+ * or lhsMatOffset + 16 > lhsMat.length
+ * or rhsVecOffset + 4 > rhsVec.length;
+ * resultVecOffset < 0 or lhsMatOffset < 0 or rhsVecOffset < 0
*/
- public static native void multiplyMV(float[] resultVec,
+ public static void multiplyMV(float[] resultVec,
int resultVecOffset, float[] lhsMat, int lhsMatOffset,
- float[] rhsVec, int rhsVecOffset);
+ float[] rhsVec, int rhsVecOffset) {
+ // error checking
+ if (resultVec == null) {
+ throw new IllegalArgumentException("resultVec == null");
+ }
+ if (lhsMat == null) {
+ throw new IllegalArgumentException("lhsMat == null");
+ }
+ if (rhsVec == null) {
+ throw new IllegalArgumentException("rhsVec == null");
+ }
+ if (resultVecOffset < 0) {
+ throw new IllegalArgumentException("resultVecOffset < 0");
+ }
+ if (lhsMatOffset < 0) {
+ throw new IllegalArgumentException("lhsMatOffset < 0");
+ }
+ if (rhsVecOffset < 0) {
+ throw new IllegalArgumentException("rhsVecOffset < 0");
+ }
+ if (resultVec.length < resultVecOffset + 4) {
+ throw new IllegalArgumentException("resultVec.length < resultVecOffset + 4");
+ }
+ if (lhsMat.length < lhsMatOffset + 16) {
+ throw new IllegalArgumentException("lhsMat.length < lhsMatOffset + 16");
+ }
+ if (rhsVec.length < rhsVecOffset + 4) {
+ throw new IllegalArgumentException("rhsVec.length < rhsVecOffset + 4");
+ }
+
+ float tmp0 = lhsMat[0 + 4 * 0 + lhsMatOffset] * rhsVec[0 + rhsVecOffset] +
+ lhsMat[0 + 4 * 1 + lhsMatOffset] * rhsVec[1 + rhsVecOffset] +
+ lhsMat[0 + 4 * 2 + lhsMatOffset] * rhsVec[2 + rhsVecOffset] +
+ lhsMat[0 + 4 * 3 + lhsMatOffset] * rhsVec[3 + rhsVecOffset];
+ float tmp1 = lhsMat[1 + 4 * 0 + lhsMatOffset] * rhsVec[0 + rhsVecOffset] +
+ lhsMat[1 + 4 * 1 + lhsMatOffset] * rhsVec[1 + rhsVecOffset] +
+ lhsMat[1 + 4 * 2 + lhsMatOffset] * rhsVec[2 + rhsVecOffset] +
+ lhsMat[1 + 4 * 3 + lhsMatOffset] * rhsVec[3 + rhsVecOffset];
+ float tmp2 = lhsMat[2 + 4 * 0 + lhsMatOffset] * rhsVec[0 + rhsVecOffset] +
+ lhsMat[2 + 4 * 1 + lhsMatOffset] * rhsVec[1 + rhsVecOffset] +
+ lhsMat[2 + 4 * 2 + lhsMatOffset] * rhsVec[2 + rhsVecOffset] +
+ lhsMat[2 + 4 * 3 + lhsMatOffset] * rhsVec[3 + rhsVecOffset];
+ float tmp3 = lhsMat[3 + 4 * 0 + lhsMatOffset] * rhsVec[0 + rhsVecOffset] +
+ lhsMat[3 + 4 * 1 + lhsMatOffset] * rhsVec[1 + rhsVecOffset] +
+ lhsMat[3 + 4 * 2 + lhsMatOffset] * rhsVec[2 + rhsVecOffset] +
+ lhsMat[3 + 4 * 3 + lhsMatOffset] * rhsVec[3 + rhsVecOffset];
+
+ resultVec[ 0 + resultVecOffset ] = tmp0;
+ resultVec[ 1 + resultVecOffset ] = tmp1;
+ resultVec[ 2 + resultVecOffset ] = tmp2;
+ resultVec[ 3 + resultVecOffset ] = tmp3;
+ }
/**
* Transposes a 4 x 4 matrix.
@@ -537,10 +711,9 @@
public static void rotateM(float[] rm, int rmOffset,
float[] m, int mOffset,
float a, float x, float y, float z) {
- synchronized(sTemp) {
- setRotateM(sTemp, 0, a, x, y, z);
- multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0);
- }
+ float[] tmp = ThreadTmp.get();
+ setRotateM(tmp, 16, a, x, y, z);
+ multiplyMM(rm, rmOffset, m, mOffset, tmp, 16);
}
/**
@@ -556,11 +729,7 @@
*/
public static void rotateM(float[] m, int mOffset,
float a, float x, float y, float z) {
- synchronized(sTemp) {
- setRotateM(sTemp, 0, a, x, y, z);
- multiplyMM(sTemp, 16, m, mOffset, sTemp, 0);
- System.arraycopy(sTemp, 16, m, mOffset, 16);
- }
+ rotateM(m, mOffset, m, mOffset, a, x, y, z);
}
/**
@@ -640,9 +809,14 @@
* @param rm returns the result
* @param rmOffset index into rm where the result matrix starts
* @param x angle of rotation, in degrees
- * @param y angle of rotation, in degrees
+ * @param y is broken, do not use
* @param z angle of rotation, in degrees
+ *
+ * @deprecated This method is incorrect around the y axis. This method is
+ * deprecated and replaced (below) by setRotateEulerM2 which
+ * behaves correctly
*/
+ @Deprecated
public static void setRotateEulerM(float[] rm, int rmOffset,
float x, float y, float z) {
x *= (float) (Math.PI / 180.0f);
@@ -679,6 +853,64 @@
}
/**
+ * Converts Euler angles to a rotation matrix.
+ *
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param x angle of rotation, in degrees
+ * @param y angle of rotation, in degrees
+ * @param z angle of rotation, in degrees
+ *
+ * @throws IllegalArgumentException if rm is null;
+ * or if rmOffset + 16 > rm.length;
+ * rmOffset < 0
+ */
+ public static void setRotateEulerM2(@NonNull float[] rm, int rmOffset,
+ float x, float y, float z) {
+ if (rm == null) {
+ throw new IllegalArgumentException("rm == null");
+ }
+ if (rmOffset < 0) {
+ throw new IllegalArgumentException("rmOffset < 0");
+ }
+ if (rm.length < rmOffset + 16) {
+ throw new IllegalArgumentException("rm.length < rmOffset + 16");
+ }
+
+ x *= (float) (Math.PI / 180.0f);
+ y *= (float) (Math.PI / 180.0f);
+ z *= (float) (Math.PI / 180.0f);
+ float cx = (float) Math.cos(x);
+ float sx = (float) Math.sin(x);
+ float cy = (float) Math.cos(y);
+ float sy = (float) Math.sin(y);
+ float cz = (float) Math.cos(z);
+ float sz = (float) Math.sin(z);
+ float cxsy = cx * sy;
+ float sxsy = sx * sy;
+
+ rm[rmOffset + 0] = cy * cz;
+ rm[rmOffset + 1] = -cy * sz;
+ rm[rmOffset + 2] = sy;
+ rm[rmOffset + 3] = 0.0f;
+
+ rm[rmOffset + 4] = sxsy * cz + cx * sz;
+ rm[rmOffset + 5] = -sxsy * sz + cx * cz;
+ rm[rmOffset + 6] = -sx * cy;
+ rm[rmOffset + 7] = 0.0f;
+
+ rm[rmOffset + 8] = -cxsy * cz + sx * sz;
+ rm[rmOffset + 9] = cxsy * sz + sx * cz;
+ rm[rmOffset + 10] = cx * cy;
+ rm[rmOffset + 11] = 0.0f;
+
+ rm[rmOffset + 12] = 0.0f;
+ rm[rmOffset + 13] = 0.0f;
+ rm[rmOffset + 14] = 0.0f;
+ rm[rmOffset + 15] = 1.0f;
+ }
+
+ /**
* Defines a viewing transformation in terms of an eye point, a center of
* view, and an up vector.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
index 1f72609..a80061e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
@@ -53,8 +53,8 @@
static final String PREFIX_BT_SYNC_INTERVAL = "SI:";
static final String PREFIX_BT_IS_ENCRYPTED = "E:";
static final String PREFIX_BT_BROADCAST_CODE = "C:";
- static final String PREFIX_BT_PRESENTATION_DELAY = "D:";
- static final String PREFIX_BT_SUBGROUPS = "G:";
+ static final String PREFIX_BT_PRESENTATION_DELAY = "PD:";
+ static final String PREFIX_BT_SUBGROUPS = "SG:";
static final String PREFIX_BT_ANDROID_VERSION = "V:";
// BluetoothLeBroadcastSubgroup
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 5c796af..879181f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -278,6 +278,18 @@
return false;
}
+ /**
+ * Check if a device class matches with a defined BluetoothClass device.
+ *
+ * @param device Must be one of the public constants in {@link BluetoothClass.Device}
+ * @return true if device class matches, false otherwise.
+ */
+ public static boolean isDeviceClassMatched(@NonNull BluetoothDevice bluetoothDevice,
+ int device) {
+ return bluetoothDevice.getBluetoothClass() != null
+ && bluetoothDevice.getBluetoothClass().getDeviceClass() == device;
+ }
+
private static boolean isAdvancedHeaderEnabled() {
if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI, BT_ADVANCED_HEADER_ENABLED,
true)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index eb53ea1..c8187b8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -35,7 +35,6 @@
import android.os.ParcelUuid;
import android.os.SystemClock;
import android.text.TextUtils;
-import android.util.EventLog;
import android.util.Log;
import android.util.LruCache;
import android.util.Pair;
@@ -1020,15 +1019,7 @@
if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) {
// The pairing dialog now warns of phone-book access for paired devices.
// No separate prompt is displayed after pairing.
- final BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
- if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
- if (bluetoothClass != null && (bluetoothClass.getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE
- || bluetoothClass.getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
- EventLog.writeEvent(0x534e4554, "138529441", -1, "");
- }
- }
+ mDevice.getPhonebookAccessPermission();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
index aff9a6e..c61ebc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
@@ -28,7 +28,9 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -38,6 +40,43 @@
private static final String METADATA_START = "<";
private static final String METADATA_END = ">";
private static final String PATTERN_REGEX = "<(.*?)>";
+ private static final String PATTERN_BT_BROADCAST_METADATA =
+ "T:<(.*?)>;+D:<(.*?)>;+AS:<(.*?)>;+B:<(.*?)>;+SI:<(.*?)>;+E:<(.*?)>;+C:<(.*?)>;"
+ + "+PD:<(.*?)>;+SG:(.*)";
+ private static final String PATTERN_BT_SUBGROUP =
+ "CID:<(.*?)>;+CC:<(.*?);>;+AC:<(.*?);>;+CP:<(.*?)>;+BC:<(.*)>;>;";
+ private static final String PATTERN_BT_CHANNEL = "CI:<(.*?)>;+BCCM:<(.*?);>;";
+
+ /* Index for BluetoothLeBroadcastMetadata */
+ private static int MATCH_INDEX_ADDRESS_TYPE = 1;
+ private static int MATCH_INDEX_DEVICE = 2;
+ private static int MATCH_INDEX_ADVERTISING_SID = 3;
+ private static int MATCH_INDEX_BROADCAST_ID = 4;
+ private static int MATCH_INDEX_SYNC_INTERVAL = 5;
+ private static int MATCH_INDEX_IS_ENCRYPTED = 6;
+ private static int MATCH_INDEX_BROADCAST_CODE = 7;
+ private static int MATCH_INDEX_PRESENTATION_DELAY = 8;
+ private static int MATCH_INDEX_SUBGROUPS = 9;
+
+ /* Index for BluetoothLeBroadcastSubgroup */
+ private static int MATCH_INDEX_CODEC_ID = 1;
+ private static int MATCH_INDEX_CODEC_CONFIG = 2;
+ private static int MATCH_INDEX_AUDIO_CONTENT = 3;
+ private static int MATCH_INDEX_CHANNEL_PREF = 4;
+ private static int MATCH_INDEX_BROADCAST_CHANNEL = 5;
+
+ /* Index for BluetoothLeAudioCodecConfigMetadata */
+ private static int LIST_INDEX_AUDIO_LOCATION = 0;
+ private static int LIST_INDEX_CODEC_CONFIG_RAW_METADATA = 1;
+
+ /* Index for BluetoothLeAudioContentMetadata */
+ private static int LIST_INDEX_PROGRAM_INFO = 0;
+ private static int LIST_INDEX_LANGUAGE = 1;
+ private static int LIST_INDEX_AUDIO_CONTENT_RAW_METADATA = 2;
+
+ /* Index for BluetoothLeBroadcastChannel */
+ private static int MATCH_INDEX_CHANNEL_INDEX = 1;
+ private static int MATCH_INDEX_CHANNEL_CODEC_CONFIG = 2;
private BluetoothLeBroadcastSubgroup mSubgroup;
private List<BluetoothLeBroadcastSubgroup> mSubgroupList;
@@ -55,17 +94,20 @@
private byte[] mBroadcastCode;
// BluetoothLeBroadcastSubgroup
- private long mCodecId;
+ private int mCodecId;
private BluetoothLeAudioContentMetadata mContentMetadata;
private BluetoothLeAudioCodecConfigMetadata mConfigMetadata;
- private BluetoothLeBroadcastChannel mChannel;
+ private Boolean mNoChannelPreference;
+ private List<BluetoothLeBroadcastChannel> mChannel;
// BluetoothLeAudioCodecConfigMetadata
private long mAudioLocation;
+ private byte[] mCodecConfigMetadata;
// BluetoothLeAudioContentMetadata
private String mLanguage;
private String mProgramInfo;
+ private byte[] mAudioContentMetadata;
// BluetoothLeBroadcastChannel
private boolean mIsSelected;
@@ -135,6 +177,7 @@
for (BluetoothLeBroadcastSubgroup subgroup: subgroupList) {
String audioCodec = convertAudioCodecConfigToString(subgroup.getCodecSpecificConfig());
String audioContent = convertAudioContentToString(subgroup.getContentMetadata());
+ boolean hasChannelPreference = subgroup.hasChannelPreference();
String channels = convertChannelToString(subgroup.getChannels());
subgroupString = new StringBuilder()
.append(BluetoothBroadcastUtils.PREFIX_BTSG_CODEC_ID)
@@ -146,6 +189,9 @@
.append(BluetoothBroadcastUtils.PREFIX_BTSG_AUDIO_CONTENT)
.append(METADATA_START).append(audioContent).append(METADATA_END)
.append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+ .append(BluetoothBroadcastUtils.PREFIX_BTSG_CHANNEL_PREF)
+ .append(METADATA_START).append(hasChannelPreference).append(METADATA_END)
+ .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
.append(BluetoothBroadcastUtils.PREFIX_BTSG_BROADCAST_CHANNEL)
.append(METADATA_START).append(channels).append(METADATA_END)
.append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
@@ -211,26 +257,35 @@
if (DEBUG) {
Log.d(TAG, "Convert " + qrCodeString + "to BluetoothLeBroadcastMetadata");
}
- Pattern pattern = Pattern.compile(PATTERN_REGEX);
+
+ Pattern pattern = Pattern.compile(PATTERN_BT_BROADCAST_METADATA);
Matcher match = pattern.matcher(qrCodeString);
if (match.find()) {
- ArrayList<String> resultList = new ArrayList<>();
- resultList.add(match.group(1));
- mSourceAddressType = Integer.parseInt(resultList.get(0));
+ mSourceAddressType = Integer.parseInt(match.group(MATCH_INDEX_ADDRESS_TYPE));
mSourceDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
- resultList.get(1));
- mSourceAdvertisingSid = Integer.parseInt(resultList.get(2));
- mBroadcastId = Integer.parseInt(resultList.get(3));
- mPaSyncInterval = Integer.parseInt(resultList.get(4));
- mIsEncrypted = Boolean.valueOf(resultList.get(5));
- mBroadcastCode = resultList.get(6).getBytes();
- mPresentationDelayMicros = Integer.parseInt(resultList.get(7));
- mSubgroup = convertToSubgroup(resultList.get(8));
+ match.group(MATCH_INDEX_DEVICE));
+ mSourceAdvertisingSid = Integer.parseInt(match.group(MATCH_INDEX_ADVERTISING_SID));
+ mBroadcastId = Integer.parseInt(match.group(MATCH_INDEX_BROADCAST_ID));
+ mPaSyncInterval = Integer.parseInt(match.group(MATCH_INDEX_SYNC_INTERVAL));
+ mIsEncrypted = Boolean.valueOf(match.group(MATCH_INDEX_IS_ENCRYPTED));
+ mBroadcastCode = match.group(MATCH_INDEX_BROADCAST_CODE).getBytes();
+ mPresentationDelayMicros =
+ Integer.parseInt(match.group(MATCH_INDEX_PRESENTATION_DELAY));
if (DEBUG) {
- Log.d(TAG, "Converted qrCodeString result: " + match.group());
+ Log.d(TAG, "Converted qrCodeString result: "
+ + " ,Type = " + mSourceAddressType
+ + " ,Device = " + mSourceDevice
+ + " ,AdSid = " + mSourceAdvertisingSid
+ + " ,BroadcastId = " + mBroadcastId
+ + " ,paSync = " + mPaSyncInterval
+ + " ,encrypted = " + mIsEncrypted
+ + " ,BroadcastCode = " + Arrays.toString(mBroadcastCode)
+ + " ,delay = " + mPresentationDelayMicros);
}
+ mSubgroup = convertToSubgroup(match.group(MATCH_INDEX_SUBGROUPS));
+
return new BluetoothLeBroadcastMetadata.Builder()
.setSourceDevice(mSourceDevice, mSourceAddressType)
.setSourceAdvertisingSid(mSourceAdvertisingSid)
@@ -254,26 +309,26 @@
if (DEBUG) {
Log.d(TAG, "Convert " + subgroupString + "to BluetoothLeBroadcastSubgroup");
}
- Pattern pattern = Pattern.compile(PATTERN_REGEX);
+ Pattern pattern = Pattern.compile(PATTERN_BT_SUBGROUP);
Matcher match = pattern.matcher(subgroupString);
if (match.find()) {
- ArrayList<String> resultList = new ArrayList<>();
- resultList.add(match.group(1));
- mCodecId = Long.getLong(resultList.get(0));
- mConfigMetadata = convertToConfigMetadata(resultList.get(1));
- mContentMetadata = convertToContentMetadata(resultList.get(2));
- mChannel = convertToChannel(resultList.get(3), mConfigMetadata);
+ mCodecId = Integer.parseInt(match.group(MATCH_INDEX_CODEC_ID));
+ mConfigMetadata = convertToConfigMetadata(match.group(MATCH_INDEX_CODEC_CONFIG));
+ mContentMetadata = convertToContentMetadata(match.group(MATCH_INDEX_AUDIO_CONTENT));
+ mNoChannelPreference = Boolean.valueOf(match.group(MATCH_INDEX_CHANNEL_PREF));
+ mChannel =
+ convertToChannel(match.group(MATCH_INDEX_BROADCAST_CHANNEL), mConfigMetadata);
- if (DEBUG) {
- Log.d(TAG, "Converted subgroupString result: " + match.group());
+ BluetoothLeBroadcastSubgroup.Builder subgroupBuilder =
+ new BluetoothLeBroadcastSubgroup.Builder();
+ subgroupBuilder.setCodecId(mCodecId);
+ subgroupBuilder.setCodecSpecificConfig(mConfigMetadata);
+ subgroupBuilder.setContentMetadata(mContentMetadata);
+
+ for (BluetoothLeBroadcastChannel channel : mChannel) {
+ subgroupBuilder.addChannel(channel);
}
-
- return new BluetoothLeBroadcastSubgroup.Builder()
- .setCodecId(mCodecId)
- .setCodecSpecificConfig(mConfigMetadata)
- .setContentMetadata(mContentMetadata)
- .addChannel(mChannel)
- .build();
+ return subgroupBuilder.build();
} else {
if (DEBUG) {
Log.d(TAG,
@@ -291,15 +346,17 @@
}
Pattern pattern = Pattern.compile(PATTERN_REGEX);
Matcher match = pattern.matcher(configMetadataString);
- if (match.find()) {
- ArrayList<String> resultList = new ArrayList<>();
+ ArrayList<String> resultList = new ArrayList<>();
+ while (match.find()) {
resultList.add(match.group(1));
- mAudioLocation = Long.getLong(resultList.get(0));
-
- if (DEBUG) {
- Log.d(TAG, "Converted configMetadataString result: " + match.group());
- }
-
+ Log.d(TAG, "Codec Config match : " + match.group(1));
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Converted configMetadataString result: " + resultList.size());
+ }
+ if (resultList.size() > 0) {
+ mAudioLocation = Long.parseLong(resultList.get(LIST_INDEX_AUDIO_LOCATION));
+ mCodecConfigMetadata = resultList.get(LIST_INDEX_CODEC_CONFIG_RAW_METADATA).getBytes();
return new BluetoothLeAudioCodecConfigMetadata.Builder()
.setAudioLocation(mAudioLocation)
.build();
@@ -319,14 +376,25 @@
}
Pattern pattern = Pattern.compile(PATTERN_REGEX);
Matcher match = pattern.matcher(contentMetadataString);
- if (match.find()) {
- ArrayList<String> resultList = new ArrayList<>();
+ ArrayList<String> resultList = new ArrayList<>();
+ while (match.find()) {
+ Log.d(TAG, "Audio Content match : " + match.group(1));
resultList.add(match.group(1));
- mProgramInfo = resultList.get(0);
- mLanguage = resultList.get(1);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Converted contentMetadataString result: " + resultList.size());
+ }
+ if (resultList.size() > 0) {
+ mProgramInfo = resultList.get(LIST_INDEX_PROGRAM_INFO);
+ mLanguage = resultList.get(LIST_INDEX_LANGUAGE);
+ mAudioContentMetadata =
+ resultList.get(LIST_INDEX_AUDIO_CONTENT_RAW_METADATA).getBytes();
- if (DEBUG) {
- Log.d(TAG, "Converted contentMetadataString result: " + match.group());
+ /* TODO(b/265253566) : Need to set the default value for language when the user starts
+ * the broadcast.
+ */
+ if (mLanguage.equals("null")) {
+ mLanguage = "eng";
}
return new BluetoothLeAudioContentMetadata.Builder()
@@ -342,28 +410,34 @@
}
}
- private BluetoothLeBroadcastChannel convertToChannel(String channelString,
+ private List<BluetoothLeBroadcastChannel> convertToChannel(String channelString,
BluetoothLeAudioCodecConfigMetadata configMetadata) {
if (DEBUG) {
Log.d(TAG, "Convert " + channelString + "to BluetoothLeBroadcastChannel");
}
- Pattern pattern = Pattern.compile(PATTERN_REGEX);
+ Pattern pattern = Pattern.compile(PATTERN_BT_CHANNEL);
Matcher match = pattern.matcher(channelString);
- if (match.find()) {
- ArrayList<String> resultList = new ArrayList<>();
- resultList.add(match.group(1));
- mIsSelected = Boolean.valueOf(resultList.get(0));
- mChannelIndex = Integer.parseInt(resultList.get(1));
+ Map<Integer, BluetoothLeAudioCodecConfigMetadata> channel =
+ new HashMap<Integer, BluetoothLeAudioCodecConfigMetadata>();
+ while (match.find()) {
+ channel.put(Integer.parseInt(match.group(MATCH_INDEX_CHANNEL_INDEX)),
+ convertToConfigMetadata(match.group(MATCH_INDEX_CHANNEL_CODEC_CONFIG)));
+ }
- if (DEBUG) {
- Log.d(TAG, "Converted channelString result: " + match.group());
+ if (channel.size() > 0) {
+ mIsSelected = false;
+ ArrayList<BluetoothLeBroadcastChannel> broadcastChannelList = new ArrayList<>();
+ for (Map.Entry<Integer, BluetoothLeAudioCodecConfigMetadata> entry :
+ channel.entrySet()) {
+
+ broadcastChannelList.add(
+ new BluetoothLeBroadcastChannel.Builder()
+ .setSelected(mIsSelected)
+ .setChannelIndex(entry.getKey())
+ .setCodecMetadata(entry.getValue())
+ .build());
}
-
- return new BluetoothLeBroadcastChannel.Builder()
- .setSelected(mIsSelected)
- .setChannelIndex(mChannelIndex)
- .setCodecMetadata(configMetadata)
- .build();
+ return broadcastChannelList;
} else {
if (DEBUG) {
Log.d(TAG,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index fd7554f..cd667ca 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -48,6 +48,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -376,9 +377,11 @@
Setting newSetting = new Setting(name, oldSetting.getValue(), null,
oldSetting.getPackageName(), oldSetting.getTag(), false,
oldSetting.getId());
+ int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), 0,
+ oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+ checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
mSettings.put(name, newSetting);
- updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,
- newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+ updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
scheduleWriteIfNeededLocked();
}
}
@@ -410,6 +413,13 @@
Setting oldState = mSettings.get(name);
String oldValue = (oldState != null) ? oldState.value : null;
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
+ String newDefaultValue = makeDefault ? value : oldDefaultValue;
+
+ int newSize = getNewMemoryUsagePerPackageLocked(packageName,
+ oldValue == null ? name.length() : 0 /* deltaKeySize */,
+ oldValue, value, oldDefaultValue, newDefaultValue);
+ checkNewMemoryUsagePerPackageLocked(packageName, newSize);
+
Setting newState;
if (oldState != null) {
@@ -430,8 +440,7 @@
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
- updateMemoryUsagePerPackageLocked(packageName, oldValue, value,
- oldDefaultValue, newState.getDefaultValue());
+ updateMemoryUsagePerPackageLocked(packageName, newSize);
scheduleWriteIfNeededLocked();
@@ -552,13 +561,18 @@
}
Setting oldState = mSettings.remove(name);
+ if (oldState == null) {
+ return false;
+ }
+ int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName,
+ -name.length() /* deltaKeySize */,
+ oldState.value, null, oldState.defaultValue, null);
FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "",
/* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
- updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
- null, oldState.defaultValue, null);
+ updateMemoryUsagePerPackageLocked(oldState.packageName, newSize);
addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
@@ -575,20 +589,23 @@
}
Setting setting = mSettings.get(name);
+ if (setting == null) {
+ return false;
+ }
Setting oldSetting = new Setting(setting);
String oldValue = setting.getValue();
String oldDefaultValue = setting.getDefaultValue();
+ int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, 0, oldValue,
+ oldDefaultValue, oldDefaultValue, oldDefaultValue);
+ checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize);
+
if (!setting.reset()) {
return false;
}
- String newValue = setting.getValue();
- String newDefaultValue = setting.getDefaultValue();
-
- updateMemoryUsagePerPackageLocked(setting.packageName, oldValue,
- newValue, oldDefaultValue, newDefaultValue);
+ updateMemoryUsagePerPackageLocked(setting.packageName, newSize);
addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting);
@@ -696,38 +713,49 @@
}
@GuardedBy("mLock")
- private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
- String newValue, String oldDefaultValue, String newDefaultValue) {
- if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
+ private boolean isExemptFromMemoryUsageCap(String packageName) {
+ return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED
+ || SYSTEM_PACKAGE_NAME.equals(packageName);
+ }
+
+ @GuardedBy("mLock")
+ private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize)
+ throws IllegalStateException {
+ if (isExemptFromMemoryUsageCap(packageName)) {
return;
}
-
- if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
- return;
- }
-
- final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
- final int newValueSize = (newValue != null) ? newValue.length() : 0;
- final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
- final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
- final int deltaSize = newValueSize + newDefaultValueSize
- - oldValueSize - oldDefaultValueSize;
-
- Integer currentSize = mPackageToMemoryUsage.get(packageName);
- final int newSize = Math.max((currentSize != null)
- ? currentSize + deltaSize : deltaSize, 0);
-
if (newSize > mMaxBytesPerAppPackage) {
throw new IllegalStateException("You are adding too many system settings. "
+ "You should stop using system settings for app specific data"
+ " package: " + packageName);
}
+ }
+ @GuardedBy("mLock")
+ private int getNewMemoryUsagePerPackageLocked(String packageName, int deltaKeySize,
+ String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) {
+ if (isExemptFromMemoryUsageCap(packageName)) {
+ return 0;
+ }
+ final Integer currentSize = mPackageToMemoryUsage.get(packageName);
+ final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
+ final int newValueSize = (newValue != null) ? newValue.length() : 0;
+ final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
+ final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
+ final int deltaSize = deltaKeySize + newValueSize + newDefaultValueSize
+ - oldValueSize - oldDefaultValueSize;
+ return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0);
+ }
+
+ @GuardedBy("mLock")
+ private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) {
+ if (isExemptFromMemoryUsageCap(packageName)) {
+ return;
+ }
if (DEBUG) {
Slog.i(LOG_TAG, "Settings for package: " + packageName
+ " size: " + newSize + " bytes.");
}
-
mPackageToMemoryUsage.put(packageName, newSize);
}
@@ -1556,4 +1584,11 @@
}
return false;
}
+
+ @VisibleForTesting
+ public int getMemoryUsage(String packageName) {
+ synchronized (mLock) {
+ return mPackageToMemoryUsage.getOrDefault(packageName, 0);
+ }
+ }
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 69eb713..f6d4329 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -20,6 +20,8 @@
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.google.common.base.Strings;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -276,4 +278,132 @@
settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
return settingsState;
}
+
+ public void testInsertSetting_memoryUsage() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+ // No exception should be thrown when there is no cap
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ settingsState.deleteSettingLocked(SETTING_NAME);
+
+ settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+ // System package doesn't have memory usage limit
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, SYSTEM_PACKAGE);
+ settingsState.deleteSettingLocked(SETTING_NAME);
+
+ // Should not throw if usage is under the cap
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19975),
+ null, false, "p1");
+ settingsState.deleteSettingLocked(SETTING_NAME);
+ try {
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("p1"));
+ }
+ try {
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("p1"));
+ }
+ assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull());
+ try {
+ settingsState.insertSettingLocked(Strings.repeat("A", 20001), "",
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ }
+
+ public void testMemoryUsagePerPackage() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+
+ // Test inserting one key with default
+ final String testKey1 = SETTING_NAME;
+ final String testValue1 = Strings.repeat("A", 100);
+ settingsState.insertSettingLocked(testKey1, testValue1, null, true, TEST_PACKAGE);
+ int expectedMemUsage = testKey1.length() + testValue1.length()
+ + testValue1.length() /* size for default */;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test inserting another key
+ final String testKey2 = SETTING_NAME + "2";
+ settingsState.insertSettingLocked(testKey2, testValue1, null, false, TEST_PACKAGE);
+ expectedMemUsage += testKey2.length() + testValue1.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating first key with new default
+ final String testValue2 = Strings.repeat("A", 300);
+ settingsState.insertSettingLocked(testKey1, testValue2, null, true, TEST_PACKAGE);
+ expectedMemUsage += (testValue2.length() - testValue1.length()) * 2;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating first key without new default
+ final String testValue3 = Strings.repeat("A", 50);
+ settingsState.insertSettingLocked(testKey1, testValue3, null, false, TEST_PACKAGE);
+ expectedMemUsage -= testValue2.length() - testValue3.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test updating second key
+ settingsState.insertSettingLocked(testKey2, testValue2, null, false, TEST_PACKAGE);
+ expectedMemUsage -= testValue1.length() - testValue2.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test resetting key
+ settingsState.resetSettingLocked(testKey1);
+ expectedMemUsage += testValue2.length() - testValue3.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test resetting default value
+ settingsState.resetSettingDefaultValueLocked(testKey1);
+ expectedMemUsage -= testValue2.length();
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test deletion
+ settingsState.deleteSettingLocked(testKey2);
+ expectedMemUsage -= testValue2.length() + testKey2.length() /* key is deleted too */;
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test another package with a different key
+ final String testPackage2 = TEST_PACKAGE + "2";
+ final String testKey3 = SETTING_NAME + "3";
+ settingsState.insertSettingLocked(testKey3, testValue1, null, true, testPackage2);
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+ final int expectedMemUsage2 = testKey3.length() + testValue1.length() * 2;
+ assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+
+ // Test system package
+ settingsState.insertSettingLocked(testKey1, testValue1, null, true, SYSTEM_PACKAGE);
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+ assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+ assertEquals(0, settingsState.getMemoryUsage(SYSTEM_PACKAGE));
+
+ // Test invalid value
+ try {
+ settingsState.insertSettingLocked(testKey1, Strings.repeat("A", 20001), null, false,
+ TEST_PACKAGE);
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+
+ // Test invalid key
+ try {
+ settingsState.insertSettingLocked(Strings.repeat("A", 20001), "", null, false,
+ TEST_PACKAGE);
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+ }
+ assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
+ }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 979e9ea..f13d961 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -578,11 +578,6 @@
<!-- Permission required for CTS test - PeopleManagerTest -->
<uses-permission android:name="android.permission.READ_PEOPLE_DATA" />
- <!-- Permissions required for CTS test - TrustTestCases -->
- <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
- <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
- <uses-permission android:name="android.permission.TRUST_LISTENER" />
-
<!-- Permission required for CTS test - CtsTaskFpsCallbackTestCases -->
<uses-permission android:name="android.permission.ACCESS_FPS_COUNTER" />
diff --git a/packages/SystemUI/checks/Android.bp b/packages/SystemUI/checks/Android.bp
index 9671add..29668d1 100644
--- a/packages/SystemUI/checks/Android.bp
+++ b/packages/SystemUI/checks/Android.bp
@@ -37,12 +37,6 @@
java_test_host {
name: "SystemUILintCheckerTest",
- // TODO(b/239881504): Since this test was written, Android
- // Lint was updated, and now includes classes that were
- // compiled for java 15. The soong build doesn't support
- // java 15 yet, so we can't compile against "lint". Disable
- // the test until java 15 is supported.
- enabled: false,
srcs: [
"tests/**/*.kt",
"tests/**/*.java",
@@ -55,5 +49,19 @@
],
test_options: {
unit_test: true,
+ tradefed_options: [
+ {
+ // lint bundles in some classes that were built with older versions
+ // of libraries, and no longer load. Since tradefed tries to load
+ // all classes in the jar to look for tests, it crashes loading them.
+ // Exclude these classes from tradefed's search.
+ name: "exclude-paths",
+ value: "org/apache",
+ },
+ {
+ name: "exclude-paths",
+ value: "META-INF",
+ },
+ ],
},
}
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index d90156d..0a9a93b 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -61,25 +61,25 @@
<!-- SIM messages --><skip />
<!-- When the user inserts a sim card from an unsupported network, it becomes network locked -->
<string name="keyguard_network_locked_message">Network locked</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message_short">No SIM card</string>
- <!-- Shown to ask the user to insert a SIM card. -->
- <string name="keyguard_missing_sim_instructions">Insert a SIM card.</string>
- <!-- Shown to ask the user to insert a SIM card when sim is missing or not readable. -->
- <string name="keyguard_missing_sim_instructions_long">The SIM card is missing or not readable. Insert a SIM card.</string>
- <!-- Shown when SIM card is permanently disabled. -->
- <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM card.</string>
- <!-- Shown to inform the user to SIM card is permanently disabled. -->
- <string name="keyguard_permanent_disabled_sim_instructions">Your SIM card has been permanently disabled.\n
- Contact your wireless service provider for another SIM card.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message_short">No SIM</string>
+ <!-- Shown to ask the user to add a SIM. -->
+ <string name="keyguard_missing_sim_instructions">Add a SIM.</string>
+ <!-- Shown to ask the user to add a SIM when sim is missing or not readable. -->
+ <string name="keyguard_missing_sim_instructions_long">The SIM is missing or not readable. Add a SIM.</string>
+ <!-- Shown when SIM is permanently disabled. -->
+ <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM.</string>
+ <!-- Shown to inform the user to SIM is permanently deactivated. -->
+ <string name="keyguard_permanent_disabled_sim_instructions">Your SIM has been permanently deactivated.\n
+ Contact your wireless service provider for another SIM.</string>
<!-- Shown to tell the user that their SIM is locked and they must unlock it. -->
- <string name="keyguard_sim_locked_message">SIM card is locked.</string>
+ <string name="keyguard_sim_locked_message">SIM is locked.</string>
<!-- When the user enters a wrong sim pin too many times, it becomes PUK locked (Pin Unlock Kode) -->
- <string name="keyguard_sim_puk_locked_message">SIM card is PUK-locked.</string>
+ <string name="keyguard_sim_puk_locked_message">SIM is PUK-locked.</string>
<!-- For the unlock screen, When the user enters a sim unlock code, it takes a little while to check
whether it is valid, and to unlock the sim if it is valid. we display a
progress dialog in the meantime. this is the emssage. -->
- <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Composes together the carrier name and the SIM card locked message. Example: CarrierName (SIM LOCKED) -->
<string name="keyguard_carrier_name_with_sim_locked_template" translatable="false"><xliff:g id="carrier">%s</xliff:g> (<xliff:g id="message">%s</xliff:g>)</string>
@@ -139,8 +139,8 @@
<string name="kg_puk_enter_pin_hint">Enter desired PIN code</string>
<!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen -->
<string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
- <!-- Message shown in dialog while the device is unlocking the SIM card -->
- <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <!-- Message shown in dialog while the device is unlocking the SIM -->
+ <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM\u2026</string>
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
<string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
<!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index b71caef..75c8286 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -28,10 +28,10 @@
<!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
<string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string>
- <!-- Shown when there is no SIM card. -->
- <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message" product="tablet">No SIM in tablet.</string>
+ <!-- Shown when there is no SIM. -->
+ <string name="keyguard_missing_sim_message" product="default">No SIM in phone.</string>
<!-- String shown in PUK screen when PIN codes don't match -->
<string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index ded466a..2727c83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -23,8 +23,8 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.res.Configuration;
+import android.content.res.Configuration.Orientation;
import android.metrics.LogMaker;
-import android.util.Log;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
@@ -75,6 +75,7 @@
@Nullable
private Consumer<Boolean> mMediaVisibilityChangedListener;
+ @Orientation
private int mLastOrientation;
private String mCachedSpecs = "";
@Nullable
@@ -88,21 +89,16 @@
new QSPanel.OnConfigurationChangedListener() {
@Override
public void onConfigurationChange(Configuration newConfig) {
+ mQSLogger.logOnConfigurationChanged(
+ /* lastOrientation= */ mLastOrientation,
+ /* newOrientation= */ newConfig.orientation,
+ /* containerName= */ mView.getDumpableTag());
+
mShouldUseSplitNotificationShade =
- LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
- // Logging to aid the investigation of b/216244185.
- Log.d(TAG,
- "onConfigurationChange: "
- + "mShouldUseSplitNotificationShade="
- + mShouldUseSplitNotificationShade + ", "
- + "newConfig.windowConfiguration="
- + newConfig.windowConfiguration);
- mQSLogger.logOnConfigurationChanged(mLastOrientation, newConfig.orientation,
- mView.getDumpableTag());
- if (newConfig.orientation != mLastOrientation) {
- mLastOrientation = newConfig.orientation;
- switchTileLayout(false);
- }
+ LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+ mLastOrientation = newConfig.orientation;
+
+ switchTileLayoutIfNeeded();
onConfigurationChanged();
}
};
@@ -334,6 +330,10 @@
}
}
+ private void switchTileLayoutIfNeeded() {
+ switchTileLayout(/* force= */ false);
+ }
+
boolean switchTileLayout(boolean force) {
/* Whether or not the panel currently contains a media player. */
boolean horizontal = shouldUseHorizontalLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 76025ab7..0446165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -53,7 +53,9 @@
return true;
}
if (otherState instanceof ImageTransformState) {
- return mIcon != null && mIcon.sameAs(((ImageTransformState) otherState).getIcon());
+ final Icon otherIcon = ((ImageTransformState) otherState).mIcon;
+ return mIcon == otherIcon || (mIcon != null && otherIcon != null && mIcon.sameAs(
+ otherIcon));
}
return false;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 3cad2a0..b847ad0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -277,7 +277,7 @@
// Then the layout changes
assertThat(mController.shouldUseHorizontalLayout()).isTrue();
- verify(mHorizontalLayoutListener).run(); // not invoked
+ verify(mHorizontalLayoutListener).run();
// When it is rotated back to portrait
mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
@@ -300,4 +300,24 @@
verify(mQSTile).refreshState();
verify(mOtherTile, never()).refreshState();
}
+
+ @Test
+ public void configurationChange_onlySplitShadeConfigChanges_horizontalLayoutStatusUpdated() {
+ // Preconditions for horizontal layout
+ when(mMediaHost.getVisible()).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(false);
+ mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mController.setUsingHorizontalLayoutChangeListener(mHorizontalLayoutListener);
+ mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+ assertThat(mController.shouldUseHorizontalLayout()).isTrue();
+ reset(mHorizontalLayoutListener);
+
+ // Only split shade status changes
+ when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
+ mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+
+ // Horizontal layout is updated accordingly.
+ assertThat(mController.shouldUseHorizontalLayout()).isFalse();
+ verify(mHorizontalLayoutListener).run();
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2a4bcb0..1e9c3b7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -657,25 +657,27 @@
userState.mBindingServices.removeIf(filter);
userState.mCrashedServices.removeIf(filter);
final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
+ boolean anyServiceRemoved = false;
while (it.hasNext()) {
final ComponentName comp = it.next();
final String compPkg = comp.getPackageName();
if (compPkg.equals(packageName)) {
it.remove();
- // Update the enabled services setting.
- persistComponentNamesToSettingLocked(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- userState.mEnabledServices, userId);
- // Update the touch exploration granted services setting.
userState.mTouchExplorationGrantedServices.remove(comp);
- persistComponentNamesToSettingLocked(
- Settings.Secure.
- TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- userState.mTouchExplorationGrantedServices, userId);
- onUserStateChangedLocked(userState);
- return;
+ anyServiceRemoved = true;
}
}
+ if (anyServiceRemoved) {
+ // Update the enabled services setting.
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userState.mEnabledServices, userId);
+ // Update the touch exploration granted services setting.
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+ userState.mTouchExplorationGrantedServices, userId);
+ onUserStateChangedLocked(userState);
+ }
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 38237fa..34b7a8a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -573,12 +573,6 @@
}
}
- if (onClickIntent != null) {
- views.setOnClickPendingIntent(android.R.id.background,
- PendingIntent.getActivity(mContext, 0, onClickIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
- }
-
Icon icon = appInfo.icon != 0
? Icon.createWithResource(appInfo.packageName, appInfo.icon)
: Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
@@ -590,6 +584,12 @@
for (int j = 0; j < widgetCount; j++) {
Widget widget = provider.widgets.get(j);
if (targetWidget != null && targetWidget != widget) continue;
+ if (onClickIntent != null) {
+ views.setOnClickPendingIntent(android.R.id.background,
+ PendingIntent.getActivity(mContext, widget.appWidgetId, onClickIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_IMMUTABLE));
+ }
if (widget.replaceWithMaskedViewsLocked(views)) {
scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9268fc0..bf71e6b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -154,8 +154,8 @@
"android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.1-java",
- "android.hardware.tv.cec-V1-java",
- "android.hardware.tv.hdmi-V1-java",
+ "android.hardware.tv.hdmi.cec-V1-java",
+ "android.hardware.tv.hdmi.connection-V1-java",
"android.hardware.weaver-V1.0-java",
"android.hardware.biometrics.face-V1.0-java",
"android.hardware.biometrics.fingerprint-V2.3-java",
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 68fd0c1..9743ba4 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -223,8 +223,8 @@
# ---------------------------
# NetworkStatsService.java
# ---------------------------
-51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
-51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51100 netstats_mobile_sample (xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51101 netstats_wifi_sample (xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
# ---------------------------
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index ae50b23..2b43ef4 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -67,6 +68,7 @@
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
import com.android.server.net.LockdownVpnTracker;
+import com.android.server.pm.UserManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -93,6 +95,7 @@
private final INetworkManagementService mNMS;
private final INetd mNetd;
private final UserManager mUserManager;
+ private final int mMainUserId;
@VisibleForTesting
@GuardedBy("mVpns")
@@ -145,6 +148,12 @@
Vpn vpn, VpnProfile profile) {
return new LockdownVpnTracker(context, handler, vpn, profile);
}
+
+ /** Get the main user on the device. */
+ public @UserIdInt int getMainUserId() {
+ // TODO(b/265785220): Change to use UserManager method instead.
+ return LocalServices.getService(UserManagerInternal.class).getMainUserId();
+ }
}
public VpnManagerService(Context context, Dependencies deps) {
@@ -159,6 +168,7 @@
mNMS = mDeps.getINetworkManagementService();
mNetd = mDeps.getNetd();
mUserManager = mContext.getSystemService(UserManager.class);
+ mMainUserId = mDeps.getMainUserId();
registerReceivers();
log("VpnManagerService starting up");
}
@@ -478,11 +488,12 @@
@Override
public boolean updateLockdownVpn() {
- // Allow the system UID for the system server and for Settings.
+ // Allow the system UID for the system server and for Settings (from user 0 or main user).
// Also, for unit tests, allow the process that ConnectivityService is running in.
if (mDeps.getCallingUid() != Process.SYSTEM_UID
+ && mDeps.getCallingUid() != UserHandle.getUid(mMainUserId, Process.SYSTEM_UID)
&& Binder.getCallingPid() != Process.myPid()) {
- logw("Lockdown VPN only available to system process or AID_SYSTEM");
+ logw("Lockdown VPN only available to system process or AID_SYSTEM on main user");
return false;
}
@@ -697,7 +708,7 @@
intentFilter,
null /* broadcastPermission */,
mHandler);
- mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+ mContext.createContextAsUser(UserHandle.of(mMainUserId), 0 /* flags */).registerReceiver(
mUserPresentReceiver,
new IntentFilter(Intent.ACTION_USER_PRESENT),
null /* broadcastPermission */,
@@ -735,6 +746,7 @@
if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
onVpnLockdownReset();
+ return;
}
// UserId should be filled for below intents, check the existence.
@@ -795,7 +807,7 @@
userVpn = mDeps.createVpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId);
mVpns.put(userId, userVpn);
- if (user.isPrimary() && isLockdownVpnEnabled()) {
+ if (userId == mMainUserId && isLockdownVpnEnabled()) {
updateLockdownVpn();
}
}
@@ -910,15 +922,9 @@
}
private void onUserUnlocked(int userId) {
- UserInfo user = mUserManager.getUserInfo(userId);
- if (user == null) {
- logw("Unlocked user doesn't exist. UserId: " + userId);
- return;
- }
-
synchronized (mVpns) {
// User present may be sent because of an unlock, which might mean an unlocked keystore.
- if (user.isPrimary() && isLockdownVpnEnabled()) {
+ if (userId == mMainUserId && isLockdownVpnEnabled()) {
updateLockdownVpn();
} else {
startAlwaysOnVpn(userId);
@@ -984,7 +990,7 @@
}
// Turn Always-on VPN off
- if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
+ if (mLockdownEnabled && userId == mMainUserId) {
final long ident = Binder.clearCallingIdentity();
try {
mVpnProfileStore.remove(Credentials.LOCKDOWN_VPN);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 75e30e5..6bd036b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13529,7 +13529,7 @@
}
} else {
BroadcastFilter bf = (BroadcastFilter)target;
- if (bf.requiredPermission == null) {
+ if (bf.exported && bf.requiredPermission == null) {
allProtected = false;
break;
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index da209f0..5cdcd42 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -41,3 +41,5 @@
# Multiuser
per-file User* = file:/MULTIUSER_OWNERS
+# Broadcasts
+per-file Broadcast* = file:/BROADCASTS_OWNERS
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bc939d6..4afaca2f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2428,7 +2428,7 @@
}
state.setCurRawAdj(adj);
-
+ adj = psr.modifyRawOomAdj(adj);
if (adj > state.getMaxAdj()) {
adj = state.getMaxAdj();
if (adj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
@@ -2458,7 +2458,7 @@
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
- state.setCurAdj(psr.modifyRawOomAdj(adj));
+ state.setCurAdj(adj);
state.setCurCapability(capability);
state.setCurrentSchedulingGroup(schedGroup);
state.setCurProcState(procState);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index bda60ff..8624ee0 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -379,11 +379,16 @@
resolvedType = key.requestResolvedType;
}
- // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
- // can specify a consistent launch mode even if the PendingIntent is immutable
+ // Apply any launch flags from the ActivityOptions. This is used only by SystemUI
+ // to ensure that we can launch the pending intent with a consistent launch mode even
+ // if the provided PendingIntent is immutable (ie. to force an activity to launch into
+ // a new task, or to launch multiple instances if supported by the app)
final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
- finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ // TODO(b/254490217): Move this check into SafeActivityOptions
+ if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) {
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ }
}
// Extract options before clearing calling identity
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 8886f0a..b8ff26e 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -98,7 +98,6 @@
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
DeviceConfig.NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT,
DeviceConfig.NAMESPACE_SWCODEC_NATIVE,
- DeviceConfig.NAMESPACE_TETHERING,
DeviceConfig.NAMESPACE_VENDOR_SYSTEM_NATIVE,
DeviceConfig.NAMESPACE_VENDOR_SYSTEM_NATIVE_BOOT,
DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 01afd18..e0d324a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -124,6 +124,8 @@
import android.media.audiopolicy.AudioProductStrategy;
import android.media.audiopolicy.AudioVolumeGroup;
import android.media.audiopolicy.IAudioPolicyCallback;
+import android.media.permission.ClearCallingIdentityContext;
+import android.media.permission.SafeCloseable;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionManager;
@@ -11047,6 +11049,33 @@
}
}
+ /** @see AudioManager#supportsBluetoothVariableLatency() */
+ @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean supportsBluetoothVariableLatency() {
+ super.supportsBluetoothVariableLatency_enforcePermission();
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ return AudioSystem.supportsBluetoothVariableLatency();
+ }
+ }
+
+ /** @see AudioManager#setBluetoothVariableLatencyEnabled(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void setBluetoothVariableLatencyEnabled(boolean enabled) {
+ super.setBluetoothVariableLatencyEnabled_enforcePermission();
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ AudioSystem.setBluetoothVariableLatencyEnabled(enabled);
+ }
+ }
+
+ /** @see AudioManager#isBluetoothVariableLatencyEnabled(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean isBluetoothVariableLatencyEnabled() {
+ super.isBluetoothVariableLatencyEnabled_enforcePermission();
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ return AudioSystem.isBluetoothVariableLatencyEnabled();
+ }
+ }
+
private final Object mExtVolumeControllerLock = new Object();
private IAudioPolicyCallback mExtVolumeController;
private void setExtVolumeController(IAudioPolicyCallback apc) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index bf0052d..dbba9ee 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -19,16 +19,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiPortInfo;
-import android.hardware.tv.cec.CecMessage;
-import android.hardware.tv.cec.IHdmiCec;
-import android.hardware.tv.cec.IHdmiCecCallback;
import android.hardware.tv.cec.V1_0.HotplugEvent;
import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback;
import android.hardware.tv.cec.V1_0.OptionKey;
import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.hardware.tv.hdmi.IHdmi;
-import android.hardware.tv.hdmi.IHdmiCallback;
+import android.hardware.tv.hdmi.cec.CecMessage;
+import android.hardware.tv.hdmi.cec.IHdmiCec;
+import android.hardware.tv.hdmi.cec.IHdmiCecCallback;
+import android.hardware.tv.hdmi.connection.IHdmiConnection;
+import android.hardware.tv.hdmi.connection.IHdmiConnectionCallback;
import android.icu.util.IllformedLocaleException;
import android.icu.util.ULocale;
import android.os.Binder;
@@ -178,7 +178,7 @@
if (controller != null) {
return controller;
}
- HdmiLogger.warning("Unable to use CEC and HDMI AIDL HALs");
+ HdmiLogger.warning("Unable to use CEC and HDMI Connection AIDL HALs");
controller = createWithNativeWrapper(service, new NativeWrapperImpl11(), atomWriter);
if (controller != null) {
@@ -872,14 +872,14 @@
private static final class NativeWrapperImplAidl
implements NativeWrapper, IBinder.DeathRecipient {
private IHdmiCec mHdmiCec;
- private IHdmi mHdmi;
+ private IHdmiConnection mHdmiConnection;
@Nullable private HdmiCecCallback mCallback;
private final Object mLock = new Object();
@Override
public String nativeInit() {
- return connectToHal() ? mHdmiCec.toString() + " " + mHdmi.toString() : null;
+ return connectToHal() ? mHdmiCec.toString() + " " + mHdmiConnection.toString() : null;
}
boolean connectToHal() {
@@ -896,15 +896,15 @@
HdmiLogger.error("Couldn't link to death : ", e);
}
- mHdmi =
- IHdmi.Stub.asInterface(
- ServiceManager.getService(IHdmi.DESCRIPTOR + "/default"));
- if (mHdmi == null) {
- HdmiLogger.error("Could not initialize HDMI AIDL HAL");
+ mHdmiConnection =
+ IHdmiConnection.Stub.asInterface(
+ ServiceManager.getService(IHdmiConnection.DESCRIPTOR + "/default"));
+ if (mHdmiConnection == null) {
+ HdmiLogger.error("Could not initialize HDMI Connection AIDL HAL");
return false;
}
try {
- mHdmi.asBinder().linkToDeath(this, 0);
+ mHdmiConnection.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
HdmiLogger.error("Couldn't link to death : ", e);
}
@@ -915,8 +915,8 @@
public void binderDied() {
// One of the services died, try to reconnect to both.
mHdmiCec.asBinder().unlinkToDeath(this, 0);
- mHdmi.asBinder().unlinkToDeath(this, 0);
- HdmiLogger.error("HDMI or CEC service died, reconnecting");
+ mHdmiConnection.asBinder().unlinkToDeath(this, 0);
+ HdmiLogger.error("HDMI Connection or CEC service died, reconnecting");
connectToHal();
// Reconnect the callback
if (mCallback != null) {
@@ -935,7 +935,7 @@
}
try {
// Create an AIDL callback that can callback onHotplugEvent
- mHdmi.setCallback(new HdmiCallbackAidl(callback));
+ mHdmiConnection.setCallback(new HdmiConnectionCallbackAidl(callback));
} catch (RemoteException e) {
HdmiLogger.error("Couldn't initialise tv.hdmi callback : ", e);
}
@@ -1052,10 +1052,11 @@
@Override
public HdmiPortInfo[] nativeGetPortInfos() {
try {
- android.hardware.tv.hdmi.HdmiPortInfo[] hdmiPortInfos = mHdmi.getPortInfo();
+ android.hardware.tv.hdmi.connection.HdmiPortInfo[] hdmiPortInfos =
+ mHdmiConnection.getPortInfo();
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.length];
int i = 0;
- for (android.hardware.tv.hdmi.HdmiPortInfo portInfo : hdmiPortInfos) {
+ for (android.hardware.tv.hdmi.connection.HdmiPortInfo portInfo : hdmiPortInfos) {
hdmiPortInfo[i] =
new HdmiPortInfo(
portInfo.portId,
@@ -1076,7 +1077,7 @@
@Override
public boolean nativeIsConnected(int port) {
try {
- return mHdmi.isConnected(port);
+ return mHdmiConnection.isConnected(port);
} catch (RemoteException e) {
HdmiLogger.error("Failed to get connection info : ", e);
return false;
@@ -1580,10 +1581,10 @@
}
}
- private static final class HdmiCallbackAidl extends IHdmiCallback.Stub {
+ private static final class HdmiConnectionCallbackAidl extends IHdmiConnectionCallback.Stub {
private final HdmiCecCallback mHdmiCecCallback;
- HdmiCallbackAidl(HdmiCecCallback hdmiCecCallback) {
+ HdmiConnectionCallbackAidl(HdmiCecCallback hdmiCecCallback) {
mHdmiCecCallback = hdmiCecCallback;
}
@@ -1594,12 +1595,12 @@
@Override
public synchronized String getInterfaceHash() throws android.os.RemoteException {
- return IHdmiCallback.Stub.HASH;
+ return IHdmiConnectionCallback.Stub.HASH;
}
@Override
public int getInterfaceVersion() throws android.os.RemoteException {
- return IHdmiCallback.Stub.VERSION;
+ return IHdmiConnectionCallback.Stub.VERSION;
}
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 4d525da..9b42cfc 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -36,6 +36,7 @@
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -103,12 +104,12 @@
/**
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
- * <p>
- * If the delta between the current boot number and the boot number stored when the mechanism
+ *
+ * <p>If the delta between the current boot number and the boot number stored when the mechanism
* was armed is under this number and the escrow mechanism fails, we report it as a failure of
* the mechanism.
- * <p>
- * If the delta over this number and escrow fails, we will not report the metric as failed
+ *
+ * <p>If the delta over this number and escrow fails, we will not report the metric as failed
* since there most likely was some other issue if the device rebooted several times before
* getting to the escrow restore code.
*/
@@ -120,8 +121,11 @@
*/
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+
// 3 minutes. It's enough for the default 3 retries with 30 seconds interval
- private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS = 180_000;
+ private static final int DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS = 180_000;
+ // 5 seconds. An extension of the overall RoR timeout to account for overhead.
+ private static final int DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS = 5000;
@IntDef(prefix = {"ERROR_"}, value = {
ERROR_NONE,
@@ -133,6 +137,7 @@
ERROR_PROVIDER_MISMATCH,
ERROR_KEYSTORE_FAILURE,
ERROR_NO_NETWORK,
+ ERROR_TIMEOUT_EXHAUSTED,
})
@Retention(RetentionPolicy.SOURCE)
@interface RebootEscrowErrorCode {
@@ -147,6 +152,7 @@
static final int ERROR_PROVIDER_MISMATCH = 6;
static final int ERROR_KEYSTORE_FAILURE = 7;
static final int ERROR_NO_NETWORK = 8;
+ static final int ERROR_TIMEOUT_EXHAUSTED = 9;
private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
@@ -168,6 +174,15 @@
/** Notified when mRebootEscrowReady changes. */
private RebootEscrowListener mRebootEscrowListener;
+ /** Set when unlocking reboot escrow times out. */
+ private boolean mRebootEscrowTimedOut = false;
+
+ /**
+ * Set when {@link #loadRebootEscrowDataWithRetry} is called to ensure the function is only
+ * called once.
+ */
+ private boolean mLoadEscrowDataWithRetry = false;
+
/**
* Hold this lock when checking or generating the reboot escrow key.
*/
@@ -192,6 +207,7 @@
PowerManager.WakeLock mWakeLock;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
interface Callbacks {
boolean isUserSecure(int userId);
@@ -246,6 +262,11 @@
"server_based_ror_enabled", false);
}
+ public boolean waitForInternet() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
+ }
+
public boolean isNetworkConnected() {
final ConnectivityManager connectivityManager =
mContext.getSystemService(ConnectivityManager.class);
@@ -263,6 +284,38 @@
NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
+ /**
+ * Request network with internet connectivity with timeout.
+ *
+ * @param networkCallback callback to be executed if connectivity manager exists.
+ * @return true if success
+ */
+ public boolean requestNetworkWithInternet(
+ ConnectivityManager.NetworkCallback networkCallback) {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return false;
+ }
+ NetworkRequest request =
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+
+ connectivityManager.requestNetwork(
+ request, networkCallback, getLoadEscrowTimeoutMillis());
+ return true;
+ }
+
+ public void stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback) {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return;
+ }
+ connectivityManager.unregisterNetworkCallback(networkCallback);
+ }
+
public Context getContext() {
return mContext;
}
@@ -318,6 +371,16 @@
DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
}
+ @VisibleForTesting
+ public int getLoadEscrowTimeoutMillis() {
+ return DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS;
+ }
+
+ @VisibleForTesting
+ public int getWakeLockTimeoutMillis() {
+ return getLoadEscrowTimeoutMillis() + DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS;
+ }
+
public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus,
int durationSinceBootCompleteInSeconds) {
@@ -351,13 +414,37 @@
mKeyStoreManager = injector.getKeyStoreManager();
}
- private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) {
+ /** Wrapper function to set error code serialized through handler, */
+ private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
+ if (mInjector.waitForInternet()) {
+ mInjector.post(
+ handler,
+ () -> {
+ mLoadEscrowDataErrorCode = value;
+ });
+ } else {
+ mLoadEscrowDataErrorCode = value;
+ }
+ }
+
+ /** Wrapper function to compare and set error code serialized through handler. */
+ private void compareAndSetLoadEscrowDataErrorCode(
+ @RebootEscrowErrorCode int expectedValue,
+ @RebootEscrowErrorCode int newValue,
+ Handler handler) {
+ if (expectedValue == mLoadEscrowDataErrorCode) {
+ setLoadEscrowDataErrorCode(newValue, handler);
+ }
+ }
+
+ private void onGetRebootEscrowKeyFailed(
+ List<UserInfo> users, int attemptCount, Handler retryHandler) {
Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
for (UserInfo user : users) {
mStorage.removeRebootEscrow(user.id);
}
- onEscrowRestoreComplete(false, attemptCount);
+ onEscrowRestoreComplete(false, attemptCount, retryHandler);
}
void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
@@ -380,39 +467,130 @@
mWakeLock = mInjector.getWakeLock();
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(false);
- mWakeLock.acquire(DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS);
+ mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
+ }
+
+ if (mInjector.waitForInternet()) {
+ // Timeout to stop retrying same as the wake lock timeout.
+ mInjector.postDelayed(
+ retryHandler,
+ () -> {
+ mRebootEscrowTimedOut = true;
+ },
+ mInjector.getLoadEscrowTimeoutMillis());
+
+ mInjector.post(
+ retryHandler,
+ () -> loadRebootEscrowDataOnInternet(retryHandler, users, rebootEscrowUsers));
+ return;
}
mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
retryHandler, 0, users, rebootEscrowUsers));
}
- void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
- List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ void scheduleLoadRebootEscrowDataOrFail(
+ Handler retryHandler,
+ int attemptNumber,
+ List<UserInfo> users,
+ List<UserInfo> rebootEscrowUsers) {
Objects.requireNonNull(retryHandler);
final int retryLimit = mInjector.getLoadEscrowDataRetryLimit();
final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds();
- if (attemptNumber < retryLimit) {
+ if (attemptNumber < retryLimit && !mRebootEscrowTimedOut) {
Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
- retryHandler, attemptNumber, users, rebootEscrowUsers),
+ retryHandler, attemptNumber, users, rebootEscrowUsers),
retryIntervalInSeconds * 1000);
return;
}
+ if (mInjector.waitForInternet()) {
+ if (mRebootEscrowTimedOut) {
+ Slog.w(TAG, "Failed to load reboot escrow data within timeout");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_TIMEOUT_EXHAUSTED, retryHandler);
+ } else {
+ Slog.w(
+ TAG,
+ "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_RETRY_COUNT_EXHAUSTED, retryHandler);
+ }
+ onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
+ return;
+ }
+
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
} else {
mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
}
- onGetRebootEscrowKeyFailed(users, attemptNumber);
+ onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
}
- void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
- List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ void loadRebootEscrowDataOnInternet(
+ Handler retryHandler, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+
+ // HAL-Based RoR does not require network connectivity.
+ if (!mInjector.serverBasedResumeOnReboot()) {
+ loadRebootEscrowDataWithRetry(
+ retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
+ return;
+ }
+
+ mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NO_NETWORK, ERROR_NONE, retryHandler);
+
+ if (!mLoadEscrowDataWithRetry) {
+ mLoadEscrowDataWithRetry = true;
+ // Only kickoff retry mechanism on first onAvailable call.
+ loadRebootEscrowDataWithRetry(
+ retryHandler,
+ /* attemptNumber = */ 0,
+ users,
+ rebootEscrowUsers);
+ }
+ }
+
+ @Override
+ public void onUnavailable() {
+ Slog.w(TAG, "Failed to connect to network within timeout");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
+ onGetRebootEscrowKeyFailed(users, /* attemptCount= */ 0, retryHandler);
+ }
+
+ @Override
+ public void onLost(Network lostNetwork) {
+ // TODO(b/231660348): If network is lost, wait for network to become
+ // available again.
+ Slog.w(TAG, "Network lost, still attempting to load escrow key.");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
+ }
+ };
+
+ // Fallback to retrying without waiting for internet on failure.
+ boolean success = mInjector.requestNetworkWithInternet(mNetworkCallback);
+ if (!success) {
+ loadRebootEscrowDataWithRetry(
+ retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
+ }
+ }
+
+ void loadRebootEscrowDataWithRetry(
+ Handler retryHandler,
+ int attemptNumber,
+ List<UserInfo> users,
+ List<UserInfo> rebootEscrowUsers) {
// Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
// generated before reboot. Note that we will clear the escrow key even if the keystore key
// is null.
@@ -423,7 +601,7 @@
RebootEscrowKey escrowKey;
try {
- escrowKey = getAndClearRebootEscrowKey(kk);
+ escrowKey = getAndClearRebootEscrowKey(kk, retryHandler);
} catch (IOException e) {
Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e);
scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
@@ -438,12 +616,12 @@
? RebootEscrowProviderInterface.TYPE_SERVER_BASED
: RebootEscrowProviderInterface.TYPE_HAL;
if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
- mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH;
+ setLoadEscrowDataErrorCode(ERROR_PROVIDER_MISMATCH, retryHandler);
} else {
- mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY;
+ setLoadEscrowDataErrorCode(ERROR_LOAD_ESCROW_KEY, retryHandler);
}
}
- onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
+ onGetRebootEscrowKeyFailed(users, attemptNumber + 1, retryHandler);
return;
}
@@ -454,10 +632,10 @@
allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
}
- if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
- mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
+ if (!allUsersUnlocked) {
+ compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNLOCK_ALL_USERS, retryHandler);
}
- onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
+ onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1, retryHandler);
}
private void clearMetricsStorage() {
@@ -497,7 +675,8 @@
.REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
}
- private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
+ private void reportMetricOnRestoreComplete(
+ boolean success, int attemptCount, Handler retryHandler) {
int serviceType = mInjector.serverBasedResumeOnReboot()
? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
: FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
@@ -511,52 +690,69 @@
}
int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
- if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
- mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
+ if (!success) {
+ compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNKNOWN, retryHandler);
}
- Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
- + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
+ Slog.i(
+ TAG,
+ "Reporting RoR recovery metrics, success: "
+ + success
+ + ", service type: "
+ + serviceType
+ + ", error code: "
+ + mLoadEscrowDataErrorCode);
// TODO(179105110) report the duration since boot complete.
- mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
- escrowDurationInSeconds, vbmetaDigestStatus, -1);
+ mInjector.reportMetric(
+ success,
+ mLoadEscrowDataErrorCode,
+ serviceType,
+ attemptCount,
+ escrowDurationInSeconds,
+ vbmetaDigestStatus,
+ -1);
- mLoadEscrowDataErrorCode = ERROR_NONE;
+ setLoadEscrowDataErrorCode(ERROR_NONE, retryHandler);
}
- private void onEscrowRestoreComplete(boolean success, int attemptCount) {
+ private void onEscrowRestoreComplete(boolean success, int attemptCount, Handler retryHandler) {
int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
- reportMetricOnRestoreComplete(success, attemptCount);
+ reportMetricOnRestoreComplete(success, attemptCount, retryHandler);
}
-
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
// Clear the saved reboot escrow provider
mInjector.clearRebootEscrowProvider();
clearMetricsStorage();
+ if (mNetworkCallback != null) {
+ mInjector.stopRequestingNetwork(mNetworkCallback);
+ }
+
if (mWakeLock != null) {
mWakeLock.release();
}
}
- private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
+ private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk, Handler retryHandler)
+ throws IOException {
RebootEscrowProviderInterface rebootEscrowProvider =
mInjector.createRebootEscrowProviderIfNeeded();
if (rebootEscrowProvider == null) {
- Slog.w(TAG,
+ Slog.w(
+ TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER;
+ setLoadEscrowDataErrorCode(ERROR_NO_PROVIDER, retryHandler);
return null;
}
// Server based RoR always need the decryption key from keystore.
if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
&& kk == null) {
- mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE;
+ setLoadEscrowDataErrorCode(ERROR_KEYSTORE_FAILURE, retryHandler);
return null;
}
@@ -870,6 +1066,9 @@
pw.print("mRebootEscrowListener=");
pw.println(mRebootEscrowListener);
+ pw.print("mLoadEscrowDataErrorCode=");
+ pw.println(mLoadEscrowDataErrorCode);
+
boolean keySet;
synchronized (mKeyGenerationLock) {
keySet = mPendingRebootEscrowKey != null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 4a0a07b..dc8fcb0 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -94,7 +94,7 @@
void networkBlocked(int uid, @Nullable UidBlockedState uidBlockedState) {
synchronized (mLock) {
if (LOGD || uid == mDebugUid) {
- Slog.d(TAG, "Blocked state of " + uid + ": " + uidBlockedState.toString());
+ Slog.d(TAG, "Blocked state of " + uid + ": " + uidBlockedState);
}
if (uidBlockedState == null) {
mNetworkBlockedBuffer.networkBlocked(uid, BLOCKED_REASON_NONE, ALLOWED_REASON_NONE,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7468d32..b6bdd4c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1977,34 +1977,39 @@
return (haystack & needle) != 0;
}
- public boolean isInLockDownMode() {
- return mIsInLockDownMode;
+ // Return whether the user is in lockdown mode.
+ // If the flag is not set, we assume the user is not in lockdown.
+ public boolean isInLockDownMode(int userId) {
+ return mUserInLockDownMode.get(userId, false);
}
@Override
public synchronized void onStrongAuthRequiredChanged(int userId) {
boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
- mUserInLockDownMode.put(userId, userInLockDownModeNext);
- boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
- if (mIsInLockDownMode == isInLockDownModeNext) {
+ // Nothing happens if the lockdown mode of userId keeps the same.
+ if (userInLockDownModeNext == isInLockDownMode(userId)) {
return;
}
- if (isInLockDownModeNext) {
- cancelNotificationsWhenEnterLockDownMode();
+ // When the lockdown mode is changed, we perform the following steps.
+ // If the userInLockDownModeNext is true, all the function calls to
+ // notifyPostedLocked and notifyRemovedLocked will not be executed.
+ // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked
+ // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked.
+ // So we shall call cancelNotificationsWhenEnterLockDownMode before
+ // we set mUserInLockDownMode as true.
+ // On the other hand, if the userInLockDownModeNext is false, we shall call
+ // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode
+ if (userInLockDownModeNext) {
+ cancelNotificationsWhenEnterLockDownMode(userId);
}
- // When the mIsInLockDownMode is true, both notifyPostedLocked and
- // notifyRemovedLocked will be dismissed. So we shall call
- // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
- // as true and call postNotificationsWhenExitLockDownMode after we set
- // mIsInLockDownMode as false.
- mIsInLockDownMode = isInLockDownModeNext;
+ mUserInLockDownMode.put(userId, userInLockDownModeNext);
- if (!isInLockDownModeNext) {
- postNotificationsWhenExitLockDownMode();
+ if (!userInLockDownModeNext) {
+ postNotificationsWhenExitLockDownMode(userId);
}
}
}
@@ -4953,16 +4958,7 @@
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- // If the caller is system, take the package name from the rule's owner rather than
- // from the caller's package.
- String rulePkg = pkg;
- if (isCallingUidSystem()) {
- if (automaticZenRule.getOwner() != null) {
- rulePkg = automaticZenRule.getOwner().getPackageName();
- }
- }
-
- return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
+ return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
"addAutomaticZenRule");
}
@@ -9713,11 +9709,14 @@
}
}
- private void cancelNotificationsWhenEnterLockDownMode() {
+ private void cancelNotificationsWhenEnterLockDownMode(int userId) {
synchronized (mNotificationLock) {
int numNotifications = mNotificationList.size();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
+ if (rec.getUser().getIdentifier() != userId) {
+ continue;
+ }
mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
rec.getStats());
}
@@ -9725,14 +9724,23 @@
}
}
- private void postNotificationsWhenExitLockDownMode() {
+ private void postNotificationsWhenExitLockDownMode(int userId) {
synchronized (mNotificationLock) {
int numNotifications = mNotificationList.size();
+ // Set the delay to spread out the burst of notifications.
+ long delay = 0;
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
- mListeners.notifyPostedLocked(rec, rec);
+ if (rec.getUser().getIdentifier() != userId) {
+ continue;
+ }
+ mHandler.postDelayed(() -> {
+ synchronized (mNotificationLock) {
+ mListeners.notifyPostedLocked(rec, rec);
+ }
+ }, delay);
+ delay += 20;
}
-
}
}
@@ -9911,6 +9919,9 @@
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
+ if (isInLockDownMode(record.getUser().getIdentifier())) {
+ continue;
+ }
if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) {
continue;
}
@@ -9952,8 +9963,8 @@
rankings.toArray(new NotificationListenerService.Ranking[0]));
}
- boolean isInLockDownMode() {
- return mStrongAuthTracker.isInLockDownMode();
+ boolean isInLockDownMode(int userId) {
+ return mStrongAuthTracker.isInLockDownMode(userId);
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
@@ -11015,7 +11026,7 @@
@GuardedBy("mNotificationLock")
void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
- if (isInLockDownMode()) {
+ if (isInLockDownMode(r.getUser().getIdentifier())) {
return;
}
@@ -11121,7 +11132,7 @@
@GuardedBy("mNotificationLock")
public void notifyRemovedLocked(NotificationRecord r, int reason,
NotificationStats notificationStats) {
- if (isInLockDownMode()) {
+ if (isInLockDownMode(r.getUser().getIdentifier())) {
return;
}
@@ -11170,10 +11181,6 @@
*/
@GuardedBy("mNotificationLock")
public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
- if (isInLockDownMode()) {
- return;
- }
-
boolean isHiddenRankingUpdate = changedHiddenNotifications != null
&& changedHiddenNotifications.size() > 0;
// TODO (b/73052211): if the ranking update changed the notification type,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 4c23ab8..d426679 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -326,7 +326,7 @@
public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
String reason) {
- if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
+ if (!isSystemRule(automaticZenRule)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
component = getActivityInfo(automaticZenRule.getConfigurationActivity());
@@ -582,6 +582,11 @@
}
}
+ private boolean isSystemRule(AutomaticZenRule rule) {
+ return rule.getOwner() != null
+ && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
+ }
+
private ServiceInfo getServiceInfo(ComponentName owner) {
Intent queryIntent = new Intent();
queryIntent.setComponent(owner);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index e411880..e7b1517 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -572,11 +572,14 @@
size += getDirectorySize(path);
if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
- path = Paths.get(splitSourceDir).toFile();
- if (path.isFile()) {
- path = path.getParentFile();
+ File pathSplitSourceDir = Paths.get(splitSourceDir).toFile();
+ if (pathSplitSourceDir.isFile()) {
+ pathSplitSourceDir = pathSplitSourceDir.getParentFile();
}
- size += getDirectorySize(path);
+ if (path.getAbsolutePath().equals(pathSplitSourceDir.getAbsolutePath())) {
+ continue;
+ }
+ size += getDirectorySize(pathSplitSourceDir);
}
}
return size;
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 8dc9428..cc58e5c 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -305,4 +305,10 @@
* for users that already existed on-disk from an older version of Android.
*/
public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
+
+ /**
+ * Returns the user id of the main user, or {@link android.os.UserHandle#USER_NULL} if there is
+ * no main user.
+ */
+ public abstract @UserIdInt int getMainUserId();
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b3dcf72..0a465e9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -6359,6 +6359,11 @@
return userData != null && userData.getIgnorePrepareStorageErrors();
}
}
+
+ @Override
+ public @UserIdInt int getMainUserId() {
+ return UserHandle.USER_SYSTEM;
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 1407530..e056151 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -298,7 +298,9 @@
dexMetadataType,
apkType,
ISA_MAP.getOrDefault(isa,
- ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
+ ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN),
+ ArtStatsLog.ART_DATUM_REPORTED__GC__ART_GC_COLLECTOR_TYPE_UNKNOWN,
+ ArtStatsLog.ART_DATUM_REPORTED__UFFD_SUPPORT__ART_UFFD_SUPPORT_UNKNOWN);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 014d580..554e269 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -644,8 +644,8 @@
Permission bp = mRegistry.getPermission(info.name);
added = bp == null;
int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+ enforcePermissionCapLocked(info, tree);
if (added) {
- enforcePermissionCapLocked(info, tree);
bp = new Permission(info.name, tree.getPackageName(), Permission.TYPE_DYNAMIC);
} else if (!bp.isDynamic()) {
throw new SecurityException("Not allowed to modify non-dynamic permission "
@@ -2136,6 +2136,46 @@
}
/**
+ * If the package was below api 23, got the SYSTEM_ALERT_WINDOW permission automatically, and
+ * then updated past api 23, and the app does not satisfy any of the other SAW permission flags,
+ * the permission should be revoked.
+ *
+ * @param newPackage The new package that was installed
+ * @param oldPackage The old package that was updated
+ */
+ private void revokeSystemAlertWindowIfUpgradedPast23(
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage) {
+ if (oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.M
+ || newPackage.getTargetSdkVersion() < Build.VERSION_CODES.M
+ || !newPackage.getRequestedPermissions()
+ .contains(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
+ return;
+ }
+
+ Permission saw;
+ synchronized (mLock) {
+ saw = mRegistry.getPermission(Manifest.permission.SYSTEM_ALERT_WINDOW);
+ }
+ final PackageStateInternal ps =
+ mPackageManagerInt.getPackageStateInternal(newPackage.getPackageName());
+ if (shouldGrantPermissionByProtectionFlags(newPackage, ps, saw, new ArraySet<>())
+ || shouldGrantPermissionBySignature(newPackage, saw)) {
+ return;
+ }
+ for (int userId : getAllUserIds()) {
+ try {
+ revokePermissionFromPackageForUser(newPackage.getPackageName(),
+ Manifest.permission.SYSTEM_ALERT_WINDOW, false, userId,
+ mDefaultPermissionCallback);
+ } catch (IllegalStateException | SecurityException e) {
+ Log.e(TAG, "unable to revoke SYSTEM_ALERT_WINDOW for "
+ + newPackage.getPackageName() + " user " + userId, e);
+ }
+ }
+ }
+
+ /**
* We might auto-grant permissions if any permission of the group is already granted. Hence if
* the group of a granted permission changes we need to revoke it to avoid having permissions of
* the new group auto-granted.
@@ -4661,6 +4701,7 @@
if (hasOldPkg) {
revokeRuntimePermissionsIfGroupChangedInternal(pkg, oldPkg);
revokeStoragePermissionsIfScopeExpandedInternal(pkg, oldPkg);
+ revokeSystemAlertWindowIfUpgradedPast23(pkg, oldPkg);
}
if (hasPermissionDefinitionChanges) {
revokeRuntimePermissionsIfPermissionDefinitionChangedInternal(
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ed4ba0d..7f8f406 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3202,8 +3202,7 @@
}
final PowerGroup powerGroup = mPowerGroups.get(groupId);
wakefulness = powerGroup.getWakefulnessLocked();
- if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
- powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
+ if (powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup);
powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false);
} else {
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index f973f5c..8068c6f 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -249,7 +249,7 @@
targetDir.mkdirs();
File targetFile = new File(targetDir, sourceFile.getName());
- boolean fallbackToCopy = !isLinkPossible(sourceFile, targetFile);
+ boolean fallbackToCopy = !isLinkPossible(sourceFile, targetDir);
if (!fallbackToCopy) {
try {
// Create a hard link to avoid copy
diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
index 5c2d5ba..5bcc98b6 100644
--- a/services/core/java/com/android/server/security/OWNERS
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 36824
per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS
-per-file FileIntegrityService.java = victorhsieh@google.com
+per-file FileIntegrity*.java = victorhsieh@google.com
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
index 868f34b..0e92709 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -21,10 +21,12 @@
import android.os.OutcomeReceiver;
import android.security.rkp.IGetKeyCallback;
import android.security.rkp.IRegistration;
+import android.security.rkp.IStoreUpgradedKeyCallback;
import android.security.rkp.service.RegistrationProxy;
import android.security.rkp.service.RemotelyProvisionedKey;
import android.util.Log;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -36,8 +38,10 @@
*/
final class RemoteProvisioningRegistration extends IRegistration.Stub {
static final String TAG = RemoteProvisioningService.TAG;
- private final ConcurrentHashMap<IGetKeyCallback, CancellationSignal> mOperations =
+ private final ConcurrentHashMap<IGetKeyCallback, CancellationSignal> mGetKeyOperations =
new ConcurrentHashMap<>();
+ private final Set<IStoreUpgradedKeyCallback> mStoreUpgradedKeyOperations =
+ ConcurrentHashMap.newKeySet();
private final RegistrationProxy mRegistration;
private final Executor mExecutor;
@@ -49,7 +53,7 @@
@Override
public void onResult(RemotelyProvisionedKey result) {
- mOperations.remove(mCallback);
+ mGetKeyOperations.remove(mCallback);
Log.i(TAG, "Successfully fetched key for client " + mCallback.hashCode());
android.security.rkp.RemotelyProvisionedKey parcelable =
new android.security.rkp.RemotelyProvisionedKey();
@@ -60,7 +64,7 @@
@Override
public void onError(Exception e) {
- mOperations.remove(mCallback);
+ mGetKeyOperations.remove(mCallback);
if (e instanceof OperationCanceledException) {
Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
wrapCallback(mCallback::onCancel);
@@ -79,7 +83,7 @@
@Override
public void getKey(int keyId, IGetKeyCallback callback) {
CancellationSignal cancellationSignal = new CancellationSignal();
- if (mOperations.putIfAbsent(callback, cancellationSignal) != null) {
+ if (mGetKeyOperations.putIfAbsent(callback, cancellationSignal) != null) {
Log.e(TAG, "Client can only request one call at a time " + callback.hashCode());
throw new IllegalArgumentException(
"Callback is already associated with an existing operation: "
@@ -92,14 +96,14 @@
new GetKeyReceiver(callback));
} catch (Exception e) {
Log.e(TAG, "getKeyAsync threw an exception for client " + callback.hashCode(), e);
- mOperations.remove(callback);
+ mGetKeyOperations.remove(callback);
wrapCallback(() -> callback.onError(e.getMessage()));
}
}
@Override
public void cancelGetKey(IGetKeyCallback callback) {
- CancellationSignal cancellationSignal = mOperations.remove(callback);
+ CancellationSignal cancellationSignal = mGetKeyOperations.remove(callback);
if (cancellationSignal == null) {
throw new IllegalArgumentException(
"Invalid client in cancelGetKey: " + callback.hashCode());
@@ -110,9 +114,35 @@
}
@Override
- public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) {
- // TODO(b/262748535)
- Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED");
+ public void storeUpgradedKeyAsync(byte[] oldKeyBlob, byte[] newKeyBlob,
+ IStoreUpgradedKeyCallback callback) {
+ if (!mStoreUpgradedKeyOperations.add(callback)) {
+ throw new IllegalArgumentException(
+ "Callback is already associated with an existing operation: "
+ + callback.hashCode());
+ }
+
+ try {
+ mRegistration.storeUpgradedKeyAsync(oldKeyBlob, newKeyBlob, mExecutor,
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Void result) {
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(callback::onSuccess);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(() -> callback.onError(e.getMessage()));
+ }
+ });
+ } catch (Exception e) {
+ Log.e(TAG, "storeUpgradedKeyAsync threw an exception for client "
+ + callback.hashCode(), e);
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(() -> callback.onError(e.getMessage()));
+ }
}
interface CallbackRunner {
diff --git a/services/core/java/com/android/server/security/rkp/TEST_MAPPING b/services/core/java/com/android/server/security/rkp/TEST_MAPPING
new file mode 100644
index 0000000..e983968
--- /dev/null
+++ b/services/core/java/com/android/server/security/rkp/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "presubmit": [
+ {
+ "name": "RemoteProvisioningServiceTests"
+ }
+ ]
+}
+
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 9727558..6043caa 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -1733,7 +1733,7 @@
setExternalControl(true, vibHolder.stats);
}
if (DEBUG) {
- Slog.e(TAG, "Playing external vibration: " + vib);
+ Slog.d(TAG, "Playing external vibration: " + vib);
}
// Vibrator will start receiving data from external channels after this point.
// Report current time as the vibration start time, for debugging.
@@ -1747,7 +1747,7 @@
if (mCurrentExternalVibration != null
&& mCurrentExternalVibration.isHoldingSameVibration(vib)) {
if (DEBUG) {
- Slog.e(TAG, "Stopping external vibration" + vib);
+ Slog.d(TAG, "Stopping external vibration: " + vib);
}
endExternalVibrateLocked(
new Vibration.EndInfo(Vibration.Status.FINISHED),
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index fd6c974..b160af6a 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -98,7 +98,7 @@
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
return mService.getRecentTasks().createRecentTaskInfo(task,
- false /* stripExtras */);
+ false /* stripExtras */, true /* getTasksAllowed */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 4860762..1fc061b 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -976,7 +976,7 @@
continue;
}
- res.add(createRecentTaskInfo(task, true /* stripExtras */));
+ res.add(createRecentTaskInfo(task, true /* stripExtras */, getTasksAllowed));
}
return res;
}
@@ -1895,7 +1895,8 @@
/**
* Creates a new RecentTaskInfo from a Task.
*/
- ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
+ ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras,
+ boolean getTasksAllowed) {
final ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
// If the recent Task is detached, we consider it will be re-attached to the default
// TaskDisplayArea because we currently only support recent overview in the default TDA.
@@ -1907,6 +1908,9 @@
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
+ if (!getTasksAllowed) {
+ Task.trimIneffectiveInfo(tr, rti);
+ }
// Fill in organized child task info for the task created by organizer.
if (tr.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 33f019e..4e339f1 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -177,6 +177,10 @@
}
// Fill in some deprecated values
rti.id = rti.taskId;
+
+ if (!mAllowed) {
+ Task.trimIneffectiveInfo(task, rti);
+ }
return rti;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d6f295e..8993840 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3447,6 +3447,27 @@
info.isSleeping = shouldSleepActivities();
}
+ /**
+ * Removes the activity info if the activity belongs to a different uid, which is
+ * different from the app that hosts the task.
+ */
+ static void trimIneffectiveInfo(Task task, TaskInfo info) {
+ final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing,
+ false /* traverseTopToBottom */);
+ final int baseActivityUid =
+ baseActivity != null ? baseActivity.getUid() : task.effectiveUid;
+
+ if (info.topActivityInfo != null
+ && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
+ info.topActivity = null;
+ info.topActivityInfo = null;
+ }
+
+ if (task.effectiveUid != baseActivityUid) {
+ info.baseActivity = null;
+ }
+ }
+
@Nullable PictureInPictureParams getPictureInPictureParams() {
final Task topTask = getTopMostTask();
if (topTask == null) return null;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index ec67414..1a3e7d1 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1904,7 +1904,8 @@
}
boolean shouldSleepActivities() {
- return false;
+ final Task task = getRootTask();
+ return task != null && task.shouldSleepActivities();
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 20d9cce..55fb599 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -136,6 +136,7 @@
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -18330,6 +18331,9 @@
if (preferentialNetworkServiceConfig.isEnabled()) {
if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ } else if (preferentialNetworkServiceConfig.shouldBlockNonMatchingNetworks()) {
+ preferenceBuilder.setPreference(
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING);
} else {
preferenceBuilder.setPreference(
PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
diff --git a/services/tests/RemoteProvisioningServiceTests/Android.bp b/services/tests/RemoteProvisioningServiceTests/Android.bp
new file mode 100644
index 0000000..075680a
--- /dev/null
+++ b/services/tests/RemoteProvisioningServiceTests/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "RemoteProvisioningServiceTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "android.security.rkp_aidl-java",
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "mockito-target",
+ "service-rkp.impl",
+ "services.core",
+ "truth-prebuilt",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ platform_apis: true,
+}
diff --git a/services/tests/RemoteProvisioningServiceTests/AndroidManifest.xml b/services/tests/RemoteProvisioningServiceTests/AndroidManifest.xml
new file mode 100644
index 0000000..7c12e189
--- /dev/null
+++ b/services/tests/RemoteProvisioningServiceTests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.security.rkp.test">
+
+ <application android:testOnly="true">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.security.rkp.test"
+ android:label="Remote Provisioning System Service Tests"/>
+</manifest>
diff --git a/services/tests/RemoteProvisioningServiceTests/AndroidTest.xml b/services/tests/RemoteProvisioningServiceTests/AndroidTest.xml
new file mode 100644
index 0000000..bf86fc8
--- /dev/null
+++ b/services/tests/RemoteProvisioningServiceTests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Frameworks RemoteProvisioningService Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <option name="test-tag" value="RemoteProvisioningServiceTests" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="RemoteProvisioningServiceTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.server.security.rkp.test" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ </test>
+</configuration>
diff --git a/services/tests/RemoteProvisioningServiceTests/OWNERS b/services/tests/RemoteProvisioningServiceTests/OWNERS
new file mode 100644
index 0000000..348f940
--- /dev/null
+++ b/services/tests/RemoteProvisioningServiceTests/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
diff --git a/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java
new file mode 100644
index 0000000..7b361d3
--- /dev/null
+++ b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.AdditionalAnswers.answerVoid;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IStoreUpgradedKeyCallback;
+import android.security.rkp.service.RegistrationProxy;
+import android.security.rkp.service.RemotelyProvisionedKey;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.stubbing.Answer;
+import org.mockito.stubbing.VoidAnswer4;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+/**
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:RemoteProvisioningRegistrationTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RemoteProvisioningRegistrationTest {
+ private RegistrationProxy mRegistrationProxy;
+ private RemoteProvisioningRegistration mRegistration;
+
+ @Before
+ public void setUp() {
+ mRegistrationProxy = mock(RegistrationProxy.class);
+ mRegistration = new RemoteProvisioningRegistration(mRegistrationProxy, Runnable::run);
+ }
+
+ // answerVoid wrapper with explicit types, avoiding long signatures when mocking getKeyAsync.
+ static Answer<Void> answerGetKeyAsync(
+ VoidAnswer4<Integer, CancellationSignal, Executor,
+ OutcomeReceiver<RemotelyProvisionedKey, Exception>> answer) {
+ return answerVoid(answer);
+ }
+
+ // answerVoid wrapper for mocking storeUpgradeKeyAsync.
+ static Answer<Void> answerStoreUpgradedKeyAsync(
+ VoidAnswer4<byte[], byte[], Executor, OutcomeReceiver<Void, Exception>> answer) {
+ return answerVoid(answer);
+ }
+
+ // matcher helper, making it easier to match the different key types
+ private android.security.rkp.RemotelyProvisionedKey matches(
+ RemotelyProvisionedKey expectedKey) {
+ return argThat((android.security.rkp.RemotelyProvisionedKey key) ->
+ Arrays.equals(key.keyBlob, expectedKey.getKeyBlob())
+ && Arrays.equals(key.encodedCertChain, expectedKey.getEncodedCertChain())
+ );
+ }
+
+ @Test
+ public void getKeySuccess() throws Exception {
+ RemotelyProvisionedKey expectedKey = mock(RemotelyProvisionedKey.class);
+ doAnswer(
+ answerGetKeyAsync((keyId, cancelSignal, executor, receiver) ->
+ executor.execute(() -> receiver.onResult(expectedKey))))
+ .when(mRegistrationProxy).getKeyAsync(eq(42), any(), any(), any());
+
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ mRegistration.getKey(42, callback);
+ verify(callback).onSuccess(matches(expectedKey));
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void getKeyHandlesError() throws Exception {
+ Exception expectedException = new Exception("oops!");
+ doAnswer(
+ answerGetKeyAsync((keyId, cancelSignal, executor, receiver) ->
+ executor.execute(() -> receiver.onError(expectedException))))
+ .when(mRegistrationProxy).getKeyAsync(eq(0), any(), any(), any());
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ mRegistration.getKey(0, callback);
+ verify(callback).onError(eq(expectedException.getMessage()));
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void getKeyCancelDuringProxyOperation() throws Exception {
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ doAnswer(
+ answerGetKeyAsync((keyId, cancelSignal, executor, receiver) -> {
+ mRegistration.cancelGetKey(callback);
+ assertThat(cancelSignal.isCanceled()).isTrue();
+ executor.execute(() -> receiver.onError(new OperationCanceledException()));
+ }))
+ .when(mRegistrationProxy).getKeyAsync(eq(Integer.MAX_VALUE), any(), any(), any());
+
+ mRegistration.getKey(Integer.MAX_VALUE, callback);
+ verify(callback).onCancel();
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void cancelGetKeyWithInvalidCallback() throws Exception {
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ assertThrows(IllegalArgumentException.class, () -> mRegistration.cancelGetKey(callback));
+ }
+
+ @Test
+ public void getKeyRejectsDuplicateCallback() throws Exception {
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ doAnswer(
+ answerGetKeyAsync((keyId, cancelSignal, executor, receiver) -> {
+ assertThrows(IllegalArgumentException.class, () ->
+ mRegistration.getKey(0, callback));
+ executor.execute(() -> receiver.onResult(mock(RemotelyProvisionedKey.class)));
+ }))
+ .when(mRegistrationProxy).getKeyAsync(anyInt(), any(), any(), any());
+
+ mRegistration.getKey(0, callback);
+ verify(callback, times(1)).onSuccess(any());
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void getKeyCancelAfterCompleteFails() throws Exception {
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ doAnswer(
+ answerGetKeyAsync((keyId, cancelSignal, executor, receiver) ->
+ executor.execute(() ->
+ receiver.onResult(mock(RemotelyProvisionedKey.class))
+ )))
+ .when(mRegistrationProxy).getKeyAsync(eq(Integer.MIN_VALUE), any(), any(), any());
+
+ mRegistration.getKey(Integer.MIN_VALUE, callback);
+ verify(callback).onSuccess(any());
+ assertThrows(IllegalArgumentException.class, () -> mRegistration.cancelGetKey(callback));
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void getKeyCatchesExceptionFromProxy() throws Exception {
+ Exception expectedException = new RuntimeException("oops! bad input!");
+ doThrow(expectedException)
+ .when(mRegistrationProxy)
+ .getKeyAsync(anyInt(), any(), any(), any());
+
+ IGetKeyCallback callback = mock(IGetKeyCallback.class);
+ mRegistration.getKey(0, callback);
+ verify(callback).onError(eq(expectedException.getMessage()));
+ assertThrows(IllegalArgumentException.class, () -> mRegistration.cancelGetKey(callback));
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void storeUpgradedKeySuccess() throws Exception {
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) ->
+ executor.execute(() -> receiver.onResult(null))))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onSuccess();
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void storeUpgradedKeyFails() throws Exception {
+ final String errorString = "this is a failure";
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) ->
+ executor.execute(() -> receiver.onError(new RemoteException(errorString)))))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onError(errorString);
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void storeUpgradedKeyHandlesException() throws Exception {
+ final String errorString = "all aboard the failboat, toot toot";
+ doThrow(new IllegalArgumentException(errorString))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onError(errorString);
+ verifyNoMoreInteractions(callback);
+ }
+
+ @Test
+ public void storeUpgradedKeyDuplicateCallback() throws Exception {
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) -> {
+ assertThrows(IllegalArgumentException.class,
+ () -> mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0],
+ callback));
+ executor.execute(() -> receiver.onResult(null));
+ }))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onSuccess();
+ verifyNoMoreInteractions(callback);
+ }
+
+}
diff --git a/services/tests/mockingservicestests/OWNERS b/services/tests/mockingservicestests/OWNERS
index 4dda51f..0640d52 100644
--- a/services/tests/mockingservicestests/OWNERS
+++ b/services/tests/mockingservicestests/OWNERS
@@ -6,3 +6,6 @@
per-file FakeServiceConnector.java = file:/GAME_MANAGER_OWNERS
per-file Game* = file:/GAME_MANAGER_OWNERS
per-file res/xml/game_manager* = file:/GAME_MANAGER_OWNERS
+
+# General utilities
+per-file services/tests/mockingservicestests/src/com/android/server/*.java=felipeal@google.com
diff --git a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/OWNERS b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/OWNERS
new file mode 100644
index 0000000..2e475a9
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/OWNERS
@@ -0,0 +1 @@
+include /services/companion/java/com/android/server/companion/virtual/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index b01c1c8..ce6bd6c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -50,6 +50,8 @@
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.hardware.rebootescrow.IRebootEscrow;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
@@ -72,6 +74,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.function.Consumer;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -113,6 +116,7 @@
private RebootEscrowManager mService;
private SecretKey mAesKey;
private MockInjector mMockInjector;
+ private Handler mHandler;
public interface MockableRebootEscrowInjected {
int getBootCount();
@@ -132,6 +136,9 @@
private final RebootEscrowKeyStoreManager mKeyStoreManager;
private boolean mServerBased;
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
+ private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
+ private boolean mWaitForInternet;
MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow,
@@ -142,6 +149,7 @@
mRebootEscrow = rebootEscrow;
mServiceConnection = null;
mServerBased = false;
+ mWaitForInternet = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -164,6 +172,7 @@
mServiceConnection = serviceConnection;
mRebootEscrow = null;
mServerBased = true;
+ mWaitForInternet = false;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
@Override
@@ -199,11 +208,33 @@
}
@Override
+ public boolean waitForInternet() {
+ return mWaitForInternet;
+ }
+
+ public void setWaitForNetwork(boolean waitForNetworkEnabled) {
+ mWaitForInternet = waitForNetworkEnabled;
+ }
+
+ @Override
public boolean isNetworkConnected() {
return false;
}
@Override
+ public boolean requestNetworkWithInternet(
+ ConnectivityManager.NetworkCallback networkCallback) {
+ mNetworkCallback = networkCallback;
+ mNetworkConsumer.accept(networkCallback);
+ return true;
+ }
+
+ @Override
+ public void stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback) {
+ mNetworkCallback = null;
+ }
+
+ @Override
public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
return mRebootEscrowProviderInUse;
@@ -242,6 +273,12 @@
}
@Override
+ public int getLoadEscrowTimeoutMillis() {
+ // Timeout in 3 seconds.
+ return 3000;
+ }
+
+ @Override
public String getVbmetaDigest(boolean other) {
return other ? "" : "fake digest";
}
@@ -291,6 +328,9 @@
mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow,
mKeyStoreManager, mStorage, mInjected);
mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage);
+ HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
+ thread.start();
+ mHandler = new Handler(thread.getLooper());
}
private void setServerBasedRebootEscrowProvider() throws Exception {
@@ -462,7 +502,7 @@
@Test
public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception {
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
}
@Test
@@ -499,7 +539,7 @@
eq(20), eq(0) /* vbmeta status */, anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -531,9 +571,16 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
- anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ eq(0) /* error code */,
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
@@ -569,15 +616,23 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
- eq(1) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
mService.loadRebootEscrowDataIfAvailable(null);
verify(mServiceConnection).unwrap(any(), anyLong());
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
metricsErrorCodeCaptor.getValue());
}
@@ -606,18 +661,24 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
- eq(2) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
- HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
- thread.start();
- mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
metricsErrorCodeCaptor.getValue());
}
@@ -645,16 +706,22 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- anyInt(), anyInt(), eq(2) /* attempt count */, anyInt(), anyInt(), anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ anyInt(),
+ anyInt(),
+ eq(2) /* attempt count */,
+ anyInt(),
+ anyInt(),
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenThrow(new IOException())
.thenAnswer(invocation -> invocation.getArgument(0));
- HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
- thread.start();
- mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
@@ -663,6 +730,447 @@
}
@Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternet_success()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ eq(0) /* error code */,
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternetRemoteException_Failure()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkUnavailable()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(0) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // Network is not available within timeout.
+ mMockInjector.mNetworkConsumer = ConnectivityManager.NetworkCallback::onUnavailable;
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkLost() throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // Network is available, then lost.
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(new IOException());
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ callback.onLost(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkAvailableWithDelay()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ // network available after 1 sec
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ callback.onAvailable(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_timeoutExhausted()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load reboot escrow data
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
+ Network mockNetwork = mock(Network.class);
+ // wait past timeout
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ try {
+ Thread.sleep(3500);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ callback.onAvailable(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_TIMEOUT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForNetwork_retryCountExhausted()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(new IOException());
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedWaitForInternet_RetrySuccess()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ anyInt(),
+ anyInt(),
+ eq(2) /* attempt count */,
+ anyInt(),
+ anyInt(),
+ anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenThrow(new IOException())
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception {
when(mInjected.getBootCount()).thenReturn(0);
@@ -687,7 +1195,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
anyInt(), anyInt(), anyInt());
@@ -715,7 +1223,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
anyInt(), anyInt(), anyInt());
}
@@ -753,7 +1261,7 @@
// Trigger a vbmeta digest mismatch
mStorage.setString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
"non sense value", USER_SYSTEM);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */,
eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt());
assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
@@ -790,7 +1298,7 @@
eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> null);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index c5131c8..57e403c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -435,63 +435,112 @@
@Test
public void testNotifyPostedLockedInLockdownMode() {
- NotificationRecord r = mock(NotificationRecord.class);
- NotificationRecord old = mock(NotificationRecord.class);
+ NotificationRecord r0 = mock(NotificationRecord.class);
+ NotificationRecord old0 = mock(NotificationRecord.class);
+ UserHandle uh0 = mock(UserHandle.class);
- // before the lockdown mode
- when(mNm.isInLockDownMode()).thenReturn(false);
- mListeners.notifyPostedLocked(r, old, true);
- mListeners.notifyPostedLocked(r, old, false);
- verify(r, atLeast(2)).getSbn();
+ NotificationRecord r1 = mock(NotificationRecord.class);
+ NotificationRecord old1 = mock(NotificationRecord.class);
+ UserHandle uh1 = mock(UserHandle.class);
- // in the lockdown mode
- reset(r);
- reset(old);
- when(mNm.isInLockDownMode()).thenReturn(true);
- mListeners.notifyPostedLocked(r, old, true);
- mListeners.notifyPostedLocked(r, old, false);
- verify(r, never()).getSbn();
- }
+ // Neither user0 and user1 is in the lockdown mode
+ when(r0.getUser()).thenReturn(uh0);
+ when(uh0.getIdentifier()).thenReturn(0);
+ when(mNm.isInLockDownMode(0)).thenReturn(false);
- @Test
- public void testnotifyRankingUpdateLockedInLockdownMode() {
- List chn = mock(List.class);
+ when(r1.getUser()).thenReturn(uh1);
+ when(uh1.getIdentifier()).thenReturn(1);
+ when(mNm.isInLockDownMode(1)).thenReturn(false);
- // before the lockdown mode
- when(mNm.isInLockDownMode()).thenReturn(false);
- mListeners.notifyRankingUpdateLocked(chn);
- verify(chn, atLeast(1)).size();
+ mListeners.notifyPostedLocked(r0, old0, true);
+ mListeners.notifyPostedLocked(r0, old0, false);
+ verify(r0, atLeast(2)).getSbn();
- // in the lockdown mode
- reset(chn);
- when(mNm.isInLockDownMode()).thenReturn(true);
- mListeners.notifyRankingUpdateLocked(chn);
- verify(chn, never()).size();
+ mListeners.notifyPostedLocked(r1, old1, true);
+ mListeners.notifyPostedLocked(r1, old1, false);
+ verify(r1, atLeast(2)).getSbn();
+
+ // Reset
+ reset(r0);
+ reset(old0);
+ reset(r1);
+ reset(old1);
+
+ // Only user 0 is in the lockdown mode
+ when(r0.getUser()).thenReturn(uh0);
+ when(uh0.getIdentifier()).thenReturn(0);
+ when(mNm.isInLockDownMode(0)).thenReturn(true);
+
+ when(r1.getUser()).thenReturn(uh1);
+ when(uh1.getIdentifier()).thenReturn(1);
+ when(mNm.isInLockDownMode(1)).thenReturn(false);
+
+ mListeners.notifyPostedLocked(r0, old0, true);
+ mListeners.notifyPostedLocked(r0, old0, false);
+ verify(r0, never()).getSbn();
+
+ mListeners.notifyPostedLocked(r1, old1, true);
+ mListeners.notifyPostedLocked(r1, old1, false);
+ verify(r1, atLeast(2)).getSbn();
}
@Test
public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
- NotificationRecord r = mock(NotificationRecord.class);
- NotificationStats rs = mock(NotificationStats.class);
+ NotificationRecord r0 = mock(NotificationRecord.class);
+ NotificationStats rs0 = mock(NotificationStats.class);
+ UserHandle uh0 = mock(UserHandle.class);
+
+ NotificationRecord r1 = mock(NotificationRecord.class);
+ NotificationStats rs1 = mock(NotificationStats.class);
+ UserHandle uh1 = mock(UserHandle.class);
+
StatusBarNotification sbn = mock(StatusBarNotification.class);
FieldSetter.setField(mNm,
NotificationManagerService.class.getDeclaredField("mHandler"),
mock(NotificationManagerService.WorkerHandler.class));
- // before the lockdown mode
- when(mNm.isInLockDownMode()).thenReturn(false);
- when(r.getSbn()).thenReturn(sbn);
- mListeners.notifyRemovedLocked(r, 0, rs);
- mListeners.notifyRemovedLocked(r, 0, rs);
- verify(r, atLeast(2)).getSbn();
+ // Neither user0 and user1 is in the lockdown mode
+ when(r0.getUser()).thenReturn(uh0);
+ when(uh0.getIdentifier()).thenReturn(0);
+ when(mNm.isInLockDownMode(0)).thenReturn(false);
+ when(r0.getSbn()).thenReturn(sbn);
- // in the lockdown mode
- reset(r);
- reset(rs);
- when(mNm.isInLockDownMode()).thenReturn(true);
- when(r.getSbn()).thenReturn(sbn);
- mListeners.notifyRemovedLocked(r, 0, rs);
- mListeners.notifyRemovedLocked(r, 0, rs);
- verify(r, never()).getSbn();
+ when(r1.getUser()).thenReturn(uh1);
+ when(uh1.getIdentifier()).thenReturn(1);
+ when(mNm.isInLockDownMode(1)).thenReturn(false);
+ when(r1.getSbn()).thenReturn(sbn);
+
+ mListeners.notifyRemovedLocked(r0, 0, rs0);
+ mListeners.notifyRemovedLocked(r0, 0, rs0);
+ verify(r0, atLeast(2)).getSbn();
+
+ mListeners.notifyRemovedLocked(r1, 0, rs1);
+ mListeners.notifyRemovedLocked(r1, 0, rs1);
+ verify(r1, atLeast(2)).getSbn();
+
+ // Reset
+ reset(r0);
+ reset(rs0);
+ reset(r1);
+ reset(rs1);
+
+ // Only user 0 is in the lockdown mode
+ when(r0.getUser()).thenReturn(uh0);
+ when(uh0.getIdentifier()).thenReturn(0);
+ when(mNm.isInLockDownMode(0)).thenReturn(true);
+ when(r0.getSbn()).thenReturn(sbn);
+
+ when(r1.getUser()).thenReturn(uh1);
+ when(uh1.getIdentifier()).thenReturn(1);
+ when(mNm.isInLockDownMode(1)).thenReturn(false);
+ when(r1.getSbn()).thenReturn(sbn);
+
+ mListeners.notifyRemovedLocked(r0, 0, rs0);
+ mListeners.notifyRemovedLocked(r0, 0, rs0);
+ verify(r0, never()).getSbn();
+
+ mListeners.notifyRemovedLocked(r1, 0, rs1);
+ mListeners.notifyRemovedLocked(r1, 0, rs1);
+ verify(r1, atLeast(2)).getSbn();
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4d1c786..dd43a6b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -174,6 +174,7 @@
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationRankingUpdate;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenPolicy;
@@ -7604,43 +7605,6 @@
}
@Test
- public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
- mService.isSystemUid = true;
- ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
- when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
- .thenReturn(true);
- mService.setZenHelper(mockZenModeHelper);
- ComponentName owner = new ComponentName("android", "ProviderName");
- ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
- boolean isEnabled = true;
- AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
- zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
- mBinderService.addAutomaticZenRule(rule, "com.android.settings");
-
- // verify that zen mode helper gets passed in a package name of "android"
- verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
- }
-
- @Test
- public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
- mService.isSystemUid = false;
- ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
- when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
- .thenReturn(true);
- mService.setZenHelper(mockZenModeHelper);
- ComponentName owner = new ComponentName("android", "ProviderName");
- ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
- boolean isEnabled = true;
- AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
- zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
- mBinderService.addAutomaticZenRule(rule, "another.package");
-
- // verify that zen mode helper gets passed in the package name from the arg, not the owner
- verify(mockZenModeHelper).addAutomaticZenRule(
- eq("another.package"), eq(rule), anyString());
- }
-
- @Test
public void testAreNotificationsEnabledForPackage() throws Exception {
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
mUid);
@@ -9837,10 +9801,10 @@
mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
- assertTrue(mStrongAuthTracker.isInLockDownMode());
- mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId());
mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
- assertFalse(mStrongAuthTracker.isInLockDownMode());
+ assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
}
@Test
@@ -9856,8 +9820,8 @@
// when entering the lockdown mode, cancel the 2 notifications.
mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
- mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
- assertTrue(mStrongAuthTracker.isInLockDownMode());
+ mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+ assertTrue(mStrongAuthTracker.isInLockDownMode(0));
// the notifyRemovedLocked function is called twice due to REASON_CANCEL_ALL.
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
@@ -9866,10 +9830,46 @@
// exit lockdown mode.
mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
- mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+ assertFalse(mStrongAuthTracker.isInLockDownMode(0));
// the notifyPostedLocked function is called twice.
- verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+ verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
+ //verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+ }
+
+ @Test
+ public void testMakeRankingUpdateLockedInLockDownMode() {
+ // post 2 notifications from a same package
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 1), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ mService.setIsVisibleToListenerReturnValue(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
+ assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
+
+ // when only user 0 entering the lockdown mode, its notification will be suppressed.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+ assertTrue(mStrongAuthTracker.isInLockDownMode(0));
+ assertFalse(mStrongAuthTracker.isInLockDownMode(1));
+
+ nru = mService.makeRankingUpdateLocked(null);
+ assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
+
+ // User 0 exits lockdown mode. Its notification will be resumed.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+ assertFalse(mStrongAuthTracker.isInLockDownMode(0));
+ assertFalse(mStrongAuthTracker.isInLockDownMode(1));
+
+ nru = mService.makeRankingUpdateLocked(null);
+ assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index b49e5cb..8cf74fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -19,10 +19,12 @@
import android.companion.ICompanionDeviceManager;
import android.content.ComponentName;
import android.content.Context;
+import android.service.notification.StatusBarNotification;
import androidx.annotation.Nullable;
import com.android.internal.logging.InstanceIdSequence;
+import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import java.util.HashSet;
import java.util.Set;
@@ -37,6 +39,9 @@
@Nullable
NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
+ @Nullable
+ Boolean mIsVisibleToListenerReturnValue = null;
+
TestableNotificationManagerService(Context context, NotificationRecordLogger logger,
InstanceIdSequence notificationInstanceIdSequence) {
super(context, logger, notificationInstanceIdSequence);
@@ -119,6 +124,19 @@
mShowReviewPermissionsNotification = setting;
}
+ protected void setIsVisibleToListenerReturnValue(boolean value) {
+ mIsVisibleToListenerReturnValue = value;
+ }
+
+ @Override
+ boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
+ ManagedServiceInfo listener) {
+ if (mIsVisibleToListenerReturnValue != null) {
+ return mIsVisibleToListenerReturnValue;
+ }
+ return super.isVisibleToListener(sbn, notificationType, listener);
+ }
+
public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
private int mGetStrongAuthForUserReturnValue = 0;
StrongAuthTrackerFake(Context context) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 2ccdcaa..4550b56 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1672,36 +1672,6 @@
}
@Test
- public void testAddAutomaticZenRule_claimedSystemOwner() {
- // Make sure anything that claims to have a "system" owner but not actually part of the
- // system package still gets limited on number of rules
- for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
- ScheduleInfo si = new ScheduleInfo();
- si.startHour = i;
- AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
- new ComponentName("android", "ScheduleConditionProvider" + i),
- null, // configuration activity
- ZenModeConfig.toScheduleConditionId(si),
- new ZenPolicy.Builder().build(),
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
- assertNotNull(id);
- }
- try {
- AutomaticZenRule zenRule = new AutomaticZenRule("name",
- new ComponentName("android", "ScheduleConditionProviderFinal"),
- null, // configuration activity
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- new ZenPolicy.Builder().build(),
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
- fail("allowed too many rules to be created");
- } catch (IllegalArgumentException e) {
- // yay
- }
- }
-
- @Test
public void testAddAutomaticZenRule_CA() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index adf694c..0462e1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -30,6 +30,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Process.NOBODY_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -1220,20 +1221,34 @@
@Test
public void testCreateRecentTaskInfo_detachedTask() {
- final Task task = createTaskBuilder(".Task").setCreateActivity(true).build();
+ final Task task = createTaskBuilder(".Task").build();
+ new ActivityBuilder(mSupervisor.mService)
+ .setTask(task)
+ .setUid(NOBODY_UID)
+ .setComponent(getUniqueComponentName())
+ .build();
final TaskDisplayArea tda = task.getDisplayArea();
assertTrue(task.isAttached());
assertTrue(task.supportsMultiWindow());
- RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true);
+ RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ false /* getTasksAllowed */);
+
+ assertTrue(info.topActivity == null);
+ assertTrue(info.topActivityInfo == null);
+ assertTrue(info.baseActivity == null);
+
// The task can be put in split screen even if it is not attached now.
task.removeImmediately();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
@@ -1242,7 +1257,8 @@
doReturn(false).when(tda).supportsNonResizableMultiWindow();
doReturn(false).when(task).isResizeable();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertFalse(info.supportsMultiWindow);
@@ -1250,7 +1266,8 @@
// the device supports it.
doReturn(true).when(tda).supportsNonResizableMultiWindow();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
}
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 3b50fa4..5716b66 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -29,9 +29,10 @@
"android.hardware.usb-V1.1-java",
"android.hardware.usb-V1.2-java",
"android.hardware.usb-V1.3-java",
- "android.hardware.usb-V1-java",
+ "android.hardware.usb-V1-java",
"android.hardware.usb.gadget-V1.0-java",
"android.hardware.usb.gadget-V1.1-java",
"android.hardware.usb.gadget-V1.2-java",
+ "android.hardware.usb.gadget-V1-java",
],
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index d580995..1b92699 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -44,6 +44,7 @@
import android.debug.AdbNotifications;
import android.debug.AdbTransportType;
import android.debug.IAdbTransport;
+import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbConfiguration;
@@ -54,9 +55,7 @@
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
-import android.hardware.usb.gadget.V1_0.IUsbGadget;
import android.hardware.usb.gadget.V1_0.Status;
-import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
@@ -88,9 +87,12 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.usb.hal.gadget.UsbGadgetHal;
+import com.android.server.usb.hal.gadget.UsbGadgetHalInstance;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.File;
@@ -105,6 +107,7 @@
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -215,6 +218,13 @@
private static UsbDeviceLogger sEventLogger;
+ private UsbGadgetHal mUsbGadgetHal;
+
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
static {
sDenyInterfaces = new HashSet<>();
sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -297,15 +307,11 @@
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
+ int operationId = sUsbOperationCount.incrementAndGet();
boolean halNotPresent = false;
- try {
- IUsbGadget.getService(true);
- } catch (RemoteException e) {
- Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
- } catch (NoSuchElementException e) {
- halNotPresent = true;
- Slog.i(TAG, "USB GADGET HAL not present in the device", e);
- }
+
+ mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
+ Slog.d(TAG, "getInstance done");
mControlFds = new HashMap<>();
FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
@@ -319,7 +325,7 @@
}
mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
- if (halNotPresent) {
+ if (mUsbGadgetHal == null) {
/**
* Initialze the legacy UsbHandler
*/
@@ -333,6 +339,8 @@
alsaManager, permissionManager);
}
+ mHandler.handlerInitDone(operationId);
+
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
startAccessoryMode();
@@ -454,6 +462,8 @@
private void startAccessoryMode() {
if (!mHasUsbAccessory) return;
+ int operationId = sUsbOperationCount.incrementAndGet();
+
mAccessoryStrings = nativeGetAccessoryStrings();
boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
// don't start accessory mode if our mandatory strings have not been set
@@ -474,7 +484,7 @@
ACCESSORY_REQUEST_TIMEOUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_HANDSHAKE_TIMEOUT),
ACCESSORY_HANDSHAKE_TIMEOUT);
- setCurrentFunctions(functions);
+ setCurrentFunctions(functions, operationId);
}
}
@@ -503,6 +513,20 @@
}
}
+ public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+ Slog.println(priority, TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ }
+ }
+
+ public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+ Slog.e(TAG, msg, e);
+ if (pw != null) {
+ pw.println(msg + e);
+ }
+ }
+
abstract static class UsbHandler extends Handler {
// current USB state
@@ -605,6 +629,19 @@
sendMessage(m);
}
+ public boolean sendMessage(int what) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ return sendMessageDelayed(m,0);
+ }
+
+ public void sendMessage(int what, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, Object arg) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -612,6 +649,22 @@
sendMessage(m);
}
+ public void sendMessage(int what, Object arg, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = operationId;
+ sendMessage(m);
+ }
+
+ public void sendMessage(int what, boolean arg, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = (arg ? 1 : 0);
+ m.arg2 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, Object arg, boolean arg1) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -620,6 +673,15 @@
sendMessage(m);
}
+ public void sendMessage(int what, long arg, boolean arg1, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = (arg1 ? 1 : 0);
+ m.arg2 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, boolean arg1, boolean arg2) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -677,7 +739,7 @@
sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
}
- private void setAdbEnabled(boolean enable) {
+ private void setAdbEnabled(boolean enable, int operationId) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable) {
@@ -686,7 +748,7 @@
setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, "");
}
- setEnabledFunctions(mCurrentFunctions, true);
+ setEnabledFunctions(mCurrentFunctions, true, operationId);
updateAdbNotification(false);
}
@@ -698,6 +760,8 @@
private void updateCurrentAccessory() {
// We are entering accessory mode if we have received a request from the host
// and the request has not timed out yet.
+ int operationId = sUsbOperationCount.incrementAndGet();
+
boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
if (mConfigured && enteringAccessoryMode) {
@@ -729,18 +793,18 @@
}
} else {
if (!enteringAccessoryMode) {
- notifyAccessoryModeExit();
+ notifyAccessoryModeExit(operationId);
} else if (DEBUG) {
Slog.v(TAG, "Debouncing accessory mode exit");
}
}
}
- private void notifyAccessoryModeExit() {
+ private void notifyAccessoryModeExit(int operationId) {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -866,8 +930,8 @@
mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
}
- private void setScreenUnlockedFunctions() {
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ private void setScreenUnlockedFunctions(int operationId) {
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
private static class AdbTransport extends IAdbTransport.Stub {
@@ -880,7 +944,8 @@
@Override
public void onAdbEnabled(boolean enabled, byte transportType) {
if (transportType == AdbTransportType.USB) {
- mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
}
}
}
@@ -903,6 +968,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
+ int operationId = sUsbOperationCount.incrementAndGet();
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
@@ -920,9 +986,9 @@
// restore defaults when USB is disconnected
if (!mScreenLocked
&& mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
}
updateUsbFunctions();
@@ -1026,13 +1092,15 @@
updateUsbNotification(false);
break;
case MSG_ENABLE_ADB:
- setAdbEnabled(msg.arg1 == 1);
+ setAdbEnabled(msg.arg1 == 1, msg.arg2);
break;
case MSG_SET_CURRENT_FUNCTIONS:
long functions = (Long) msg.obj;
- setEnabledFunctions(functions, false);
+ operationId = (int) msg.arg1;
+ setEnabledFunctions(functions, false, operationId);
break;
case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS:
+ operationId = sUsbOperationCount.incrementAndGet();
mScreenUnlockedFunctions = (Long) msg.obj;
if (mSettings != null) {
SharedPreferences.Editor editor = mSettings.edit();
@@ -1043,12 +1111,13 @@
}
if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
// If the screen is unlocked, also set current functions.
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
break;
case MSG_UPDATE_SCREEN_LOCK:
+ operationId = sUsbOperationCount.incrementAndGet();
if (msg.arg1 == 1 == mScreenLocked) {
break;
}
@@ -1058,23 +1127,25 @@
}
if (mScreenLocked) {
if (!mConnected) {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
} else {
if (mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE
&& mCurrentFunctions == UsbManager.FUNCTION_NONE) {
// Set the screen unlocked functions if current function is charging.
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
}
}
break;
case MSG_UPDATE_USER_RESTRICTIONS:
+ operationId = sUsbOperationCount.incrementAndGet();
// Restart the USB stack if USB transfer is enabled but no longer allowed.
if (isUsbDataTransferActive(mCurrentFunctions) && !isUsbTransferAllowed()) {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, true);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, true, operationId);
}
break;
case MSG_SYSTEM_READY:
+ operationId = sUsbOperationCount.incrementAndGet();
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1092,17 +1163,19 @@
NotificationManager.IMPORTANCE_HIGH));
}
mSystemReady = true;
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_LOCALE_CHANGED:
updateAdbNotification(true);
updateUsbNotification(true);
break;
case MSG_BOOT_COMPLETED:
+ operationId = sUsbOperationCount.incrementAndGet();
mBootCompleted = true;
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_USER_SWITCHED: {
+ operationId = sUsbOperationCount.incrementAndGet();
if (mCurrentUser != msg.arg1) {
if (DEBUG) {
Slog.v(TAG, "Current user switched to " + msg.arg1);
@@ -1115,16 +1188,18 @@
mSettings.getString(String.format(Locale.ENGLISH,
UNLOCKED_CONFIG_PREF, mCurrentUser), ""));
}
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
break;
}
case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+ operationId = sUsbOperationCount.incrementAndGet();
if (DEBUG) {
- Slog.v(TAG, "Accessory mode enter timeout: " + mConnected);
+ Slog.v(TAG, "Accessory mode enter timeout: " + mConnected
+ + " ,operationId: " + operationId);
}
if (!mConnected || (mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) == 0) {
- notifyAccessoryModeExit();
+ notifyAccessoryModeExit(operationId);
}
break;
}
@@ -1147,7 +1222,9 @@
}
}
- protected void finishBoot() {
+ public abstract void handlerInitDone(int operationId);
+
+ protected void finishBoot(int operationId) {
if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
if (mPendingBootBroadcast) {
updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
@@ -1155,9 +1232,9 @@
}
if (!mScreenLocked
&& mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
if (mCurrentAccessory != null) {
mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -1491,7 +1568,8 @@
/**
* Evaluates USB function policies and applies the change accordingly.
*/
- protected abstract void setEnabledFunctions(long functions, boolean forceRestart);
+ protected abstract void setEnabledFunctions(long functions,
+ boolean forceRestart, int operationId);
public void setAccessoryUEventTime(long accessoryConnectionStartTime) {
mAccessoryConnectionStartTime = accessoryConnectionStartTime;
@@ -1506,6 +1584,11 @@
mSendStringCount = 0;
mStartAccessory = false;
}
+
+ public abstract void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions);
+
+ public abstract void getUsbSpeedCb(int speed);
}
private static final class UsbHandlerLegacy extends UsbHandler {
@@ -1524,6 +1607,11 @@
private String mCurrentFunctionsStr;
private boolean mUsbDataUnlocked;
+ /**
+ * Keeps track of the latest setCurrentUsbFunctions request number.
+ */
+ private int mCurrentRequest = 0;
+
UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
super(looper, context, deviceManager, alsaManager, permissionManager);
@@ -1557,6 +1645,10 @@
}
}
+ @Override
+ public void handlerInitDone(int operationId) {
+ }
+
private void readOemUsbOverrideConfig(Context context) {
String[] configList = context.getResources().getStringArray(
com.android.internal.R.array.config_oemUsbModeOverride);
@@ -1659,11 +1751,14 @@
}
@Override
- protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
+ protected void setEnabledFunctions(long usbFunctions,
+ boolean forceRestart, int operationId) {
boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
if (DEBUG) {
- Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", "
- + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+ Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions +
+ " ,forceRestart=" + forceRestart +
+ " ,usbDataUnlocked=" + usbDataUnlocked +
+ " ,operationId=" + operationId);
}
if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -1759,7 +1854,6 @@
|| !mCurrentFunctionsStr.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
- Slog.i(TAG, "Setting USB config to " + functions);
mCurrentFunctionsStr = functions;
mCurrentOemFunctions = oemFunctions;
mCurrentFunctionsApplied = false;
@@ -1855,15 +1949,18 @@
if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
return true;
}
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed){
+ }
}
- private static final class UsbHandlerHal extends UsbHandler {
-
- /**
- * Proxy object for the usb gadget hal daemon.
- */
- @GuardedBy("mGadgetProxyLock")
- private IUsbGadget mGadgetProxy;
+ private final class UsbHandlerHal extends UsbHandler {
private final Object mGadgetProxyLock = new Object();
@@ -1910,33 +2007,20 @@
UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
super(looper, context, deviceManager, alsaManager, permissionManager);
+ int operationId = sUsbOperationCount.incrementAndGet();
try {
- ServiceNotification serviceNotification = new ServiceNotification();
-
- boolean ret = IServiceManager.getService()
- .registerForNotifications(GADGET_HAL_FQ_NAME, "", serviceNotification);
- if (!ret) {
- Slog.e(TAG, "Failed to register usb gadget service start notification");
- return;
- }
synchronized (mGadgetProxyLock) {
- mGadgetProxy = IUsbGadget.getService(true);
- mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
- USB_GADGET_HAL_DEATH_COOKIE);
mCurrentFunctions = UsbManager.FUNCTION_NONE;
mCurrentUsbFunctionsRequested = true;
mUsbSpeed = UsbSpeed.UNKNOWN;
mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
- mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+ updateUsbGadgetHalVersion();
}
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
- updateUsbGadgetHalVersion();
} catch (NoSuchElementException e) {
Slog.e(TAG, "Usb gadget hal not found", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "Usb Gadget hal not responding", e);
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
@@ -1949,7 +2033,7 @@
if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
synchronized (mGadgetProxyLock) {
- mGadgetProxy = null;
+ mUsbGadgetHal = null;
}
}
}
@@ -1972,18 +2056,22 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_CHARGING_FUNCTIONS:
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
break;
case MSG_SET_FUNCTIONS_TIMEOUT:
- Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+ operationId = sUsbOperationCount.incrementAndGet();
+ Slog.e(TAG, "Set functions timed out! no reply from usb hal"
+ + " ,operationId:" + operationId);
if (msg.arg1 != 1) {
// Set this since default function may be selected from Developer options
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
break;
case MSG_GET_CURRENT_USB_FUNCTIONS:
Slog.i(TAG, "processing MSG_GET_CURRENT_USB_FUNCTIONS");
mCurrentUsbFunctionsReceived = true;
+ operationId = msg.arg2;
if (mCurrentUsbFunctionsRequested) {
Slog.i(TAG, "updating mCurrentFunctions");
@@ -1993,91 +2081,71 @@
"mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
mCurrentFunctionsApplied = msg.arg1 == 1;
}
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_FUNCTION_SWITCH_TIMEOUT:
/**
* Dont force to default when the configuration is already set to default.
*/
+ operationId = sUsbOperationCount.incrementAndGet();
if (msg.arg1 != 1) {
// Set this since default function may be selected from Developer options
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
break;
case MSG_GADGET_HAL_REGISTERED:
boolean preexisting = msg.arg1 == 1;
+ operationId = sUsbOperationCount.incrementAndGet();
synchronized (mGadgetProxyLock) {
try {
- mGadgetProxy = IUsbGadget.getService();
- mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
- USB_GADGET_HAL_DEATH_COOKIE);
+ mUsbGadgetHal = UsbGadgetHalInstance.getInstance(mUsbDeviceManager,
+ null);
if (!mCurrentFunctionsApplied && !preexisting) {
- setEnabledFunctions(mCurrentFunctions, false);
+ setEnabledFunctions(mCurrentFunctions, false, operationId);
}
} catch (NoSuchElementException e) {
Slog.e(TAG, "Usb gadget hal not found", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "Usb Gadget hal not responding", e);
}
}
break;
case MSG_RESET_USB_GADGET:
synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "reset Usb Gadget mGadgetProxy is null");
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "reset Usb Gadget mUsbGadgetHal is null");
break;
}
try {
- android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_1.IUsbGadget
- .castFrom(mGadgetProxy);
- gadgetProxy.reset();
- } catch (RemoteException e) {
+ mUsbGadgetHal.reset();
+ } catch (Exception e) {
Slog.e(TAG, "reset Usb Gadget failed", e);
}
}
break;
case MSG_UPDATE_USB_SPEED:
- synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "mGadgetProxy is null");
- break;
- }
+ operationId = sUsbOperationCount.incrementAndGet();
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "mGadgetHal is null, operationId:" + operationId);
+ break;
+ }
- try {
- android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_2.IUsbGadget
- .castFrom(mGadgetProxy);
- if (gadgetProxy != null) {
- gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "get UsbSpeed failed", e);
- }
+ try {
+ mUsbGadgetHal.getUsbSpeed(operationId);
+ } catch (Exception e) {
+ Slog.e(TAG, "get UsbSpeed failed", e);
}
break;
case MSG_UPDATE_HAL_VERSION:
- synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "mGadgetProxy is null");
- break;
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "mUsbGadgetHal is null");
+ break;
+ }
+ else {
+ try {
+ mCurrentGadgetHalVersion = mUsbGadgetHal.getGadgetHalVersion();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "update Usb gadget version failed", e);
}
-
- android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
- if (gadgetProxy == null) {
- android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxyV1By1 =
- android.hardware.usb.gadget.V1_1.IUsbGadget
- .castFrom(mGadgetProxy);
- if (gadgetProxyV1By1 == null) {
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
- break;
- }
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_1;
- break;
- }
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_2;
}
break;
default:
@@ -2085,56 +2153,31 @@
}
}
- private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
- int mRequest;
- long mFunctions;
- boolean mChargingFunctions;
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
- UsbGadgetCallback() {
+ if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+ || (mFunctions != functions)) {
+ return;
}
- UsbGadgetCallback(int request, long functions,
- boolean chargingFunctions) {
- mRequest = request;
- mFunctions = functions;
- mChargingFunctions = chargingFunctions;
- }
-
- @Override
- public void setCurrentUsbFunctionsCb(long functions,
- int status) {
- /**
- * Callback called for a previous setCurrenUsbFunction
- */
- if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
- || (mFunctions != functions)) {
- return;
- }
-
- removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
- Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
- if (status == Status.SUCCESS) {
- mCurrentFunctionsApplied = true;
- } else if (!mChargingFunctions) {
- Slog.e(TAG, "Setting default fuctions");
- sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
- }
- }
-
- @Override
- public void getCurrentUsbFunctionsCb(long functions,
- int status) {
- sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
- status == Status.FUNCTIONS_APPLIED);
- }
-
- @Override
- public void getUsbSpeedCb(int speed) {
- mUsbSpeed = speed;
+ removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+ Slog.i(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+ if (status == Status.SUCCESS) {
+ mCurrentFunctionsApplied = true;
+ } else if (!mChargingFunctions) {
+ Slog.e(TAG, "Setting default fuctions");
+ sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
}
}
- private void setUsbConfig(long config, boolean chargingFunctions) {
+ @Override
+ public void getUsbSpeedCb(int speed) {
+ mUsbSpeed = speed;
+ }
+
+ private void setUsbConfig(long config, boolean chargingFunctions, int operationId) {
if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
/**
* Cancel any ongoing requests, if present.
@@ -2144,8 +2187,8 @@
removeMessages(MSG_SET_CHARGING_FUNCTIONS);
synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "setUsbConfig mUsbGadgetHal is null");
return;
}
try {
@@ -2162,10 +2205,9 @@
LocalServices.getService(AdbManagerInternal.class)
.stopAdbdForTransport(AdbTransportType.USB);
}
- UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
- config, chargingFunctions);
- mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,
- SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+ mUsbGadgetHal.setCurrentUsbFunctions(mCurrentRequest,
+ config, chargingFunctions,
+ SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS, operationId);
sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
SET_FUNCTIONS_TIMEOUT_MS);
if (mConnected) {
@@ -2174,17 +2216,19 @@
SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
}
if (DEBUG) Slog.d(TAG, "timeout message queued");
- } catch (RemoteException e) {
+ } catch (Exception e) {//RemoteException e) {
Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
}
}
}
@Override
- protected void setEnabledFunctions(long functions, boolean forceRestart) {
+ protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
if (DEBUG) {
- Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
- + "forceRestart=" + forceRestart);
+ Slog.d(TAG, "setEnabledFunctionsi " +
+ "functions=" + functions +
+ ", forceRestart=" + forceRestart +
+ ", operationId=" + operationId);
}
if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
if ((functions & UsbManager.FUNCTION_NCM) != 0) {
@@ -2205,7 +2249,7 @@
functions = getAppliedFunctions(functions);
// Set the new USB configuration.
- setUsbConfig(functions, chargingFunctions);
+ setUsbConfig(functions, chargingFunctions, operationId);
if (mBootCompleted && isUsbDataTransferActive(functions)) {
// Start up dependent services.
@@ -2213,6 +2257,11 @@
}
}
}
+
+ @Override
+ public void handlerInitDone(int operationId) {
+ mUsbGadgetHal.getCurrentUsbFunctions(operationId);
+ }
}
/* returns the currently attached USB accessory */
@@ -2254,6 +2303,21 @@
return mHandler.getGadgetHalVersion();
}
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
+ mHandler.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ public void getCurrentUsbFunctionsCb(long functions, int status) {
+ mHandler.sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+ status == Status.FUNCTIONS_APPLIED);
+ }
+
+ public void getUsbSpeedCb(int speed) {
+ mHandler.getUsbSpeedCb(speed);
+ }
+
/**
* Returns a dup of the control file descriptor for the given function.
*/
@@ -2279,7 +2343,7 @@
*
* @param functions The functions to set, or empty to set the charging function.
*/
- public void setCurrentFunctions(long functions) {
+ public void setCurrentFunctions(long functions, int operationId) {
if (DEBUG) {
Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
}
@@ -2296,7 +2360,7 @@
} else if (functions == UsbManager.FUNCTION_ACCESSORY) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
}
- mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
+ mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, operationId);
}
/**
@@ -2324,7 +2388,8 @@
}
private void onAdbEnabled(boolean enabled) {
- mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
}
/**
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 86f877f..6e0d799 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -605,16 +605,16 @@
}
@Override
- public void setCurrentFunctions(long functions) {
+ public void setCurrentFunctions(long functions, int operationId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
Preconditions.checkState(mDeviceManager != null);
- mDeviceManager.setCurrentFunctions(functions);
+ mDeviceManager.setCurrentFunctions(functions, operationId);
}
@Override
- public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
- setCurrentFunctions(UsbManager.usbFunctionsFromString(functions));
+ public void setCurrentFunction(String functions, boolean usbDataUnlocked, int operationId) {
+ setCurrentFunctions(UsbManager.usbFunctionsFromString(functions), operationId);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
new file mode 100644
index 0000000..bdfe60a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -0,0 +1,220 @@
+/*
+ * 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_V2_0;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.IUsbGadget;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.os.ServiceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Implements the methods to interact with AIDL USB HAL.
+ */
+public final class UsbGadgetAidl implements UsbGadgetHal {
+ private static final String TAG = UsbGadgetAidl.class.getSimpleName();
+ private static final String USB_GADGET_AIDL_SERVICE = IUsbGadget.DESCRIPTOR + "/default";
+ // Proxy object for the usb gadget hal daemon.
+ @GuardedBy("mGadgetProxyLock")
+ private IUsbGadget mGadgetProxy;
+ private final UsbDeviceManager mDeviceManager;
+ public final IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mGadgetProxyLock = new Object();
+ // Callback when the UsbDevice status is changed by the kernel.
+ private UsbGadgetCallback mUsbGadgetCallback;
+
+ public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy == null) {
+ throw new RemoteException("IUsb not initialized yet");
+ }
+ }
+ Slog.i(TAG, "USB Gadget HAL AIDL version: GADGET_HAL_V2_0");
+ return GADGET_HAL_V2_0;
+ }
+
+ @Override
+ public void systemReady() {
+ }
+
+ public void serviceDied() {
+ logAndPrint(Log.ERROR, mPw, "Usb Gadget AIDL hal service died");
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = null;
+ }
+ connectToProxy(null);
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy != null) {
+ return;
+ }
+
+ try {
+ mGadgetProxy = IUsbGadget.Stub.asInterface(
+ ServiceManager.waitForService(USB_GADGET_AIDL_SERVICE));
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+ + " Did the service fail to start?", e);
+ }
+ }
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ return ServiceManager.isDeclared(USB_GADGET_AIDL_SERVICE);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget Aidl hal service not found.", e);
+ }
+
+ return false;
+ }
+
+ public UsbGadgetAidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+ mDeviceManager = Objects.requireNonNull(deviceManager);
+ mPw = pw;
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void getCurrentUsbFunctions(long operationId) {
+ synchronized (mGadgetProxyLock) {
+ try {
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback(), operationId);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getCurrentUsbFunctions"
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void getUsbSpeed(long operationId) {
+ try {
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.getUsbSpeed(new UsbGadgetCallback(), operationId);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed"
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+
+ @Override
+ public void reset() {
+ try {
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.reset();
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed", e);
+ return;
+ }
+ }
+
+ @Override
+ public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+ boolean mChargingFunctions, int timeout, long operationId) {
+ try {
+ mUsbGadgetCallback = new UsbGadgetCallback(mRequest,
+ mFunctions, mChargingFunctions);
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback,
+ timeout, operationId);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling setCurrentUsbFunctions: "
+ + "mRequest=" + mRequest
+ + ", mFunctions=" + mFunctions
+ + ", mChargingFunctions=" + mChargingFunctions
+ + ", timeout=" + timeout
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+
+ private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ public int mRequest;
+ public long mFunctions;
+ public boolean mChargingFunctions;
+
+ UsbGadgetCallback() {
+ }
+
+ UsbGadgetCallback(int request, long functions,
+ boolean chargingFunctions) {
+ mRequest = request;
+ mFunctions = functions;
+ mChargingFunctions = chargingFunctions;
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, long transactionId) {
+ mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ @Override
+ public void getCurrentUsbFunctionsCb(long functions,
+ int status, long transactionId) {
+ mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed, long transactionId) {
+ mDeviceManager.getUsbSpeedCb(speed);
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return IUsbGadgetCallback.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return IUsbGadgetCallback.VERSION;
+ }
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
new file mode 100644
index 0000000..267247b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -0,0 +1,138 @@
+/*
+ * 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.usb.hal.gadget;
+
+import android.annotation.IntDef;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.os.RemoteException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.String;
+
+/**
+ * @hide
+ */
+public interface UsbGadgetHal {
+ /**
+ * Power role: This USB port can act as a source (provide power).
+ * @hide
+ */
+ public static final int HAL_POWER_ROLE_SOURCE = 1;
+
+ /**
+ * Power role: This USB port can act as a sink (receive power).
+ * @hide
+ */
+ public static final int HAL_POWER_ROLE_SINK = 2;
+
+ @IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
+ HAL_POWER_ROLE_SOURCE,
+ HAL_POWER_ROLE_SINK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbPowerRole{}
+
+ /**
+ * Data role: This USB port can act as a host (access data services).
+ * @hide
+ */
+ public static final int HAL_DATA_ROLE_HOST = 1;
+
+ /**
+ * Data role: This USB port can act as a device (offer data services).
+ * @hide
+ */
+ public static final int HAL_DATA_ROLE_DEVICE = 2;
+
+ @IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
+ HAL_DATA_ROLE_HOST,
+ HAL_DATA_ROLE_DEVICE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbDataRole{}
+
+ /**
+ * This USB port can act as a downstream facing port (host).
+ *
+ * @hide
+ */
+ public static final int HAL_MODE_DFP = 1;
+
+ /**
+ * This USB port can act as an upstream facing port (device).
+ *
+ * @hide
+ */
+ public static final int HAL_MODE_UFP = 2;
+ @IntDef(prefix = { "HAL_MODE_" }, value = {
+ HAL_MODE_DFP,
+ HAL_MODE_UFP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbPortMode{}
+
+ /**
+ * UsbPortManager would call this when the system is done booting.
+ */
+ public void systemReady();
+
+ /**
+ * This function is used to query the USB functions included in the
+ * current USB configuration.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void getCurrentUsbFunctions(long transactionId);
+
+ /**
+ * The function is used to query current USB speed.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void getUsbSpeed(long transactionId);
+
+ /**
+ * This function is used to reset USB gadget driver.
+ * Performs USB data connection reset. The connection will disconnect and
+ * reconnect.
+ */
+ public void reset();
+
+ /**
+ * Invoked to query the version of current gadget hal implementation.
+ */
+ public @UsbHalVersion int getGadgetHalVersion() throws RemoteException;
+
+ /**
+ * This function is used to set the current USB gadget configuration.
+ * The USB gadget needs to be torn down if a USB configuration is already
+ * active.
+ *
+ * @param functions list of functions defined by GadgetFunction to be
+ * included in the gadget composition.
+ * @param timeout The maximum time (in milliseconds) within which the
+ * IUsbGadgetCallback needs to be returned.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void setCurrentUsbFunctions(int request, long functions,
+ boolean chargingFunctions, int timeout, long transactionId);
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
new file mode 100644
index 0000000..d268315
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
@@ -0,0 +1,48 @@
+/*
+ * 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.usb.hal.gadget;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.gadget.UsbGadgetHidl;
+import com.android.server.usb.hal.gadget.UsbGadgetAidl;
+import com.android.server.usb.UsbDeviceManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbGadgetHalInstance {
+
+ public static UsbGadgetHal getInstance(UsbDeviceManager deviceManager,
+ IndentingPrintWriter pw) {
+
+ logAndPrint(Log.DEBUG, pw, "Querying USB Gadget HAL version");
+ if (UsbGadgetAidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, pw, "USB Gadget HAL AIDL present");
+ return new UsbGadgetAidl(deviceManager, pw);
+ }
+ if (UsbGadgetHidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, pw, "USB Gadget HAL HIDL present");
+ return new UsbGadgetHidl(deviceManager, pw);
+ }
+
+ logAndPrint(Log.ERROR, pw, "USB Gadget HAL AIDL/HIDL not present");
+ return null;
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
new file mode 100644
index 0000000..3e5ecc5
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -0,0 +1,261 @@
+/*
+ * 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_0;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_1;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_2;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IHwBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbGadgetHidl implements UsbGadgetHal {
+ // Cookie sent for usb gadget hal death notification.
+ private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+ // Proxy object for the usb gadget hal daemon.
+ @GuardedBy("mGadgetProxyLock")
+ private IUsbGadget mGadgetProxy;
+ private UsbDeviceManager mDeviceManager;
+ private final IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mGadgetProxyLock = new Object();
+ private UsbGadgetCallback mUsbGadgetCallback;
+
+ public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+ int version;
+ synchronized(mGadgetProxyLock) {
+ if (mGadgetProxy == null) {
+ throw new RemoteException("IUsbGadget not initialized yet");
+ }
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ version = UsbManager.GADGET_HAL_V1_2;
+ } else if (android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ version = UsbManager.GADGET_HAL_V1_1;
+ } else {
+ version = UsbManager.GADGET_HAL_V1_0;
+ }
+ logAndPrint(Log.INFO, mPw, "USB Gadget HAL HIDL version: " + version);
+ return version;
+ }
+ }
+
+ final class DeathRecipient implements IHwBinder.DeathRecipient {
+ private final IndentingPrintWriter mPw;
+
+ DeathRecipient(IndentingPrintWriter pw) {
+ mPw = pw;
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+ logAndPrint(Log.ERROR, mPw, "Usb Gadget hal service died cookie: " + cookie);
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ logAndPrint(Log.INFO, mPw, "Usb gadget hal service started " + fqName + " " + name);
+ connectToProxy(null);
+ }
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy != null) {
+ return;
+ }
+
+ try {
+ mGadgetProxy = IUsbGadget.getService();
+ mGadgetProxy.linkToDeath(new DeathRecipient(pw), USB_GADGET_HAL_DEATH_COOKIE);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+ + " Did the service fail to start?", e);
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not responding"
+ , e);
+ }
+ }
+ }
+
+ @Override
+ public void systemReady() {
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ IUsbGadget.getService(true);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hidl hal service not found.", e);
+ return false;
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "IUSBGadget hal service present but failed to get service", e);
+ }
+
+ return true;
+ }
+
+ public UsbGadgetHidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+ mDeviceManager = Objects.requireNonNull(deviceManager);
+ mPw = pw;
+ try {
+ ServiceNotification serviceNotification = new ServiceNotification();
+
+ boolean ret = IServiceManager.getService()
+ .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+ "", serviceNotification);
+ if (!ret) {
+ logAndPrint(Log.ERROR, pw, "Failed to register service start notification");
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "Failed to register service start notification", e);
+ return;
+ }
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void getCurrentUsbFunctions(long transactionId) {
+ try {
+ synchronized(mGadgetProxyLock) {
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getCurrentUsbFunctions", e);
+ return;
+ }
+ }
+
+ @Override
+ public void getUsbSpeed(long transactionId) {
+ try {
+ synchronized(mGadgetProxyLock) {
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+ android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+ gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
+ }
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "get UsbSpeed failed", e);
+ }
+ }
+
+ @Override
+ public void reset() {
+ try {
+ synchronized(mGadgetProxyLock) {
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+ android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+ gadgetProxy.reset();
+ }
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed", e);
+ return;
+ }
+ }
+
+ @Override
+ public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+ boolean mChargingFunctions, int timeout, long operationId) {
+ try {
+ mUsbGadgetCallback = new UsbGadgetCallback(null, mRequest,
+ mFunctions, mChargingFunctions);
+ synchronized(mGadgetProxyLock) {
+ mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback, timeout);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling setCurrentUsbFunctions"
+ + " mRequest = " + mRequest
+ + ", mFunctions = " + mFunctions
+ + ", timeout = " + timeout
+ + ", mChargingFunctions = " + mChargingFunctions
+ + ", operationId =" + operationId, e);
+ return;
+ }
+ }
+
+ private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ public int mRequest;
+ public long mFunctions;
+ public boolean mChargingFunctions;
+
+ UsbGadgetCallback() {
+ }
+ UsbGadgetCallback(IndentingPrintWriter pw, int request,
+ long functions, boolean chargingFunctions) {
+ mRequest = request;
+ mFunctions = functions;
+ mChargingFunctions = chargingFunctions;
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status) {
+ mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ @Override
+ public void getCurrentUsbFunctionsCb(long functions,
+ int status) {
+ mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed) {
+ mDeviceManager.getUsbSpeedCb(speed);
+ }
+ }
+}
+
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index c2b65f8..845449e 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -1020,6 +1020,26 @@
}
/**
+ * Return the encoding type of a received SMS message, which is specified using ENCODING_*
+ * GSM: defined in android.telephony.SmsConstants
+ * CDMA: defined in android.telephony.cdma.UserData
+ *
+ * @hide
+ */
+ public int getReceivedEncodingType() {
+ return mWrappedSmsMessage.getReceivedEncodingType();
+ }
+
+ /**
+ * Check if format of the message is 3GPP.
+ *
+ * @hide
+ */
+ public boolean is3gpp() {
+ return (mWrappedSmsMessage instanceof com.android.internal.telephony.gsm.SmsMessage);
+ }
+
+ /**
* Determines whether or not to use CDMA format for MO SMS.
* If SMS over IMS is supported, then format is based on IMS SMS format,
* otherwise format is based on current phone type.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 13550f0..ac148e7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -478,6 +478,14 @@
public static final String SUBSCRIPTION_TYPE = SimInfo.COLUMN_SUBSCRIPTION_TYPE;
/**
+ * TelephonyProvider column name for last used TP - message Reference
+ * <P>Type: INTEGER (int)</P> with -1 as default value
+ * TP - Message Reference valid range [0 - 255]
+ * @hide
+ */
+ public static final String TP_MESSAGE_REF = SimInfo.COLUMN_TP_MESSAGE_REF;
+
+ /**
* TelephonyProvider column name data_enabled_override_rules.
* It's a list of rules for overriding data enabled settings. The syntax is
* For example, "mms=nonDefault" indicates enabling data for mms in non-default subscription.
@@ -1040,6 +1048,13 @@
public static final String ALLOWED_NETWORK_TYPES =
SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS;
+ /**
+ * TelephonyProvider column name for user handle associated with a sim.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String USER_HANDLE = SimInfo.COLUMN_USER_HANDLE;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"USAGE_SETTING_"},
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 3379ce5..b32f046 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1109,6 +1109,7 @@
sb.append(", ").append(mCarrierId);
sb.append(", ").append(mSkip464Xlat);
sb.append(", ").append(mAlwaysOn);
+ sb.append(", ").append(Objects.hash(mUser, mPassword));
return sb.toString();
}
@@ -1297,8 +1298,6 @@
other.mLingeringNetworkTypeBitmask)
&& Objects.equals(this.mProfileId, other.mProfileId)
&& Objects.equals(this.mPersistent, other.mPersistent)
- && Objects.equals(this.mMvnoType, other.mMvnoType)
- && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
&& Objects.equals(this.mApnSetId, other.mApnSetId)
&& Objects.equals(this.mCarrierId, other.mCarrierId)
&& Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index f65b7c2..945b085 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -1828,6 +1828,8 @@
return getITelephony().isRcsVolteSingleRegistrationCapable(mSubId);
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
}
}
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 6a6c306..74bac22 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -147,7 +147,7 @@
"org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
/**
- * The service ID used to indicate that the Standalone Messaging is available.
+ * The service ID used to indicate that the Chatbot using Standalone Messaging is available.
* <p>
* See the GSMA RCC.07 specification for more information.
*/
@@ -161,6 +161,14 @@
*/
public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+ /**
+ * The service ID used to indicate that the Standalone Messaging is available.
+ * <p>
+ * See the GSMA RCC.07 RCS5_1_advanced_communications_specification_v4.0 specification
+ * for more information.
+ */
+ public static final String SERVICE_ID_SLM = "org.openmobilealliance:StandaloneMsg";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = "SERVICE_ID_", value = {
@@ -177,7 +185,8 @@
SERVICE_ID_SHARED_SKETCH,
SERVICE_ID_CHATBOT,
SERVICE_ID_CHATBOT_STANDALONE,
- SERVICE_ID_CHATBOT_ROLE
+ SERVICE_ID_CHATBOT_ROLE,
+ SERVICE_ID_SLM
})
public @interface ServiceId {}
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 6d46ed3..0cc1e98 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN;
+
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.telephony.SmsMessage;
@@ -94,6 +96,15 @@
protected boolean mMwiDontStore;
/**
+ * The encoding type of a received SMS message, which is specified using ENCODING_*
+ * GSM: defined in android.telephony.SmsConstants
+ * CDMA: defined in android.telephony.cdma.UserData
+ *
+ * @hide
+ */
+ protected int mReceivedEncodingType = ENCODING_UNKNOWN;
+
+ /**
* Indicates status for messages stored on the ICC.
*/
protected int mStatusOnIcc = -1;
@@ -512,4 +523,8 @@
return mRecipientAddress.getAddressString();
}
+
+ public int getReceivedEncodingType() {
+ return mReceivedEncodingType;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index f636276..b51ba31 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -780,6 +780,7 @@
mUserData = mBearerData.userData.payload;
mUserDataHeader = mBearerData.userData.userDataHeader;
mMessageBody = mBearerData.userData.payloadStr;
+ mReceivedEncodingType = mBearerData.userData.msgEncoding;
}
if (mOriginatingAddress != null) {
@@ -860,6 +861,9 @@
Rlog.w(LOG_TAG, "BearerData.decode() returned null");
return null;
}
+ if (bData.userData != null) {
+ mReceivedEncodingType = bData.userData.msgEncoding;
+ }
if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
Rlog.d(LOG_TAG, "MT raw BearerData = " + HexDump.toHexString(mEnvelope.bearerData));
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index b51e8d3d..09ead31 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -249,7 +249,6 @@
ENCODING_UNKNOWN, 0, 0);
}
-
/**
* Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
*
@@ -272,7 +271,7 @@
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- header, encoding, languageTable, languageShiftTable, -1);
+ header, encoding, languageTable, languageShiftTable, -1, 0);
}
/**
@@ -297,6 +296,32 @@
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable, int validityPeriod) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
+ encoding, languageTable, languageShiftTable, validityPeriod, 0);
+ }
+
+ /**
+ * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param header a byte array containing the data for the User Data Header.
+ * @param encoding encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param languageTable
+ * @param languageShiftTable
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @param messageRef TP Message Reference number
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, byte[] header, int encoding,
+ int languageTable, int languageShiftTable, int validityPeriod, int messageRef) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
@@ -350,7 +375,7 @@
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
- statusReportRequested, ret);
+ statusReportRequested, ret, messageRef);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage correctness check.
@@ -496,7 +521,7 @@
String destinationAddress, String message,
boolean statusReportRequested, int validityPeriod) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
- null, ENCODING_UNKNOWN, 0, 0, validityPeriod);
+ null, ENCODING_UNKNOWN, 0, 0, validityPeriod, 0);
}
/**
@@ -507,12 +532,13 @@
* @param destinationPort the port to deliver the message to at the destination.
* @param data the data for the message.
* @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param messageRef TP Message Reference number
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, int destinationPort, byte[] data,
- boolean statusReportRequested) {
+ boolean statusReportRequested, int messageRef) {
SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
portAddrs.destPort = destinationPort;
@@ -533,7 +559,7 @@
SubmitPdu ret = new SubmitPdu();
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
- statusReportRequested, ret);
+ statusReportRequested, ret, messageRef);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage correctness check.
if (bo == null) return ret;
@@ -559,6 +585,24 @@
}
/**
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address & port.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param destinationPort the port to deliver the message to at the destination.
+ * @param data the data for the message.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, int destinationPort, byte[] data,
+ boolean statusReportRequested) {
+ return getSubmitPdu(scAddress, destinationAddress, destinationPort, data,
+ statusReportRequested, 0);
+ }
+
+ /**
* Creates the beginning of a SUBMIT PDU.
*
* This is the part of the SUBMIT PDU that is common to the two versions of
@@ -576,6 +620,28 @@
private static ByteArrayOutputStream getSubmitPduHead(
String scAddress, String destinationAddress, byte mtiByte,
boolean statusReportRequested, SubmitPdu ret) {
+ return getSubmitPduHead(scAddress, destinationAddress, mtiByte, statusReportRequested, ret,
+ 0);
+ }
+
+ /**
+ * Creates the beginning of a SUBMIT PDU.
+ *
+ * This is the part of the SUBMIT PDU that is common to the two versions of
+ * {@link #getSubmitPdu}, one of which takes a byte array and the other of which takes a
+ * <code>String</code>.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param mtiByte
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param ret <code>SubmitPdu</code>.
+ * @param messageRef TP Message Reference number
+ * @return a byte array of the beginning of a SUBMIT PDU. Null for invalid destinationAddress.
+ */
+ private static ByteArrayOutputStream getSubmitPduHead(
+ String scAddress, String destinationAddress, byte mtiByte,
+ boolean statusReportRequested, SubmitPdu ret, int messageRef) {
ByteArrayOutputStream bo = new ByteArrayOutputStream(
MAX_USER_DATA_BYTES + 40);
@@ -596,7 +662,7 @@
bo.write(mtiByte);
// space for TP-Message-Reference
- bo.write(0);
+ bo.write(messageRef);
byte[] daBytes;
@@ -1396,28 +1462,28 @@
} else {
switch ((mDataCodingScheme >> 2) & 0x3) {
case 0: // GSM 7 bit default alphabet
- encodingType = ENCODING_7BIT;
- break;
+ encodingType = ENCODING_7BIT;
+ break;
case 2: // UCS 2 (16bit)
- encodingType = ENCODING_16BIT;
- break;
+ encodingType = ENCODING_16BIT;
+ break;
case 1: // 8 bit data
- //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
- //that's stored in 8-bit unpacked format) characters.
- if (r.getBoolean(com.android.internal.
- R.bool.config_sms_decode_gsm_8bit_data)) {
- encodingType = ENCODING_8BIT;
- break;
- }
+ // Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
+ // string that's stored in 8-bit unpacked format) characters.
+ if (r.getBoolean(com.android.internal
+ .R.bool.config_sms_decode_gsm_8bit_data)) {
+ encodingType = ENCODING_8BIT;
+ break;
+ }
case 3: // reserved
- Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
- + (mDataCodingScheme & 0xff));
- encodingType = r.getInteger(
- com.android.internal.R.integer.default_reserved_data_coding_scheme);
- break;
+ Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
+ + (mDataCodingScheme & 0xff));
+ encodingType = r.getInteger(
+ com.android.internal.R.integer.default_reserved_data_coding_scheme);
+ break;
}
}
} else if ((mDataCodingScheme & 0xf0) == 0xf0) {
@@ -1492,6 +1558,7 @@
encodingType == ENCODING_7BIT);
this.mUserData = p.getUserData();
this.mUserDataHeader = p.getUserDataHeader();
+ this.mReceivedEncodingType = encodingType;
/*
* Look for voice mail indication in TP_UDH TS23.040 9.2.3.24
diff --git a/tests/Internal/src/com/android/internal/app/OWNERS b/tests/Internal/src/com/android/internal/app/OWNERS
new file mode 100644
index 0000000..d55dc78
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/app/OWNERS
@@ -0,0 +1,2 @@
+# Locale related test
+per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index 782439f..98bf541 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -24,12 +24,15 @@
import android.content.Context;
import android.hardware.usb.UsbManager;
+import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Unit tests lib for {@link android.hardware.usb.UsbManager}.
*/
@@ -42,6 +45,11 @@
private UsbManager mUsbManagerMock;
@Mock private android.hardware.usb.IUsbManager mMockUsbService;
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
public UsbManagerTestLib(Context context) {
MockitoAnnotations.initMocks(this);
mContext = context;
@@ -82,10 +90,11 @@
}
private void testSetCurrentFunctionsMock_Matched(long functions) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
setCurrentFunctions(functions);
- verify(mMockUsbService).setCurrentFunctions(eq(functions));
+ verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
} catch (RemoteException remEx) {
Log.w(TAG, "RemoteException");
}
@@ -106,9 +115,10 @@
}
public void testSetCurrentFunctionsEx(long functions) throws Exception {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
setCurrentFunctions(functions);
- verify(mMockUsbService).setCurrentFunctions(eq(functions));
+ verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
}
public void testGetCurrentFunctions_shouldMatched() {
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 861d221..e06a4cb 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -98,7 +98,7 @@
}
@Override
- protected void setEnabledFunctions(long functions, boolean force) {
+ protected void setEnabledFunctions(long functions, boolean force, int operationId) {
mCurrentFunctions = functions;
}
@@ -134,6 +134,20 @@
protected void sendStickyBroadcast(Intent intent) {
mBroadcastedIntent = intent;
}
+
+ @Override
+ public void handlerInitDone(int operationId) {
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed){
+ }
+
}
@Before
diff --git a/tests/VectorDrawableTest/OWNERS b/tests/VectorDrawableTest/OWNERS
new file mode 100644
index 0000000..27e1668
--- /dev/null
+++ b/tests/VectorDrawableTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/OWNERS