Merge "Fuzz java parcel surfaces"
diff --git a/Android.bp b/Android.bp
index b30851c..8e09157 100644
--- a/Android.bp
+++ b/Android.bp
@@ -105,7 +105,7 @@
":android.security.legacykeystore-java-source",
":android.security.maintenance-java-source",
":android.security.metrics-java-source",
- ":android.system.keystore2-V1-java-source",
+ ":android.system.keystore2-V3-java-source",
":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 0e08496..272b4f6 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -328,10 +328,12 @@
java_library {
name: "android_test_stubs_current",
- // Modules do not have test APIs, but we want to include their SystemApis, like we include
- // the SystemApi of framework-non-updatable-sources.
static_libs: [
- "all-modules-system-stubs",
+ // Updatable modules do not have test APIs, but we want to include their SystemApis, like we
+ // include the SystemApi of framework-non-updatable-sources.
+ "all-updatable-modules-system-stubs",
+ // Non-updatable modules on the other hand can have test APIs, so include their test-stubs.
+ "all-non-updatable-modules-test-stubs",
"android-non-updatable.stubs.test",
"private-stub-annotations-jar",
],
diff --git a/api/api.go b/api/api.go
index ba0fdc1..c91ff81 100644
--- a/api/api.go
+++ b/api/api.go
@@ -36,6 +36,8 @@
// built against module_current SDK). Instead they are directly statically
// linked into the all-framework-module-lib, which is building against hidden
// APIs.
+// In addition, the modules in this list are allowed to contribute to test APIs
+// stubs.
var non_updatable_modules = []string{virtualization}
// The intention behind this soong plugin is to generate a number of "merged"
@@ -246,9 +248,33 @@
}
func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
+ // First create the all-updatable-modules-system-stubs
+ {
+ updatable_modules := removeAll(modules, non_updatable_modules)
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-updatable-modules-system-stubs")
+ props.Static_libs = transformArray(updatable_modules, "", ".stubs.system")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+ // Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
+ // into all-modules-system-stubs.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-modules-system-stubs")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.system")
+ props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+}
+
+func createMergedTestStubsForNonUpdatableModules(ctx android.LoadHookContext) {
props := libraryProps{}
- props.Name = proptools.StringPtr("all-modules-system-stubs")
- props.Static_libs = transformArray(modules, "", ".stubs.system")
+ props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.test")
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
ctx.CreateModule(java.LibraryFactory, &props)
@@ -360,6 +386,7 @@
createMergedPublicStubs(ctx, bootclasspath)
createMergedSystemStubs(ctx, bootclasspath)
+ createMergedTestStubsForNonUpdatableModules(ctx)
createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
createMergedFrameworkImpl(ctx, bootclasspath)
diff --git a/core/api/current.txt b/core/api/current.txt
index 01bfecf..7ef4f77 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21574,6 +21574,11 @@
field public static final int AVCProfileHigh422 = 32; // 0x20
field public static final int AVCProfileHigh444 = 64; // 0x40
field public static final int AVCProfileMain = 2; // 0x2
+ field public static final int DTS_HDProfileHRA = 1; // 0x1
+ field public static final int DTS_HDProfileLBR = 2; // 0x2
+ field public static final int DTS_HDProfileMA = 4; // 0x4
+ field public static final int DTS_UHDProfileP1 = 1; // 0x1
+ field public static final int DTS_UHDProfileP2 = 2; // 0x2
field public static final int DolbyVisionLevel8k30 = 1024; // 0x400
field public static final int DolbyVisionLevel8k60 = 2048; // 0x800
field public static final int DolbyVisionLevelFhd24 = 4; // 0x4
@@ -37600,6 +37605,7 @@
field public static final int ERROR_PERMISSION_DENIED = 5; // 0x5
field public static final int ERROR_UNIMPLEMENTED = 12; // 0xc
field public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; // 0x2
+ field public static final int RETRY_AFTER_NEXT_REBOOT = 4; // 0x4
field public static final int RETRY_NEVER = 1; // 0x1
field public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3; // 0x3
field public static final int RETRY_WITH_EXPONENTIAL_BACKOFF = 2; // 0x2
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 03818a5..da961cf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1466,13 +1466,33 @@
method public static boolean isEncodingLinearPcm(int);
}
+ public final class AudioHalVersionInfo implements java.lang.Comparable<android.media.AudioHalVersionInfo> android.os.Parcelable {
+ method public int compareTo(@NonNull android.media.AudioHalVersionInfo);
+ method public int describeContents();
+ method public int getHalType();
+ method public int getMajorVersion();
+ method public int getMinorVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.media.AudioHalVersionInfo AIDL_1_0;
+ field public static final int AUDIO_HAL_TYPE_AIDL = 1; // 0x1
+ field public static final int AUDIO_HAL_TYPE_HIDL = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioHalVersionInfo> CREATOR;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_2_0;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_4_0;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_5_0;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_6_0;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_7_0;
+ field @NonNull public static final android.media.AudioHalVersionInfo HIDL_7_1;
+ field @NonNull public static final java.util.List<android.media.AudioHalVersionInfo> VERSIONS;
+ }
+
public class AudioManager {
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
- method @Nullable public static String getHalVersion();
+ method @Nullable public static android.media.AudioHalVersionInfo getHalVersion();
method public static final int[] getPublicStreamTypes();
method @NonNull public java.util.List<java.lang.Integer> getReportedSurroundFormats();
method public int getStreamMinVolumeInt(int);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 2d244a9..aa56105 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -366,7 +366,7 @@
*/
public static final int getCallingUidOrWtf() {
if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
- Log.wtf(TAG,
+ Log.wtfStack(TAG,
"Thread is not in a binder transaction, "
+ "and the calling identity has not been "
+ "explicitly set with clearCallingIdentity");
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e720f1a..4d6422c 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -126,6 +126,8 @@
Tag.BOOT_PATCHLEVEL; // KM_UINT | 719;
public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION =
Tag.DEVICE_UNIQUE_ATTESTATION; // KM_BOOL | 720;
+ public static final int KM_TAG_ATTESTATION_ID_SECOND_IMEI =
+ Tag.ATTESTATION_ID_SECOND_IMEI; // KM_BYTES | 723;
public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
diff --git a/core/tests/fuzzers/java_service_fuzzer/Android.bp b/core/tests/fuzzers/java_service_fuzzer/Android.bp
index 625de14..6acb198 100644
--- a/core/tests/fuzzers/java_service_fuzzer/Android.bp
+++ b/core/tests/fuzzers/java_service_fuzzer/Android.bp
@@ -37,4 +37,12 @@
"framework-res",
],
native_bridge_supported: true,
+ fuzz_config: {
+ cc: [
+ "smoreland@google.com",
+ "waghpawan@google.com",
+ ],
+ // Adds bugs to hotlist "AIDL fuzzers bugs" on buganizer
+ hotlists: ["4637097"],
+ },
}
diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java
index 1a81dda..6536e43 100644
--- a/keystore/java/android/security/KeyStoreException.java
+++ b/keystore/java/android/security/KeyStoreException.java
@@ -138,6 +138,16 @@
* provisioning server refuses key issuance, this is a permanent error.</p>
*/
public static final int ERROR_ATTESTATION_KEYS_UNAVAILABLE = 16;
+ /**
+ * This device requires a software upgrade to use the key provisioning server. The software
+ * is outdated and this error is returned only on devices that rely solely on
+ * remotely-provisioned keys (see <a href=
+ * "https://android-developers.googleblog.com/2022/03/upgrading-android-attestation-remote.html"
+ * >Remote Key Provisioning</a>).
+ *
+ * @hide
+ */
+ public static final int ERROR_DEVICE_REQUIRES_UPGRADE_FOR_ATTESTATION = 17;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -157,7 +167,8 @@
ERROR_INCORRECT_USAGE,
ERROR_KEY_NOT_TEMPORALLY_VALID,
ERROR_KEY_OPERATION_EXPIRED,
- ERROR_ATTESTATION_KEYS_UNAVAILABLE
+ ERROR_ATTESTATION_KEYS_UNAVAILABLE,
+ ERROR_DEVICE_REQUIRES_UPGRADE_FOR_ATTESTATION,
})
public @interface PublicErrorCode {
}
@@ -184,6 +195,16 @@
* This value is returned when {@link #isTransientFailure()} is {@code true}.
*/
public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3;
+ /**
+ * Re-try the operation that led to this error when the device has a software update
+ * downloaded and on the next reboot. The Remote provisioning server recognizes
+ * the device, but refuses issuance of attestation keys because it contains a software
+ * version that could potentially be vulnerable and needs an update. Re-trying after the
+ * device has upgraded and rebooted may alleviate the problem.
+ *
+ * <p>This value is returned when {@link #isTransientFailure()} is {@code true}.
+ */
+ public static final int RETRY_AFTER_NEXT_REBOOT = 4;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -191,6 +212,7 @@
RETRY_NEVER,
RETRY_WITH_EXPONENTIAL_BACKOFF,
RETRY_WHEN_CONNECTIVITY_AVAILABLE,
+ RETRY_AFTER_NEXT_REBOOT,
})
public @interface RetryPolicy {
}
@@ -217,6 +239,13 @@
* when the device has connectivity again.
* @hide */
public static final int RKP_FETCHING_PENDING_CONNECTIVITY = 3;
+ /**
+ * The RKP server recognizes the device, but the device may be running vulnerable software,
+ * and thus refusing issuance of RKP keys to it.
+ *
+ * @hide
+ */
+ public static final int RKP_FETCHING_PENDING_SOFTWARE_REBOOT = 4;
// Constants for encoding information about the error encountered:
// Whether the error relates to the system state/implementation as a whole, or a specific key.
@@ -236,7 +265,7 @@
private static int initializeRkpStatusForRegularErrors(int errorCode) {
// Check if the system code mistakenly called a constructor of KeyStoreException with
// the OUT_OF_KEYS error code but without RKP status.
- if (errorCode == ResponseCode.OUT_OF_KEYS) {
+ if (isRkpRelatedError(errorCode)) {
Log.e(TAG, "RKP error code without RKP status");
// Set RKP status to RKP_SERVER_REFUSED_ISSUANCE so that the caller never retries.
return RKP_SERVER_REFUSED_ISSUANCE;
@@ -272,7 +301,7 @@
super(message);
mErrorCode = errorCode;
mRkpStatus = rkpStatus;
- if (mErrorCode != ResponseCode.OUT_OF_KEYS) {
+ if (!isRkpRelatedError(mErrorCode)) {
Log.e(TAG, "Providing RKP status for error code " + errorCode + " has no effect.");
}
}
@@ -309,10 +338,11 @@
public boolean isTransientFailure() {
PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
// Special-case handling for RKP failures:
- if (mRkpStatus != RKP_SUCCESS && mErrorCode == ResponseCode.OUT_OF_KEYS) {
+ if (mRkpStatus != RKP_SUCCESS && isRkpRelatedError(mErrorCode)) {
switch (mRkpStatus) {
case RKP_TEMPORARILY_UNAVAILABLE:
case RKP_FETCHING_PENDING_CONNECTIVITY:
+ case RKP_FETCHING_PENDING_SOFTWARE_REBOOT:
return true;
case RKP_SERVER_REFUSED_ISSUANCE:
default:
@@ -346,6 +376,11 @@
return (failureInfo.indicators & IS_SYSTEM_ERROR) != 0;
}
+ private static boolean isRkpRelatedError(int errorCode) {
+ return errorCode == ResponseCode.OUT_OF_KEYS
+ || errorCode == ResponseCode.OUT_OF_KEYS_REQUIRES_UPGRADE;
+ }
+
/**
* Returns the re-try policy for transient failures. Valid only if
* {@link #isTransientFailure()} returns {@code True}.
@@ -362,6 +397,8 @@
return RETRY_WHEN_CONNECTIVITY_AVAILABLE;
case RKP_SERVER_REFUSED_ISSUANCE:
return RETRY_NEVER;
+ case RKP_FETCHING_PENDING_SOFTWARE_REBOOT:
+ return RETRY_AFTER_NEXT_REBOOT;
default:
return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0
? RETRY_WITH_EXPONENTIAL_BACKOFF : RETRY_NEVER;
@@ -620,5 +657,8 @@
new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST));
sErrorCodeToFailureInfo.put(ResponseCode.OUT_OF_KEYS,
new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_ATTESTATION_KEYS_UNAVAILABLE));
+ sErrorCodeToFailureInfo.put(ResponseCode.OUT_OF_KEYS_REQUIRES_UPGRADE,
+ new PublicErrorInformation(IS_SYSTEM_ERROR | IS_TRANSIENT_ERROR,
+ ERROR_DEVICE_REQUIRES_UPGRADE_FOR_ATTESTATION));
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index acc0005..2830d7eff 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -52,6 +52,7 @@
import android.system.keystore2.KeyMetadata;
import android.system.keystore2.ResponseCode;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -647,6 +648,7 @@
// {@link android.security.KeyStoreException#RKP_TEMPORARILY_UNAVAILABLE},
// {@link android.security.KeyStoreException#RKP_SERVER_REFUSED_ISSUANCE},
// {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_CONNECTIVITY}
+ // {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_SOFTWARE_REBOOT}
public final int rkpStatus;
@Nullable
public final KeyPair keyPair;
@@ -856,6 +858,13 @@
KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
imei.getBytes(StandardCharsets.UTF_8)
));
+ final String secondImei = telephonyService.getImei(1);
+ if (!TextUtils.isEmpty(secondImei)) {
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_SECOND_IMEI,
+ secondImei.getBytes(StandardCharsets.UTF_8)
+ ));
+ }
break;
}
case AttestationUtils.ID_TYPE_MEID: {
diff --git a/media/java/android/media/AudioHalVersionInfo.aidl b/media/java/android/media/AudioHalVersionInfo.aidl
new file mode 100644
index 0000000..a83f8c8
--- /dev/null
+++ b/media/java/android/media/AudioHalVersionInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable AudioHalVersionInfo;
diff --git a/media/java/android/media/AudioHalVersionInfo.java b/media/java/android/media/AudioHalVersionInfo.java
new file mode 100644
index 0000000..985a758
--- /dev/null
+++ b/media/java/android/media/AudioHalVersionInfo.java
@@ -0,0 +1,174 @@
+/*
+ * 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Defines the audio HAL version.
+ *
+ * @hide
+ */
+@TestApi
+public final class AudioHalVersionInfo implements Parcelable, Comparable<AudioHalVersionInfo> {
+ /**
+ * Indicate the audio HAL is implemented with HIDL (HAL interface definition language).
+ *
+ * @see <a href="https://source.android.com/docs/core/architecture/hidl/">HIDL</a>
+ * <p>The value of AUDIO_HAL_TYPE_HIDL should match the value of {@link
+ * android.media.AudioHalVersion.Type#HIDL}.
+ */
+ public static final int AUDIO_HAL_TYPE_HIDL = 0;
+
+ /**
+ * Indicate the audio HAL is implemented with AIDL (Android Interface Definition Language).
+ *
+ * @see <a href="https://source.android.com/docs/core/architecture/aidl/">AIDL</a>
+ * <p>The value of AUDIO_HAL_TYPE_AIDL should match the value of {@link
+ * android.media.AudioHalVersion.Type#AIDL}.
+ */
+ public static final int AUDIO_HAL_TYPE_AIDL = 1;
+
+ /** @hide */
+ @IntDef(
+ flag = false,
+ prefix = "AUDIO_HAL_TYPE_",
+ value = {AUDIO_HAL_TYPE_HIDL, AUDIO_HAL_TYPE_AIDL})
+ public @interface AudioHalType {}
+
+ /** AudioHalVersionInfo object of all valid Audio HAL versions. */
+ public static final @NonNull AudioHalVersionInfo AIDL_1_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_AIDL, 1 /* major */, 0 /* minor */);
+
+ public static final @NonNull AudioHalVersionInfo HIDL_7_1 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 7 /* major */, 1 /* minor */);
+ public static final @NonNull AudioHalVersionInfo HIDL_7_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 7 /* major */, 0 /* minor */);
+ public static final @NonNull AudioHalVersionInfo HIDL_6_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 6 /* major */, 0 /* minor */);
+ public static final @NonNull AudioHalVersionInfo HIDL_5_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 5 /* major */, 0 /* minor */);
+ public static final @NonNull AudioHalVersionInfo HIDL_4_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 4 /* major */, 0 /* minor */);
+ public static final @NonNull AudioHalVersionInfo HIDL_2_0 =
+ new AudioHalVersionInfo(AUDIO_HAL_TYPE_HIDL, 2 /* major */, 0 /* minor */);
+
+ /**
+ * List of all valid Audio HAL versions. This list need to be in sync with sAudioHALVersions
+ * defined in frameworks/av/media/libaudiohal/FactoryHalHidl.cpp.
+ */
+ // TODO: add AIDL_1_0 with sAudioHALVersions.
+ public static final @NonNull List<AudioHalVersionInfo> VERSIONS =
+ List.of(HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0);
+
+ private static final String TAG = "AudioHalVersionInfo";
+ private AudioHalVersion mHalVersion = new AudioHalVersion();
+
+ public @AudioHalType int getHalType() {
+ return mHalVersion.type;
+ }
+
+ public int getMajorVersion() {
+ return mHalVersion.major;
+ }
+
+ public int getMinorVersion() {
+ return mHalVersion.minor;
+ }
+
+ /** String representative of AudioHalVersion.Type */
+ private static @NonNull String typeToString(@AudioHalType int type) {
+ if (type == AudioHalVersion.Type.HIDL) {
+ return "HIDL";
+ } else if (type == AudioHalVersion.Type.AIDL) {
+ return "AIDL";
+ } else {
+ return "INVALID";
+ }
+ }
+
+ /** String representative of type, major and minor */
+ private static @NonNull String toString(@AudioHalType int type, int major, int minor) {
+ return typeToString(type) + ":" + Integer.toString(major) + "." + Integer.toString(minor);
+ }
+
+ private AudioHalVersionInfo(@AudioHalType int type, int major, int minor) {
+ mHalVersion.type = type;
+ mHalVersion.major = major;
+ mHalVersion.minor = minor;
+ }
+
+ private AudioHalVersionInfo(Parcel in) {
+ mHalVersion = in.readTypedObject(AudioHalVersion.CREATOR);
+ }
+
+ /** String representative of this (AudioHalVersionInfo) object */
+ @Override
+ public String toString() {
+ return toString(mHalVersion.type, mHalVersion.major, mHalVersion.minor);
+ }
+
+ /**
+ * Compare two HAL versions by comparing their index in VERSIONS.
+ *
+ * <p>Normally all AudioHalVersionInfo object to compare should exist in the VERSIONS list. If
+ * both candidates exist in the VERSIONS list, smaller index means newer. Any candidate not
+ * exist in the VERSIONS list will be considered to be oldest version.
+ *
+ * @return 0 if the HAL version is the same as the other HAL version. Positive if the HAL
+ * version is newer than the other HAL version. Negative if the HAL version is older than
+ * the other version.
+ */
+ @Override
+ public int compareTo(@NonNull AudioHalVersionInfo other) {
+ int indexOther = VERSIONS.indexOf(other);
+ int indexThis = VERSIONS.indexOf(this);
+ if (indexThis < 0 || indexOther < 0) {
+ return indexThis - indexOther;
+ }
+ return indexOther - indexThis;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel out, int flag) {
+ out.writeTypedObject(mHalVersion, flag);
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioHalVersionInfo> CREATOR =
+ new Parcelable.Creator<AudioHalVersionInfo>() {
+ @Override
+ public AudioHalVersionInfo createFromParcel(@NonNull Parcel in) {
+ return new AudioHalVersionInfo(in);
+ }
+
+ @Override
+ public AudioHalVersionInfo[] newArray(int size) {
+ return new AudioHalVersionInfo[size];
+ }
+ };
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c3e605e..399650d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -8462,13 +8462,14 @@
}
/**
- * Returns the audio HAL version in the form MAJOR.MINOR. If there is no audio HAL found, null
- * will be returned.
+ * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
+ * HAL found, null will be returned.
*
+ * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
* @hide
*/
@TestApi
- public static @Nullable String getHalVersion() {
+ public static @Nullable AudioHalVersionInfo getHalVersion() {
try {
return getService().getHalVersion();
} catch (RemoteException e) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
old mode 100755
new mode 100644
index e28178a..3b33ecd
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -22,6 +22,7 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioFormat;
import android.media.AudioFocusInfo;
+import android.media.AudioHalVersionInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
@@ -512,5 +513,5 @@
in AudioDeviceAttributes device, in List<VolumeInfo> volumes,
boolean handlesvolumeAdjustment);
- String getHalVersion();
+ AudioHalVersionInfo getHalVersion();
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index bf30c50..30d90a8 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -4106,6 +4106,22 @@
public static final int AV1Level72 = 0x400000;
public static final int AV1Level73 = 0x800000;
+ /** DTS codec profile for DTS HRA. */
+ @SuppressLint("AllUpper")
+ public static final int DTS_HDProfileHRA = 0x1;
+ /** DTS codec profile for DTS Express. */
+ @SuppressLint("AllUpper")
+ public static final int DTS_HDProfileLBR = 0x2;
+ /** DTS codec profile for DTS-HD Master Audio */
+ @SuppressLint("AllUpper")
+ public static final int DTS_HDProfileMA = 0x4;
+ /** DTS codec profile for DTS:X Profile 1 */
+ @SuppressLint("AllUpper")
+ public static final int DTS_UHDProfileP1 = 0x1;
+ /** DTS codec profile for DTS:X Profile 2 */
+ @SuppressLint("AllUpper")
+ public static final int DTS_UHDProfileP2 = 0x2;
+
/**
* The profile of the media content. Depending on the type of media this can be
* one of the profile values defined in this class.
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index be1e6fe..721f93b 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -82,6 +82,7 @@
import android.media.AudioFocusInfo;
import android.media.AudioFocusRequest;
import android.media.AudioFormat;
+import android.media.AudioHalVersionInfo;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPlaybackConfiguration;
@@ -6289,9 +6290,13 @@
return AudioSystem.STREAM_RING;
} else if (wasStreamActiveRecently(
AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
- if (DEBUG_VOL)
- Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
- return AudioSystem.STREAM_NOTIFICATION;
+ if (DEBUG_VOL) {
+ Log.v(
+ TAG,
+ "getActiveStreamType: Forcing STREAM_NOTIFICATION stream"
+ + " active");
+ }
+ return AudioSystem.STREAM_NOTIFICATION;
} else {
if (DEBUG_VOL) {
Log.v(TAG, "getActiveStreamType: Forcing DEFAULT_VOL_STREAM_NO_PLAYBACK("
@@ -10825,15 +10830,16 @@
return mMediaFocusControl.sendFocusLoss(focusLoser);
}
- private static final String[] HAL_VERSIONS =
- new String[] {"7.1", "7.0", "6.0", "5.0", "4.0", "2.0"};
-
- /** @see AudioManager#getHalVersion */
- public @Nullable String getHalVersion() {
- for (String version : HAL_VERSIONS) {
+ /**
+ * @see AudioManager#getHalVersion
+ */
+ public @Nullable AudioHalVersionInfo getHalVersion() {
+ for (AudioHalVersionInfo version : AudioHalVersionInfo.VERSIONS) {
try {
+ // TODO: check AIDL service.
+ String versionStr = version.getMajorVersion() + "." + version.getMinorVersion();
HwBinder.getService(
- String.format("android.hardware.audio@%s::IDevicesFactory", version),
+ String.format("android.hardware.audio@%s::IDevicesFactory", versionStr),
"default");
return version;
} catch (NoSuchElementException e) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
new file mode 100644
index 0000000..cbe6d26
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
+import android.net.LinkAddress;
+import android.net.NetworkPolicyManager;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.server.NetworkManagementService.Dependencies;
+import com.android.server.net.BaseNetworkObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.BiFunction;
+
+/**
+ * Tests for {@link NetworkManagementService}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkManagementServiceTest {
+ private NetworkManagementService mNMService;
+ @Mock private Context mContext;
+ @Mock private ConnectivityManager mCm;
+ @Mock private IBatteryStats.Stub mBatteryStatsService;
+ @Mock private INetd.Stub mNetdService;
+
+ private static final int TEST_UID = 111;
+
+ @NonNull
+ @Captor
+ private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
+
+ private final MockDependencies mDeps = new MockDependencies();
+
+ private final class MockDependencies extends Dependencies {
+ @Override
+ public IBinder getService(String name) {
+ switch (name) {
+ case BatteryStats.SERVICE_NAME:
+ return mBatteryStatsService;
+ default:
+ throw new UnsupportedOperationException("Unknown service " + name);
+ }
+ }
+
+ @Override
+ public void registerLocalService(NetworkManagementInternal nmi) {
+ }
+
+ @Override
+ public INetd getNetd() {
+ return mNetdService;
+ }
+
+ @Override
+ public int getCallingUid() {
+ return Process.SYSTEM_UID;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doNothing().when(mNetdService)
+ .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
+ doReturn(Context.CONNECTIVITY_SERVICE).when(mContext).getSystemServiceName(
+ eq(ConnectivityManager.class));
+ doReturn(mCm).when(mContext).getSystemService(eq(Context.CONNECTIVITY_SERVICE));
+ // Start the service and wait until it connects to our socket.
+ mNMService = NetworkManagementService.create(mContext, mDeps);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mNMService.shutdown();
+ }
+
+ private static <T> T expectSoon(T mock) {
+ return verify(mock, timeout(200));
+ }
+
+ /**
+ * Tests that network observers work properly.
+ */
+ @Test
+ public void testNetworkObservers() throws Exception {
+ BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
+ doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver.
+ mNMService.registerObserver(observer);
+
+ // Forget everything that happened to the mock so far, so we can explicitly verify
+ // everything that happens and does not happen to it from now on.
+
+ INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
+ reset(observer);
+ // Now call unsolListener methods and ensure that the observer methods are
+ // called. After every method we expect a callback soon after; to ensure that
+ // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
+
+ /**
+ * Interface changes.
+ */
+ unsolListener.onInterfaceAdded("rmnet12");
+ expectSoon(observer).interfaceAdded("rmnet12");
+
+ unsolListener.onInterfaceRemoved("eth1");
+ expectSoon(observer).interfaceRemoved("eth1");
+
+ unsolListener.onInterfaceChanged("clat4", true);
+ expectSoon(observer).interfaceStatusChanged("clat4", true);
+
+ unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
+ expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
+
+ /**
+ * Bandwidth control events.
+ */
+ unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
+ expectSoon(observer).limitReached("data", "rmnet_usb0");
+
+ /**
+ * Interface class activity.
+ */
+ unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
+
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
+
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
+
+ /**
+ * IP address changes.
+ */
+ unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
+ expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
+
+ unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
+ expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
+
+ unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
+ expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
+
+ /**
+ * DNS information broadcasts.
+ */
+ unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
+ expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
+ new String[]{"2001:db8::1"});
+
+ unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
+ new String[]{"2001:db8::1", "2001:db8::2"});
+ expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
+ new String[]{"2001:db8::1", "2001:db8::2"});
+
+ // We don't check for negative lifetimes, only for parse errors.
+ unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
+ expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
+ new String[]{"::1"});
+
+ // No syntax checking on the addresses.
+ unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
+ new String[]{"", "::", "", "foo", "::1"});
+ expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
+ new String[]{"", "::", "", "foo", "::1"});
+
+ // Make sure nothing else was called.
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testFirewallEnabled() {
+ mNMService.setFirewallEnabled(true);
+ assertTrue(mNMService.isFirewallEnabled());
+
+ mNMService.setFirewallEnabled(false);
+ assertFalse(mNMService.isFirewallEnabled());
+ }
+
+ @Test
+ public void testNetworkRestrictedDefault() {
+ assertFalse(mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ public void testMeteredNetworkRestrictions() throws RemoteException {
+ // Make sure the mocked netd method returns true.
+ doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
+
+ // Restrict usage of mobile data in background
+ mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
+ assertTrue("Should be true since mobile data usage is restricted",
+ mNMService.isNetworkRestricted(TEST_UID));
+ verify(mCm).addUidToMeteredNetworkDenyList(TEST_UID);
+
+ mNMService.setDataSaverModeEnabled(true);
+ verify(mNetdService).bandwidthEnableDataSaver(true);
+
+ mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
+ assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+ verify(mCm).removeUidFromMeteredNetworkDenyList(TEST_UID);
+
+ mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
+ assertFalse("Should be false since data saver is on and the uid is allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+ verify(mCm).addUidToMeteredNetworkAllowList(TEST_UID);
+
+ // remove uid from allowlist and turn datasaver off again
+ mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
+ verify(mCm).removeUidFromMeteredNetworkAllowList(TEST_UID);
+ mNMService.setDataSaverModeEnabled(false);
+ verify(mNetdService).bandwidthEnableDataSaver(false);
+ assertFalse("Network should not be restricted when data saver is off",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ public void testFirewallChains() {
+ final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
+ // Dozable chain
+ final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
+ isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
+ // Powersaver chain
+ final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
+ isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
+ // Standby chain
+ final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
+ isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
+ isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
+ // Restricted mode chain
+ final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
+ isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+ // Low Power Standby chain
+ final ArrayMap<Integer, Boolean> isRestrictedForLowPowerStandby = new ArrayMap<>();
+ isRestrictedForLowPowerStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForLowPowerStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForLowPowerStandby.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(FIREWALL_CHAIN_LOW_POWER_STANDBY, isRestrictedForLowPowerStandby);
+
+ final int[] chains = {
+ FIREWALL_CHAIN_STANDBY,
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_RESTRICTED,
+ FIREWALL_CHAIN_LOW_POWER_STANDBY
+ };
+ final int[] states = {
+ INetd.FIREWALL_RULE_ALLOW,
+ INetd.FIREWALL_RULE_DENY,
+ NetworkPolicyManager.FIREWALL_RULE_DEFAULT
+ };
+ BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
+ return String.format("Unexpected value for chain: %s and state: %s",
+ valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
+ valueToString(INetd.class, "FIREWALL_RULE_", state));
+ };
+ for (int chain : chains) {
+ final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
+ mNMService.setFirewallChainEnabled(chain, true);
+ verify(mCm).setFirewallChainEnabled(chain, true /* enabled */);
+ for (int state : states) {
+ mNMService.setFirewallUidRule(chain, TEST_UID, state);
+ assertEquals(errorMsg.apply(chain, state),
+ expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
+ }
+ mNMService.setFirewallChainEnabled(chain, false);
+ verify(mCm).setFirewallChainEnabled(chain, false /* enabled */);
+ }
+ }
+}