summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java331
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java128
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java69
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java115
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java193
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java139
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java532
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java149
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java359
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java63
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java146
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java82
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java74
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java92
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java210
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java84
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java107
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/module-lib-current.txt2
-rw-r--r--core/api/system-current.txt6
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl7
-rw-r--r--core/java/android/hardware/usb/IUsbOperationInternal.aidl24
-rw-r--r--core/java/android/hardware/usb/UsbManager.java66
-rw-r--r--core/java/android/hardware/usb/UsbOperationInternal.java131
-rw-r--r--core/java/android/hardware/usb/UsbPort.java97
-rw-r--r--core/java/android/hardware/usb/UsbPortStatus.java97
-rw-r--r--core/java/android/net/VpnProfileState.java16
-rwxr-xr-xcore/java/android/os/Build.java5
-rw-r--r--core/java/android/permission/OWNERS10
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/java/android/speech/OWNERS1
-rw-r--r--core/java/android/view/View.java8
-rw-r--r--core/java/com/android/internal/usb/DumpUtils.java3
-rw-r--r--core/jni/OWNERS1
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp67
-rw-r--r--core/proto/android/os/system_properties.proto4
-rw-r--r--core/proto/android/service/usb.proto11
-rw-r--r--core/res/OWNERS6
-rw-r--r--core/res/res/values/config.xml70
-rw-r--r--core/res/res/values/config_telephony.xml112
-rw-r--r--core/res/res/values/symbols.xml16
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/PackageInstallerSessions/Android.bp1
-rw-r--r--core/tests/bugreports/Android.bp1
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--packages/CtsShim/build/Android.bp6
-rw-r--r--packages/CtsShim/build/jni/Android.bp1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt2
-rw-r--r--services/core/java/com/android/server/BootReceiver.java30
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java13
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java377
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java28
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java10
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java29
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java72
-rw-r--r--services/usb/Android.bp1
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java512
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java22
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java136
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java476
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java169
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java45
-rw-r--r--services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java471
-rw-r--r--telephony/java/Android.bp9
-rw-r--r--telephony/java/android/telephony/AnomalyReporter.java9
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java21
-rw-r--r--tools/aapt2/SdkConstants.cpp2
-rw-r--r--tools/bit/adb.cpp4
-rw-r--r--tools/bit/main.cpp126
75 files changed, 5483 insertions, 793 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
new file mode 100644
index 000000000000..d38d5197b937
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
@@ -0,0 +1,331 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class AnnotatedElementPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Class<?> mType;
+ private Field mField;
+ private Method mMethod;
+
+ @Before
+ public void setUp() throws Exception {
+ mType = Type.class;
+ mField = Type.class.getField("field");
+ mMethod = Type.class.getMethod("method", String.class);
+ }
+
+ // get annotations by member type and method
+
+ @Test
+ public void timeGetTypeAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetFieldAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetMethodAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetParameterAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getParameterAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetTypeAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeGetFieldAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeGetMethodAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.getAnnotation(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsTypeAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mType.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsFieldAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mField.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ @Test
+ public void timeIsMethodAnnotationPresent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mMethod.isAnnotationPresent(Marker.class);
+ }
+ }
+
+ // get annotations by result size
+
+ @Test
+ public void timeGetAllReturnsLargeAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasLargeAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsSmallAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsMarkerAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasMarkerAnnotation.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsNoAnnotation() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasNoAnnotations.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetAllReturnsThreeAnnotations() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasThreeAnnotations.class.getAnnotations();
+ }
+ }
+
+ // get annotations with inheritance
+
+ @Test
+ public void timeGetAnnotationsOnSubclass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ExtendsHasThreeAnnotations.class.getAnnotations();
+ }
+ }
+
+ @Test
+ public void timeGetDeclaredAnnotationsOnSubclass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ExtendsHasThreeAnnotations.class.getDeclaredAnnotations();
+ }
+ }
+
+ // get annotations with enclosing / inner classes
+
+ @Test
+ public void timeGetDeclaredClasses() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ AnnotatedElementPerfTest.class.getDeclaredClasses();
+ }
+ }
+
+ @Test
+ public void timeGetDeclaringClass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getDeclaringClass();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingClass() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingClass();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingConstructor() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingConstructor();
+ }
+ }
+
+ @Test
+ public void timeGetEnclosingMethod() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().getEnclosingMethod();
+ }
+ }
+
+ @Test
+ public void timeGetModifiers() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getModifiers();
+ }
+ }
+
+ @Test
+ public void timeGetSimpleName() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.getSimpleName();
+ }
+ }
+
+ @Test
+ public void timeIsAnonymousClass() {
+ Object anonymousClass = new Object() {};
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ anonymousClass.getClass().isAnonymousClass();
+ }
+ }
+
+ @Test
+ public void timeIsLocalClass() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ HasSmallAnnotation.class.isLocalClass();
+ }
+ }
+
+ // the annotated elements
+
+ @Marker
+ public class Type {
+ @Marker public String field;
+
+ @Marker
+ public void method(@Marker String parameter) {}
+ }
+
+ @Large(
+ a = "on class",
+ b = {"A", "B", "C"},
+ c = @Small(e = "E1", f = 1695938256, g = 7264081114510713000L),
+ d = {@Small(e = "E2", f = 1695938256, g = 7264081114510713000L)})
+ public class HasLargeAnnotation {}
+
+ @Small(e = "E1", f = 1695938256, g = 7264081114510713000L)
+ public class HasSmallAnnotation {}
+
+ @Marker
+ public class HasMarkerAnnotation {}
+
+ public class HasNoAnnotations {}
+
+ @Large(
+ a = "on class",
+ b = {"A", "B", "C"},
+ c = @Small(e = "E1", f = 1695938256, g = 7264081114510713000L),
+ d = {@Small(e = "E2", f = 1695938256, g = 7264081114510713000L)})
+ @Small(e = "E1", f = 1695938256, g = 7264081114510713000L)
+ @Marker
+ public class HasThreeAnnotations {}
+
+ public class ExtendsHasThreeAnnotations extends HasThreeAnnotations {}
+
+ // the annotations
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Marker {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Large {
+ String a() default "";
+
+ String[] b() default {};
+
+ Small c() default @Small;
+
+ Small[] d() default {};
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Small {
+ String e() default "";
+
+ int f() default 0;
+
+ long g() default 0L;
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
new file mode 100644
index 000000000000..cc56868468e5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigDecimal;
+import java.text.AttributedCharacterIterator;
+import java.text.Bidi;
+import java.text.DecimalFormat;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BidiPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final AttributedCharacterIterator CHAR_ITER =
+ DecimalFormat.getInstance().formatToCharacterIterator(new BigDecimal(Math.PI));
+
+ @Test
+ public void time_createBidiFromIter() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bidi = new Bidi(CHAR_ITER);
+ }
+ }
+
+ @Test
+ public void time_createBidiFromCharArray() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ new char[] {'s', 's', 's'},
+ 0,
+ new byte[] {(byte) 1, (byte) 2, (byte) 3},
+ 0,
+ 3,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ }
+ }
+
+ @Test
+ public void time_createBidiFromString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bidi = new Bidi("Hello", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ }
+ }
+
+ @Test
+ public void time_reorderVisually() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi.reorderVisually(
+ new byte[] {2, 1, 3, 0, 4}, 0, new String[] {"H", "e", "l", "l", "o"}, 0, 5);
+ }
+ }
+
+ @Test
+ public void time_hebrewBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ new char[] {'\u05D0', '\u05D0', '\u05D0'},
+ 0,
+ new byte[] {(byte) -1, (byte) -2, (byte) -3},
+ 0,
+ 3,
+ Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ bd =
+ new Bidi(
+ new char[] {'\u05D0', '\u05D0', '\u05D0'},
+ 0,
+ new byte[] {(byte) -1, (byte) -2, (byte) -3},
+ 0,
+ 3,
+ Bidi.DIRECTION_LEFT_TO_RIGHT);
+ }
+ }
+
+ @Test
+ public void time_complicatedOverrideBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi bd =
+ new Bidi(
+ "a\u05D0a\"a\u05D0\"\u05D0a".toCharArray(),
+ 0,
+ new byte[] {0, 0, 0, -3, -3, 2, 2, 0, 3},
+ 0,
+ 9,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ }
+ }
+
+ @Test
+ public void time_requiresBidi() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1); // false.
+ Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1); // true.
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
new file mode 100644
index 000000000000..662694b1b5d1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BigIntegerPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeRandomDivision() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.divide(y);
+ }
+ }
+
+ @Test
+ public void timeRandomGcd() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.gcd(y);
+ }
+ }
+
+ @Test
+ public void timeRandomMultiplication() throws Exception {
+ Random r = new Random();
+ BigInteger x = new BigInteger(1024, r);
+ BigInteger y = new BigInteger(1024, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ x.multiply(y);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
new file mode 100644
index 000000000000..db5462cd69bf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class BitSetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mSize={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{1000}, {10000}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int mSize;
+
+ private BitSet mBitSet;
+
+ @Before
+ public void setUp() throws Exception {
+ mBitSet = new BitSet(mSize);
+ }
+
+ @Test
+ public void timeIsEmptyTrue() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ if (!mBitSet.isEmpty()) throw new RuntimeException();
+ }
+ }
+
+ @Test
+ public void timeIsEmptyFalse() {
+ mBitSet.set(mBitSet.size() - 1);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ if (mBitSet.isEmpty()) throw new RuntimeException();
+ }
+ }
+
+ @Test
+ public void timeGet() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 1;
+ while (state.keepRunning()) {
+ mBitSet.get(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeClear() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 1;
+ while (state.keepRunning()) {
+ mBitSet.clear(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeSet() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize);
+ }
+ }
+
+ @Test
+ public void timeSetOn() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize, true);
+ }
+ }
+
+ @Test
+ public void timeSetOff() {
+ int i = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mBitSet.set(++i % mSize, false);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
new file mode 100644
index 000000000000..3952c12b3bfe
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.text.BreakIterator;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public final class BreakIteratorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum Text {
+ LIPSUM(
+ Locale.US,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi mollis consequat"
+ + " nisl non pharetra. Praesent pretium vehicula odio sed ultrices. Aenean a"
+ + " felis libero. Vivamus sed commodo nibh. Pellentesque turpis lectus, euismod"
+ + " vel ante nec, cursus posuere orci. Suspendisse velit neque, fermentum"
+ + " luctus ultrices in, ultrices vitae arcu. Duis tincidunt cursus lorem. Nam"
+ + " ultricies accumsan quam vitae imperdiet. Pellentesque habitant morbi"
+ + " tristique senectus et netus et malesuada fames ac turpis egestas. Quisque"
+ + " aliquet pretium nisi, eget laoreet enim molestie sit amet. Class aptent"
+ + " taciti sociosqu ad litora torquent per conubia nostra, per inceptos"
+ + " himenaeos.\n"
+ + "Nam dapibus aliquam lacus ac suscipit. Proin in nibh sit amet purus congue"
+ + " laoreet eget quis nisl. Morbi gravida dignissim justo, a venenatis ante"
+ + " pulvinar at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin"
+ + " ultrices vestibulum dui, vel aliquam lacus aliquam quis. Duis fringilla"
+ + " sapien ac lacus egestas, vel adipiscing elit euismod. Donec non tellus"
+ + " odio. Donec gravida eu massa ac feugiat. Aliquam erat volutpat. Praesent id"
+ + " adipiscing metus, nec laoreet enim. Aliquam vitae posuere turpis. Mauris ac"
+ + " pharetra sem. In at placerat tortor. Vivamus ac vehicula neque. Cras"
+ + " volutpat ullamcorper massa et varius. Praesent sagittis neque vitae nulla"
+ + " euismod pharetra.\n"
+ + "Sed placerat sapien non molestie sollicitudin. Nullam sit amet dictum quam."
+ + " Etiam tincidunt tortor vel pretium vehicula. Praesent fringilla ipsum vel"
+ + " velit luctus dignissim. Nulla massa ligula, mattis in enim et, mattis"
+ + " lacinia odio. Suspendisse tristique urna a orci commodo tempor. Duis"
+ + " lacinia egestas arcu a sollicitudin.\n"
+ + "In ac feugiat lacus. Nunc fermentum eu est at tristique. Pellentesque quis"
+ + " ligula et orci placerat lacinia. Maecenas quis mauris diam. Etiam mi ipsum,"
+ + " tempus in purus quis, euismod faucibus orci. Nulla facilisi. Praesent sit"
+ + " amet sapien vel elit porta adipiscing. Phasellus sit amet volutpat diam.\n"
+ + "Proin bibendum elit non lacus pharetra, quis eleifend tellus placerat. Nulla"
+ + " facilisi. Maecenas ante diam, pellentesque mattis mattis in, porta ut"
+ + " lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices"
+ + " posuere cubilia Curae; Nunc interdum tristique metus, in scelerisque odio"
+ + " fermentum eget. Cras nec venenatis lacus. Aenean euismod eget metus quis"
+ + " molestie. Cras tincidunt dolor ut massa ornare, in elementum lacus auctor."
+ + " Cras sodales nisl lacus, id ultrices ligula varius at. Sed tristique sit"
+ + " amet tellus vel mollis. Sed sed sollicitudin quam. Sed sed adipiscing"
+ + " risus, et dictum orci. Cras tempor pellentesque turpis et tempus."),
+ LONGPARA(
+ Locale.US,
+ "During dinner, Mr. Bennet scarcely spoke at all; but when the servants were"
+ + " withdrawn, he thought it time to have some conversation with his guest, and"
+ + " therefore started a subject in which he expected him to shine, by observing"
+ + " that he seemed very fortunate in his patroness. Lady Catherine de Bourgh's"
+ + " attention to his wishes, and consideration for his comfort, appeared very"
+ + " remarkable. Mr. Bennet could not have chosen better. Mr. Collins was"
+ + " eloquent in her praise. The subject elevated him to more than usual"
+ + " solemnity of manner, and with a most important aspect he protested that"
+ + " \"he had never in his life witnessed such behaviour in a person of"
+ + " rank--such affability and condescension, as he had himself experienced from"
+ + " Lady Catherine. She had been graciously pleased to approve of both of the"
+ + " discourses which he had already had the honour of preaching before her. She"
+ + " had also asked him twice to dine at Rosings, and had sent for him only the"
+ + " Saturday before, to make up her pool of quadrille in the evening. Lady"
+ + " Catherine was reckoned proud by many people he knew, but _he_ had never"
+ + " seen anything but affability in her. She had always spoken to him as she"
+ + " would to any other gentleman; she made not the smallest objection to his"
+ + " joining in the society of the neighbourhood nor to his leaving the parish"
+ + " occasionally for a week or two, to visit his relations. She had even"
+ + " condescended to advise him to marry as soon as he could, provided he chose"
+ + " with discretion; and had once paid him a visit in his humble parsonage,"
+ + " where she had perfectly approved all the alterations he had been making,"
+ + " and had even vouchsafed to suggest some herself--some shelves in the closet"
+ + " up stairs.\""),
+ GERMAN(
+ Locale.GERMANY,
+ "Aber dieser Freiheit setzte endlich der Winter ein Ziel. Draußen auf den Feldern"
+ + " und den hohen Bergen lag der Schnee und Peter wäre in seinem dünnen"
+ + " Leinwandjäckchen bald erfroren. Es war also seine einzige Freude, hinaus"
+ + " vor die Hütte zu treten und den Sperlingen Brotkrümchen zu streuen, was er"
+ + " sich jedesmal an seinem Frühstück absparte. Wenn nun die Vögel so lustig"
+ + " zwitscherten und um ihn herumflogen, da klopfte ihm das Herz vor Lust, und"
+ + " oft gab er ihnen sein ganzes Stück Schwarzbrot, ohne daran zu denken, daß"
+ + " er dafür alsdann selbst hungern müsse."),
+ THAI(
+ Locale.forLanguageTag("th-TH"),
+ "เป็นสำเนียงทางการของภาษาไทย"
+ + " เดิมทีเป็นการผสมผสานกันระหว่างสำเนียงอยุธยาและชาวไทยเชื้อสายจีนรุ่นหลังที่"
+ + "พูดไทยแทนกลุ่มภาษาจีน"
+ + " ลักษณะเด่นคือมีการออกเสียงที่ชัดเจนและแข็งกระด้างซึ่งได้รับอิทธิพลจากภาษาแต"
+ + "้จิ๋ว"
+ + " การออกเสียงพยัญชนะ สระ การผันวรรณยุกต์ที่ในภาษาไทยมาตรฐาน"
+ + " มาจากสำเนียงถิ่นนี้ในขณะที่ภาษาไทยสำเนียงอื่นล้วนเหน่อทั้งสิ้น"
+ + " คำศัพท์ที่ใช้ในสำเนียงกรุงเทพจำนวนมากได้รับมาจากกลุ่มภาษาจีนเช่นคำว่า โป๊,"
+ + " เฮ็ง, อาหมวย, อาซิ่ม ซึ่งมาจากภาษาแต้จิ๋ว และจากภาษาจีนเช่น ถู(涂), ชิ่ว(去"
+ + " อ่านว่า\"ชู่\") และคำว่า ทาย(猜 อ่านว่า \"ชาย\") เป็นต้น"
+ + " เนื่องจากสำเนียงกรุงเทพได้รับอิทธิพลมาจากภาษาจีนดังนั้นตัวอักษร \"ร\""
+ + " มักออกเสียงเหมารวมเป็น \"ล\" หรือคำควบกล่ำบางคำถูกละทิ้งไปด้วยเช่น รู้ เป็น"
+ + " ลู้, เรื่อง เป็น เลื่อง หรือ ประเทศ เป็น ปะเทศ"
+ + " เป็นต้นสร้างความลำบากให้แก่ต่างชาติที่ต้องการเรียนภาษาไทย"
+ + " แต่อย่างไรก็ตามผู้ที่พูดสำเนียงถิ่นนี้ก็สามารถออกอักขระภาษาไทยตามมาตรฐานได"
+ + "้อย่างถูกต้องเพียงแต่มักเผลอไม่ค่อยออกเสียง"),
+ THAI2(Locale.forLanguageTag("th-TH"), "this is the word browser in Thai: เบราว์เซอร์"),
+ TABS(Locale.US, "one\t\t\t\t\t\t\t\t\t\t\t\t\t\ttwo\n"),
+ ACCENT(Locale.US, "e\u0301\u00e9\nwhich is:\n\"e\\u0301\\u00e9\""),
+ EMOJI(Locale.US, ">>\ud83d\ude01<<\nwhich is:\n\">>\\ud83d\\ude01<<\""),
+ SPACES(Locale.US, " leading spaces and trailing ones too "),
+ EMPTY(Locale.US, ""),
+ NEWLINE(Locale.US, "\\n:\n"),
+ BIDI(
+ Locale.forLanguageTag("he-IL"),
+ "Sarah שרה is spelled sin ש resh ר heh ה from right to left.");
+
+ final Locale mLocale;
+ final String mText;
+
+ Text(Locale locale, String text) {
+ this.mText = text;
+ this.mLocale = locale;
+ }
+ }
+
+ @Parameters(name = "mText={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {Text.ACCENT}, {Text.BIDI}, {Text.EMOJI}, {Text.EMPTY}, {Text.GERMAN},
+ {Text.LIPSUM}, {Text.LONGPARA}, {Text.NEWLINE}, {Text.SPACES}, {Text.TABS},
+ {Text.THAI}, {Text.THAI2}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public Text mText;
+
+ @Test
+ public void timeBreakIterator() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ BreakIterator it = BreakIterator.getLineInstance(mText.mLocale);
+ it.setText(mText.mText);
+
+ while (it.next() != BreakIterator.DONE) {
+ // Keep iterating
+ }
+ }
+ }
+
+ @Test
+ public void timeIcuBreakIterator() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ android.icu.text.BreakIterator it =
+ android.icu.text.BreakIterator.getLineInstance(mText.mLocale);
+ it.setText(mText.mText);
+
+ while (it.next() != android.icu.text.BreakIterator.DONE) {
+ // Keep iterating
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java
new file mode 100644
index 000000000000..8e57b28a0550
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferBulkPerfTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferBulkPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mAligned({0}), mSrcBufferType({1}), mDataBufferType({2}), mBufferSize({3})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {true, MyBufferType.DIRECT, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.DIRECT, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.DIRECT, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.HEAP, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.HEAP, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.DIRECT, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.HEAP, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.HEAP, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.MAPPED, MyBufferType.MAPPED, 4096},
+ {false, MyBufferType.MAPPED, MyBufferType.MAPPED, 4096},
+ {true, MyBufferType.DIRECT, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.DIRECT, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.DIRECT, 1232896},
+ {true, MyBufferType.DIRECT, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.HEAP, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.HEAP, 1232896},
+ {true, MyBufferType.DIRECT, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.DIRECT, MyBufferType.MAPPED, 1232896},
+ {true, MyBufferType.HEAP, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.HEAP, MyBufferType.MAPPED, 1232896},
+ {true, MyBufferType.MAPPED, MyBufferType.MAPPED, 1232896},
+ {false, MyBufferType.MAPPED, MyBufferType.MAPPED, 1232896},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public boolean mAligned;
+
+ enum MyBufferType {
+ DIRECT,
+ HEAP,
+ MAPPED
+ }
+
+ @Parameterized.Parameter(1)
+ public MyBufferType mSrcBufferType;
+
+ @Parameterized.Parameter(2)
+ public MyBufferType mDataBufferType;
+
+ @Parameterized.Parameter(3)
+ public int mBufferSize;
+
+ public static ByteBuffer newBuffer(boolean aligned, MyBufferType bufferType, int bsize)
+ throws IOException {
+ int size = aligned ? bsize : bsize + 8 + 1;
+ ByteBuffer result = null;
+ switch (bufferType) {
+ case DIRECT:
+ result = ByteBuffer.allocateDirect(size);
+ break;
+ case HEAP:
+ result = ByteBuffer.allocate(size);
+ break;
+ case MAPPED:
+ File tmpFile = File.createTempFile("MappedByteBufferTest", ".tmp");
+ tmpFile.createNewFile();
+ tmpFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw");
+ raf.setLength(size);
+ FileChannel fc = raf.getChannel();
+ result = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
+ break;
+ }
+ result.position(aligned ? 0 : 1);
+ return result;
+ }
+
+ @Test
+ public void timeByteBuffer_putByteBuffer() throws Exception {
+ ByteBuffer src = ByteBufferBulkPerfTest.newBuffer(mAligned, mSrcBufferType, mBufferSize);
+ ByteBuffer data = ByteBufferBulkPerfTest.newBuffer(mAligned, mDataBufferType, mBufferSize);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ data.position(mAligned ? 0 : 1);
+ src.put(data);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
new file mode 100644
index 000000000000..4bd7c4e4fa82
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -0,0 +1,532 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum MyByteOrder {
+ BIG(ByteOrder.BIG_ENDIAN),
+ LITTLE(ByteOrder.LITTLE_ENDIAN);
+ final ByteOrder mByteOrder;
+
+ MyByteOrder(ByteOrder mByteOrder) {
+ this.mByteOrder = mByteOrder;
+ }
+ }
+
+ @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {MyByteOrder.BIG, true, MyBufferType.DIRECT},
+ {MyByteOrder.LITTLE, true, MyBufferType.DIRECT},
+ {MyByteOrder.BIG, false, MyBufferType.DIRECT},
+ {MyByteOrder.LITTLE, false, MyBufferType.DIRECT},
+ {MyByteOrder.BIG, true, MyBufferType.HEAP},
+ {MyByteOrder.LITTLE, true, MyBufferType.HEAP},
+ {MyByteOrder.BIG, false, MyBufferType.HEAP},
+ {MyByteOrder.LITTLE, false, MyBufferType.HEAP},
+ {MyByteOrder.BIG, true, MyBufferType.MAPPED},
+ {MyByteOrder.LITTLE, true, MyBufferType.MAPPED},
+ {MyByteOrder.BIG, false, MyBufferType.MAPPED},
+ {MyByteOrder.LITTLE, false, MyBufferType.MAPPED}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public MyByteOrder mByteOrder;
+
+ @Parameterized.Parameter(1)
+ public boolean mAligned;
+
+ enum MyBufferType {
+ DIRECT,
+ HEAP,
+ MAPPED;
+ }
+
+ @Parameterized.Parameter(2)
+ public MyBufferType mBufferType;
+
+ public static ByteBuffer newBuffer(
+ MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws IOException {
+ int size = aligned ? 8192 : 8192 + 8 + 1;
+ ByteBuffer result = null;
+ switch (bufferType) {
+ case DIRECT:
+ result = ByteBuffer.allocateDirect(size);
+ break;
+ case HEAP:
+ result = ByteBuffer.allocate(size);
+ break;
+ case MAPPED:
+ File tmpFile = new File("/sdcard/bm.tmp");
+ if (new File("/tmp").isDirectory()) {
+ // We're running on the desktop.
+ tmpFile = File.createTempFile("MappedByteBufferTest", ".tmp");
+ }
+ tmpFile.createNewFile();
+ tmpFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw");
+ raf.setLength(8192 * 8);
+ FileChannel fc = raf.getChannel();
+ result = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
+ break;
+ }
+ result.order(byteOrder.mByteOrder);
+ result.position(aligned ? 0 : 1);
+ return result;
+ }
+
+ //
+ // peeking
+ //
+
+ @Test
+ public void timeByteBuffer_getByte() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.get();
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getByteArray() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ byte[] dst = new byte[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getByte_indexed() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.get(i);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getChar() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getChar();
+ }
+ }
+ }
+
+ @Test
+ public void timeCharBuffer_getCharArray() throws Exception {
+ CharBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer();
+ char[] dst = new char[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getChar_indexed() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getChar(i * 2);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getDouble() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getDouble();
+ }
+ }
+ }
+
+ @Test
+ public void timeDoubleBuffer_getDoubleArray() throws Exception {
+ DoubleBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer();
+ double[] dst = new double[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getFloat() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getFloat();
+ }
+ }
+ }
+
+ @Test
+ public void timeFloatBuffer_getFloatArray() throws Exception {
+ FloatBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer();
+ float[] dst = new float[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getInt() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getInt();
+ }
+ }
+ }
+
+ @Test
+ public void timeIntBuffer_getIntArray() throws Exception {
+ IntBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer();
+ int[] dst = new int[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getLong() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getLong();
+ }
+ }
+ }
+
+ @Test
+ public void timeLongBuffer_getLongArray() throws Exception {
+ LongBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer();
+ long[] dst = new long[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_getShort() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.getShort();
+ }
+ }
+ }
+
+ @Test
+ public void timeShortBuffer_getShortArray() throws Exception {
+ ShortBuffer src =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer();
+ short[] dst = new short[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ src.position(0);
+ src.get(dst);
+ }
+ }
+ }
+
+ //
+ // poking
+ //
+
+ @Test
+ public void timeByteBuffer_putByte() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(0);
+ for (int i = 0; i < 1024; ++i) {
+ src.put((byte) 0);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putByteArray() throws Exception {
+ ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ byte[] src = new byte[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(mAligned ? 0 : 1);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putChar() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putChar(' ');
+ }
+ }
+ }
+
+ @Test
+ public void timeCharBuffer_putCharArray() throws Exception {
+ CharBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer();
+ char[] src = new char[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putDouble() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putDouble(0.0);
+ }
+ }
+ }
+
+ @Test
+ public void timeDoubleBuffer_putDoubleArray() throws Exception {
+ DoubleBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer();
+ double[] src = new double[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putFloat() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putFloat(0.0f);
+ }
+ }
+ }
+
+ @Test
+ public void timeFloatBuffer_putFloatArray() throws Exception {
+ FloatBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer();
+ float[] src = new float[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putInt() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putInt(0);
+ }
+ }
+ }
+
+ @Test
+ public void timeIntBuffer_putIntArray() throws Exception {
+ IntBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer();
+ int[] src = new int[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putLong() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putLong(0L);
+ }
+ }
+ }
+
+ @Test
+ public void timeLongBuffer_putLongArray() throws Exception {
+ LongBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer();
+ long[] src = new long[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBuffer_putShort() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ for (int i = 0; i < 1024; ++i) {
+ src.putShort((short) 0);
+ }
+ }
+ }
+
+ @Test
+ public void timeShortBuffer_putShortArray() throws Exception {
+ ShortBuffer dst =
+ ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer();
+ short[] src = new short[1024];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < 1024; ++i) {
+ dst.position(0);
+ dst.put(src);
+ }
+ }
+ }
+
+ @Test
+ public void time_new_byteArray() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ byte[] bs = new byte[8192];
+ }
+ }
+
+ @Test
+ public void time_ByteBuffer_allocate() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ByteBuffer bs = ByteBuffer.allocate(8192);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
new file mode 100644
index 000000000000..81f9e59f2423
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ByteBufferScalarVersusVectorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.DIRECT
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.HEAP
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ true,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ true,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.BIG,
+ false,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ },
+ {
+ ByteBufferPerfTest.MyByteOrder.LITTLE,
+ false,
+ ByteBufferPerfTest.MyBufferType.MAPPED
+ }
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public ByteBufferPerfTest.MyByteOrder mByteOrder;
+
+ @Parameterized.Parameter(1)
+ public boolean mAligned;
+
+ @Parameterized.Parameter(2)
+ public ByteBufferPerfTest.MyBufferType mBufferType;
+
+ @Test
+ public void timeManualByteBufferCopy() throws Exception {
+ ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(0);
+ dst.position(0);
+ for (int i = 0; i < 8192; ++i) {
+ dst.put(src.get());
+ }
+ }
+ }
+
+ @Test
+ public void timeByteBufferBulkGet() throws Exception {
+ ByteBuffer src = ByteBuffer.allocate(mAligned ? 8192 : 8192 + 1);
+ byte[] dst = new byte[8192];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst, 0, dst.length);
+ }
+ }
+
+ @Test
+ public void timeDirectByteBufferBulkGet() throws Exception {
+ ByteBuffer src = ByteBuffer.allocateDirect(mAligned ? 8192 : 8192 + 1);
+ byte[] dst = new byte[8192];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ src.position(mAligned ? 0 : 1);
+ src.get(dst, 0, dst.length);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
new file mode 100644
index 000000000000..28ec6ded3c86
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Tests various Character methods, intended for testing multiple implementations against each
+ * other.
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharacterPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mCharacterSet({0}), mOverload({1})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {CharacterSet.ASCII, Overload.CHAR},
+ {CharacterSet.ASCII, Overload.INT},
+ {CharacterSet.UNICODE, Overload.CHAR},
+ {CharacterSet.UNICODE, Overload.INT}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public CharacterSet mCharacterSet;
+
+ @Parameterized.Parameter(1)
+ public Overload mOverload;
+
+ private char[] mChars;
+
+ @Before
+ public void setUp() throws Exception {
+ this.mChars = mCharacterSet.mChars;
+ }
+
+ public enum Overload {
+ CHAR,
+ INT
+ }
+
+ public double nanosToUnits(double nanos) {
+ return nanos / 65536;
+ }
+
+ public enum CharacterSet {
+ ASCII(128),
+ UNICODE(65536);
+ final char[] mChars;
+
+ CharacterSet(int size) {
+ this.mChars = new char[65536];
+ for (int i = 0; i < 65536; ++i) {
+ mChars[i] = (char) (i % size);
+ }
+ }
+ }
+
+ // A fake benchmark to give us a baseline.
+ @Test
+ public void timeIsSpace() {
+ boolean fake = false;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ fake ^= ((char) ch == ' ');
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ fake ^= (ch == ' ');
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.digit(mChars[ch], 10);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.digit((int) mChars[ch], 10);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeGetNumericValue() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.getNumericValue(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.getNumericValue((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isDigit(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isDigit((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsIdentifierIgnorable() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isIdentifierIgnorable(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isIdentifierIgnorable((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsJavaIdentifierPart() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierPart(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierPart((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsJavaIdentifierStart() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierStart(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isJavaIdentifierStart((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLetter() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetter(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetter((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLetterOrDigit() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetterOrDigit(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLetterOrDigit((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsLowerCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLowerCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isLowerCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsSpaceChar() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isSpaceChar(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isSpaceChar((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsUpperCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isUpperCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isUpperCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeIsWhitespace() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isWhitespace(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.isWhitespace((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeToLowerCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toLowerCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toLowerCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeToUpperCase() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ if (mOverload == Overload.CHAR) {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toUpperCase(mChars[ch]);
+ }
+ }
+ } else {
+ while (state.keepRunning()) {
+ for (int ch = 0; ch < 65536; ++ch) {
+ Character.toUpperCase((int) mChars[ch]);
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
new file mode 100644
index 000000000000..603b182e7c36
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharsetForNamePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameters(name = "mCharsetName({0})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {"UTF-16"},
+ {"UTF-8"},
+ {"UTF8"},
+ {"ISO-8859-1"},
+ {"8859_1"},
+ {"ISO-8859-2"},
+ {"8859_2"},
+ {"US-ASCII"},
+ {"ASCII"},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public String mCharsetName;
+
+ @Test
+ public void timeCharsetForName() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Charset.forName(mCharsetName);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
new file mode 100644
index 000000000000..437d186834e0
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CharsetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mLength({0}), mName({1})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {1, "UTF-16"},
+ {1, "UTF-8"},
+ {1, "UTF8"},
+ {1, "ISO-8859-1"},
+ {1, "8859_1"},
+ {1, "ISO-8859-2"},
+ {1, "8859_2"},
+ {1, "US-ASCII"},
+ {1, "ASCII"},
+ {10, "UTF-16"},
+ {10, "UTF-8"},
+ {10, "UTF8"},
+ {10, "ISO-8859-1"},
+ {10, "8859_1"},
+ {10, "ISO-8859-2"},
+ {10, "8859_2"},
+ {10, "US-ASCII"},
+ {10, "ASCII"},
+ {100, "UTF-16"},
+ {100, "UTF-8"},
+ {100, "UTF8"},
+ {100, "ISO-8859-1"},
+ {100, "8859_1"},
+ {100, "ISO-8859-2"},
+ {100, "8859_2"},
+ {100, "US-ASCII"},
+ {100, "ASCII"},
+ {1000, "UTF-16"},
+ {1000, "UTF-8"},
+ {1000, "UTF8"},
+ {1000, "ISO-8859-1"},
+ {1000, "8859_1"},
+ {1000, "ISO-8859-2"},
+ {1000, "8859_2"},
+ {1000, "US-ASCII"},
+ {1000, "ASCII"},
+ {10000, "UTF-16"},
+ {10000, "UTF-8"},
+ {10000, "UTF8"},
+ {10000, "ISO-8859-1"},
+ {10000, "8859_1"},
+ {10000, "ISO-8859-2"},
+ {10000, "8859_2"},
+ {10000, "US-ASCII"},
+ {10000, "ASCII"},
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public int mLength;
+
+ @Parameterized.Parameter(1)
+ public String mName;
+
+ @Test
+ public void time_new_String_BString() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, mName);
+ }
+ }
+
+ @Test
+ public void time_new_String_BII() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, 0, bytes.length);
+ }
+ }
+
+ @Test
+ public void time_new_String_BIIString() throws Exception {
+ byte[] bytes = makeBytes(makeString(mLength));
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new String(bytes, 0, bytes.length, mName);
+ }
+ }
+
+ @Test
+ public void time_String_getBytes() throws Exception {
+ String string = makeString(mLength);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ string.getBytes(mName);
+ }
+ }
+
+ private static String makeString(int length) {
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ result.append('A' + (i % 26));
+ }
+ return result.toString();
+ }
+
+ private static byte[] makeBytes(String s) {
+ try {
+ return s.getBytes("US-ASCII");
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
new file mode 100644
index 000000000000..f31e9c154f15
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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.libcore.regression;
+
+import android.icu.lang.UCharacter;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.charset.Charset;
+
+/**
+ * Decode the same size of ASCII, BMP, Supplementary character using fast-path UTF-8 decoder. The
+ * fast-path code is in {@link StringFactory#newStringFromBytes(byte[], int, int, Charset)}
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CharsetUtf8PerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final int mNoOfBytes = 0x100; // 4MB
+
+ private void makeUnicodeRange(int startingCodePoint, int endingCodePoint, int repeated) {
+ StringBuilder builder = new StringBuilder();
+ for (int codePoint = startingCodePoint; codePoint <= endingCodePoint; codePoint++) {
+ if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) {
+ builder.append(UCharacter.toString(codePoint));
+ }
+ }
+
+ String str = builder.toString();
+ StringBuilder builder2 = new StringBuilder();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < repeated; i++) {
+ builder2.append(str);
+ }
+ }
+ }
+
+ @Test
+ public void time_ascii() {
+ makeUnicodeRange(0, 0x7f, mNoOfBytes / 0x80);
+ }
+
+ @Test
+ public void time_bmp2() {
+ makeUnicodeRange(0x0080, 0x07ff, mNoOfBytes / 2 / 0x780);
+ }
+
+ @Test
+ public void time_bmp3() {
+ makeUnicodeRange(
+ 0x0800,
+ 0xffff,
+ mNoOfBytes / 3 / 0xf000 /* 0x10000 - 0x0800 - no of surrogate code points */);
+ }
+
+ @Test
+ public void time_supplementary() {
+ makeUnicodeRange(0x10000, 0x10ffff, mNoOfBytes / 4 / 0x100000);
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
new file mode 100644
index 000000000000..1d33fcb250b9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.zip.Adler32;
+import java.util.zip.CRC32;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ChecksumPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeAdler_block() throws Exception {
+ byte[] bytes = new byte[10000];
+ Adler32 adler = new Adler32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ adler.update(bytes);
+ }
+ }
+
+ @Test
+ public void timeAdler_byte() throws Exception {
+ Adler32 adler = new Adler32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ adler.update(1);
+ }
+ }
+
+ @Test
+ public void timeCrc_block() throws Exception {
+ byte[] bytes = new byte[10000];
+ CRC32 crc = new CRC32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ crc.update(bytes);
+ }
+ }
+
+ @Test
+ public void timeCrc_byte() throws Exception {
+ CRC32 crc = new CRC32();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ crc.update(1);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
new file mode 100644
index 000000000000..35730ec753f1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/** CipherInputStream benchmark. */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CipherInputStreamPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final int DATA_SIZE = 1024 * 1024;
+ private static final byte[] DATA = new byte[DATA_SIZE];
+
+ private static final int IV_SIZE = 16;
+ private static final byte[] IV = new byte[IV_SIZE];
+
+ static {
+ for (int i = 0; i < DATA_SIZE; i++) {
+ DATA[i] = (byte) i;
+ }
+ for (int i = 0; i < IV_SIZE; i++) {
+ IV[i] = (byte) i;
+ }
+ }
+
+ private SecretKey mKey;
+
+ private byte[] mOutput = new byte[8192];
+
+ private Cipher mCipherEncrypt;
+
+ private AlgorithmParameterSpec mSpec;
+
+ @Before
+ public void setUp() throws Exception {
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ generator.init(128);
+ mKey = generator.generateKey();
+
+ mSpec = new IvParameterSpec(IV);
+
+ mCipherEncrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+ }
+
+ @Test
+ public void timeEncrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+ InputStream is = new CipherInputStream(new ByteArrayInputStream(DATA), mCipherEncrypt);
+ while (is.read(mOutput) != -1) {
+ // Keep iterating
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
new file mode 100644
index 000000000000..15c27f2366e1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Cipher benchmarks. Only runs on AES currently because of the combinatorial explosion of the test
+ * as it stands.
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class CipherPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameters(
+ name =
+ "mMode({0}), mPadding({1}), mKeySize({2}), mInputSize({3}),"
+ + " mImplementation({4})")
+ public static Collection cases() {
+ int[] mKeySizes = new int[] {128, 192, 256};
+ int[] inputSizes = new int[] {16, 32, 64, 128, 1024, 8192};
+ final List<Object[]> params = new ArrayList<>();
+ for (Mode mode : Mode.values()) {
+ for (Padding padding : Padding.values()) {
+ for (Implementation implementation : Implementation.values()) {
+ if ((mode == Mode.CBC
+ || mode == Mode.CFB
+ || mode == Mode.CTR
+ || mode == Mode.ECB
+ || mode == Mode.OFB)
+ && padding == Padding.PKCS1PADDING) {
+ continue;
+ }
+ if ((mode == Mode.CFB || mode == Mode.OFB)
+ && padding == Padding.NOPADDING
+ && implementation == Implementation.OpenSSL) {
+ continue;
+ }
+ for (int mKeySize : mKeySizes) {
+ for (int inputSize : inputSizes) {
+ params.add(
+ new Object[] {
+ mode, padding, mKeySize, inputSize, implementation
+ });
+ }
+ }
+ }
+ }
+ }
+ return params;
+ }
+
+ private static final int DATA_SIZE = 8192;
+ private static final byte[] DATA = new byte[DATA_SIZE];
+
+ private static final int IV_SIZE = 16;
+
+ private static final byte[] IV = new byte[IV_SIZE];
+
+ static {
+ for (int i = 0; i < DATA_SIZE; i++) {
+ DATA[i] = (byte) i;
+ }
+ for (int i = 0; i < IV_SIZE; i++) {
+ IV[i] = (byte) i;
+ }
+ }
+
+ public Algorithm mAlgorithm = Algorithm.AES;
+
+ public enum Algorithm {
+ AES,
+ };
+
+ @Parameterized.Parameter(0)
+ public Mode mMode;
+
+ public enum Mode {
+ CBC,
+ CFB,
+ CTR,
+ ECB,
+ OFB,
+ };
+
+ @Parameterized.Parameter(1)
+ public Padding mPadding;
+
+ public enum Padding {
+ NOPADDING,
+ PKCS1PADDING,
+ };
+
+ @Parameterized.Parameter(2)
+ public int mKeySize;
+
+ @Parameterized.Parameter(3)
+ public int mInputSize;
+
+ @Parameterized.Parameter(4)
+ public Implementation mImplementation;
+
+ public enum Implementation {
+ OpenSSL,
+ BouncyCastle
+ };
+
+ private String mProviderName;
+
+ // Key generation isn't part of the benchmark so cache the results
+ private static Map<Integer, SecretKey> sKeySizes = new HashMap<Integer, SecretKey>();
+
+ private String mCipherAlgorithm;
+ private SecretKey mKey;
+
+ private byte[] mOutput = new byte[DATA.length];
+
+ private Cipher mCipherEncrypt;
+
+ private Cipher mCipherDecrypt;
+
+ private AlgorithmParameterSpec mSpec;
+
+ @Before
+ public void setUp() throws Exception {
+ mCipherAlgorithm =
+ mAlgorithm.toString() + "/" + mMode.toString() + "/" + mPadding.toString();
+
+ String mKeyAlgorithm = mAlgorithm.toString();
+ mKey = sKeySizes.get(mKeySize);
+ if (mKey == null) {
+ KeyGenerator generator = KeyGenerator.getInstance(mKeyAlgorithm);
+ generator.init(mKeySize);
+ mKey = generator.generateKey();
+ sKeySizes.put(mKeySize, mKey);
+ }
+
+ switch (mImplementation) {
+ case OpenSSL:
+ mProviderName = "AndroidOpenSSL";
+ break;
+ case BouncyCastle:
+ mProviderName = "BC";
+ break;
+ default:
+ throw new RuntimeException(mImplementation.toString());
+ }
+
+ if (mMode != Mode.ECB) {
+ mSpec = new IvParameterSpec(IV);
+ }
+
+ mCipherEncrypt = Cipher.getInstance(mCipherAlgorithm, mProviderName);
+ mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
+
+ mCipherDecrypt = Cipher.getInstance(mCipherAlgorithm, mProviderName);
+ mCipherDecrypt.init(Cipher.DECRYPT_MODE, mKey, mSpec);
+ }
+
+ @Test
+ public void timeEncrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherEncrypt.doFinal(DATA, 0, mInputSize, mOutput);
+ }
+ }
+
+ @Test
+ public void timeDecrypt() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mCipherDecrypt.doFinal(DATA, 0, mInputSize, mOutput);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
new file mode 100644
index 000000000000..6728e73d0c4b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.Collator;
+import java.text.RuleBasedCollator;
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CollatorPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final RuleBasedCollator COLLATOR =
+ (RuleBasedCollator) Collator.getInstance(Locale.US);
+
+ @Test
+ public void timeCollatorPrimary() {
+ COLLATOR.setStrength(Collator.PRIMARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcde", "abcdf");
+ COLLATOR.compare("abcde", "abcde");
+ COLLATOR.compare("abcdf", "abcde");
+ }
+ }
+
+ @Test
+ public void timeCollatorSecondary() {
+ COLLATOR.setStrength(Collator.SECONDARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdÂ", "abcdÄ");
+ COLLATOR.compare("abcdÂ", "abcdÂ");
+ COLLATOR.compare("abcdÄ", "abcdÂ");
+ }
+ }
+
+ @Test
+ public void timeCollatorTertiary() {
+ COLLATOR.setStrength(Collator.TERTIARY);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdE", "abcde");
+ COLLATOR.compare("abcde", "abcde");
+ COLLATOR.compare("abcde", "abcdE");
+ }
+ }
+
+ @Test
+ public void timeCollatorIdentical() {
+ COLLATOR.setStrength(Collator.IDENTICAL);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ COLLATOR.compare("abcdȪ", "abcdȫ");
+ COLLATOR.compare("abcdȪ", "abcdȪ");
+ COLLATOR.compare("abcdȫ", "abcdȪ");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
new file mode 100644
index 000000000000..a89efffcdd1f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Random;
+import java.util.Vector;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class CollectionsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mArrayListLength({0})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{4}, {16}, {64}, {256}, {1024}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int arrayListLength;
+
+ public static Comparator<Integer> REVERSE =
+ new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ int lhsAsInt = lhs.intValue();
+ int rhsAsInt = rhs.intValue();
+ return rhsAsInt < lhsAsInt ? -1 : (lhsAsInt == rhsAsInt ? 0 : 1);
+ }
+ };
+
+ @Test
+ public void timeSort_arrayList() throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input);
+ }
+ }
+
+ @Test
+ public void timeSortWithComparator_arrayList() throws Exception {
+ List<Integer> input = buildList(arrayListLength, ArrayList.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ @Test
+ public void timeSort_vector() throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input);
+ }
+ }
+
+ @Test
+ public void timeSortWithComparator_vector() throws Exception {
+ List<Integer> input = buildList(arrayListLength, Vector.class);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Collections.sort(input, REVERSE);
+ }
+ }
+
+ private static <T extends List<Integer>> List<Integer> buildList(
+ int arrayListLength, Class<T> listClass) throws Exception {
+ Random random = new Random();
+ random.setSeed(0);
+ List<Integer> list = listClass.newInstance();
+ for (int i = 0; i < arrayListLength; ++i) {
+ list.add(random.nextInt());
+ }
+ return list;
+ }
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index 641b1a3697e2..e4fc9f3a57d1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29612,6 +29612,7 @@ package android.os {
field public static final int S = 31; // 0x1f
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 10000; // 0x2710
+ field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 9db3cdc1f03c..fd87a6168d7e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -100,10 +100,12 @@ package android.hardware.usb {
field public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2; // 0x2
field public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1; // 0xffffffff
field public static final int USB_HAL_NOT_SUPPORTED = -1; // 0xffffffff
+ field public static final int USB_HAL_RETRY = -2; // 0xfffffffe
field public static final int USB_HAL_V1_0 = 10; // 0xa
field public static final int USB_HAL_V1_1 = 11; // 0xb
field public static final int USB_HAL_V1_2 = 12; // 0xc
field public static final int USB_HAL_V1_3 = 13; // 0xd
+ field public static final int USB_HAL_V2_0 = 20; // 0x14
}
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 95fc7ec58e95..abc2b74c0645 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4169,8 +4169,14 @@ package android.hardware.usb {
}
public final class UsbPort {
+ method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
+ field public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1; // 0x1
+ field public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2; // 0x2
+ field public static final int ENABLE_USB_DATA_ERROR_OTHER = 4; // 0x4
+ field public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3; // 0x3
+ field public static final int ENABLE_USB_DATA_SUCCESS = 0; // 0x0
}
public final class UsbPortStatus implements android.os.Parcelable {
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 7f07af79ab69..3e79f18a4d65 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -18,6 +18,7 @@ package android.hardware.usb;
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.ParcelableUsbPort;
@@ -136,7 +137,7 @@ interface IUsbManager
void resetUsbGadget();
/* Set USB data on or off */
- boolean enableUsbDataSignal(boolean enable);
+ boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback);
/* Gets the USB Hal Version. */
int getUsbHalVersion();
@@ -159,6 +160,6 @@ interface IUsbManager
/* Enable/disable contaminant detection */
void enableContaminantDetection(in String portId, boolean enable);
- /* Sets USB device connection handler. */
- void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
+ /* Sets USB device connection handler. */
+ void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
}
diff --git a/core/java/android/hardware/usb/IUsbOperationInternal.aidl b/core/java/android/hardware/usb/IUsbOperationInternal.aidl
new file mode 100644
index 000000000000..3f3bbf63ed8b
--- /dev/null
+++ b/core/java/android/hardware/usb/IUsbOperationInternal.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 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.usb;
+
+/**
+ * @hide
+ */
+oneway interface IUsbOperationInternal {
+void onOperationComplete(in int status);
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 964d7c1658dc..df70bfd4c1a0 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -36,6 +36,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbPort;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -48,6 +50,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.StringJoiner;
/**
@@ -516,6 +519,14 @@ public class UsbManager {
public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
/**
+ * Returned when the client has to retry querying the version.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int USB_HAL_RETRY = -2;
+
+ /**
* The Value for USB hal is not presented.
*
* {@hide}
@@ -556,6 +567,14 @@ public class UsbManager {
public static final int USB_HAL_V1_3 = 13;
/**
+ * Value for USB Hal Version v2.0.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int USB_HAL_V2_0 = 20;
+
+ /**
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
* {@hide}
*/
@@ -664,6 +683,7 @@ public class UsbManager {
USB_HAL_V1_1,
USB_HAL_V1_2,
USB_HAL_V1_3,
+ USB_HAL_V2_0,
})
public @interface UsbHalVersion {}
@@ -1168,8 +1188,9 @@ public class UsbManager {
/**
* Enable/Disable the USB data signaling.
* <p>
- * Enables/Disables USB data path in all the USB ports.
+ * Enables/Disables USB data path of the first port..
* It will force to stop or restore USB data signaling.
+ * Call UsbPort API if the device has more than one UsbPort.
* </p>
*
* @param enable enable or disable USB data signaling
@@ -1180,11 +1201,11 @@ public class UsbManager {
*/
@RequiresPermission(Manifest.permission.MANAGE_USB)
public boolean enableUsbDataSignal(boolean enable) {
- try {
- return mService.enableUsbDataSignal(enable);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ List<UsbPort> usbPorts = getPorts();
+ if (usbPorts.size() == 1) {
+ return usbPorts.get(0).enableUsbData(enable) == UsbPort.ENABLE_USB_DATA_SUCCESS;
}
+ return false;
}
/**
@@ -1270,6 +1291,41 @@ public class UsbManager {
}
/**
+ * Should only be called by {@link UsbPort#enableUsbData}.
+ * <p>
+ * Enables or disables USB data on the specific port.
+ *
+ * @param port USB port for which USB data needs to be enabled or disabled.
+ * @param enable Enable USB data when true.
+ * Disable USB data when false.
+ * @param operationId operationId for the request.
+ * @param callback callback object to be invoked when the operation is complete.
+ * @return True when the operation is asynchronous. The caller must therefore call
+ * {@link UsbOperationInternal#waitForOperationComplete} for processing
+ * the result.
+ * False when the operation is synchronous. Caller can proceed reading the result
+ * through {@link UsbOperationInternal#getStatus}
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ boolean enableUsbData(@NonNull UsbPort port, boolean enable, int operationId,
+ IUsbOperationInternal callback) {
+ Objects.requireNonNull(port, "enableUsbData: port must not be null. opId:" + operationId);
+ try {
+ return mService.enableUsbData(port.getId(), enable, operationId, callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "enableUsbData: failed. opId:" + operationId, e);
+ try {
+ callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException r) {
+ Log.e(TAG, "enableUsbData: failed to call onOperationComplete. opId:"
+ + operationId, r);
+ }
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sets the component that will handle USB device connection.
* <p>
* Setting component allows to specify external USB host manager to handle use cases, where
diff --git a/core/java/android/hardware/usb/UsbOperationInternal.java b/core/java/android/hardware/usb/UsbOperationInternal.java
new file mode 100644
index 000000000000..9bc2b3892a1e
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbOperationInternal.java
@@ -0,0 +1,131 @@
+/*
+ * 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.hardware.usb;
+
+import android.annotation.IntDef;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbPort;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.TimeUnit;
+/**
+ * UsbOperationInternal allows UsbPort to support both synchronous and
+ * asynchronous function irrespective of whether the underlying hal
+ * method is synchronous or asynchronous.
+ *
+ * @hide
+ */
+public final class UsbOperationInternal extends IUsbOperationInternal.Stub {
+ private static final String TAG = "UsbPortStatus";
+ private final int mOperationID;
+ // Cached portId.
+ private final String mId;
+ // True implies operation did not timeout.
+ private boolean mOperationComplete;
+ private @UsbOperationStatus int mStatus;
+ final ReentrantLock mLock = new ReentrantLock();
+ final Condition mOperationWait = mLock.newCondition();
+ // Maximum time the caller has to wait for onOperationComplete to be called.
+ private static final int USB_OPERATION_TIMEOUT_MSECS = 5000;
+
+ /**
+ * The requested operation was successfully completed.
+ * Returned in {@link onOperationComplete} and {@link getStatus}.
+ */
+ public static final int USB_OPERATION_SUCCESS = 0;
+
+ /**
+ * The requested operation failed due to internal error.
+ * Returned in {@link onOperationComplete} and {@link getStatus}.
+ */
+ public static final int USB_OPERATION_ERROR_INTERNAL = 1;
+
+ /**
+ * The requested operation failed as it's not supported.
+ * Returned in {@link onOperationComplete} and {@link getStatus}.
+ */
+ public static final int USB_OPERATION_ERROR_NOT_SUPPORTED = 2;
+
+ /**
+ * The requested operation failed as it's not supported.
+ * Returned in {@link onOperationComplete} and {@link getStatus}.
+ */
+ public static final int USB_OPERATION_ERROR_PORT_MISMATCH = 3;
+
+ @IntDef(prefix = { "USB_OPERATION_" }, value = {
+ USB_OPERATION_SUCCESS,
+ USB_OPERATION_ERROR_INTERNAL,
+ USB_OPERATION_ERROR_NOT_SUPPORTED,
+ USB_OPERATION_ERROR_PORT_MISMATCH
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface UsbOperationStatus{}
+
+ UsbOperationInternal(int operationID, String id) {
+ this.mOperationID = operationID;
+ this.mId = id;
+ }
+
+ /**
+ * Hal glue layer would directly call this function when the requested
+ * operation is complete.
+ */
+ @Override
+ public void onOperationComplete(@UsbOperationStatus int status) {
+ mLock.lock();
+ try {
+ mOperationComplete = true;
+ mStatus = status;
+ Log.i(TAG, "Port:" + mId + " opID:" + mOperationID + " status:" + mStatus);
+ mOperationWait.signal();
+ } finally {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Caller invokes this function to wait for the operation to be complete.
+ */
+ public void waitForOperationComplete() {
+ mLock.lock();
+ try {
+ long now = System.currentTimeMillis();
+ long deadline = now + USB_OPERATION_TIMEOUT_MSECS;
+ // Wait in loop to overcome spurious wakeups.
+ do {
+ mOperationWait.await(deadline - System.currentTimeMillis(),
+ TimeUnit.MILLISECONDS);
+ } while (!mOperationComplete && System.currentTimeMillis() < deadline);
+ if (!mOperationComplete) {
+ Log.e(TAG, "Port:" + mId + " opID:" + mOperationID
+ + " operationComplete not received in " + USB_OPERATION_TIMEOUT_MSECS
+ + "msecs");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Port:" + mId + " opID:" + mOperationID + " operationComplete interrupted");
+ } finally {
+ mLock.unlock();
+ }
+ }
+
+ public @UsbOperationStatus int getStatus() {
+ return mOperationComplete ? mStatus : USB_OPERATION_ERROR_INTERNAL;
+ }
+}
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 274e23fff292..f469a3e66d50 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,6 +16,10 @@
package android.hardware.usb;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
@@ -34,15 +38,23 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
import android.Manifest;
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.hardware.usb.UsbOperationInternal;
import android.hardware.usb.V1_0.Constants;
+import android.os.Binder;
+import android.util.Log;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Represents a physical USB port and describes its characteristics.
@@ -51,6 +63,7 @@ import java.util.Objects;
*/
@SystemApi
public final class UsbPort {
+ private static final String TAG = "UsbPort";
private final String mId;
private final int mSupportedModes;
private final UsbManager mUsbManager;
@@ -64,6 +77,47 @@ public final class UsbPort {
*/
private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
+ /**
+ * The {@link #enableUsbData} request was successfully completed.
+ */
+ public static final int ENABLE_USB_DATA_SUCCESS = 0;
+
+ /**
+ * The {@link #enableUsbData} request failed due to internal error.
+ */
+ public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1;
+
+ /**
+ * The {@link #enableUsbData} request failed as it's not supported.
+ */
+ public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2;
+
+ /**
+ * The {@link #enableUsbData} request failed as port id mismatched.
+ */
+ public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3;
+
+ /**
+ * The {@link #enableUsbData} request failed due to other reasons.
+ */
+ public static final int ENABLE_USB_DATA_ERROR_OTHER = 4;
+
+ /** @hide */
+ @IntDef(prefix = { "ENABLE_USB_DATA_" }, value = {
+ ENABLE_USB_DATA_SUCCESS,
+ ENABLE_USB_DATA_ERROR_INTERNAL,
+ ENABLE_USB_DATA_ERROR_NOT_SUPPORTED,
+ ENABLE_USB_DATA_ERROR_PORT_MISMATCH,
+ ENABLE_USB_DATA_ERROR_OTHER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface EnableUsbDataStatus{}
+
/** @hide */
public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
int supportedContaminantProtectionModes,
@@ -157,7 +211,7 @@ public final class UsbPort {
* {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
* </p><p>
* Note: This function is asynchronous and may fail silently without applying
- * the requested changes. If this function does cause a status change to occur then
+ * the operationed changes. If this function does cause a status change to occur then
* a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
* </p>
*
@@ -177,6 +231,47 @@ public final class UsbPort {
}
/**
+ * Enables/Disables Usb data on the port.
+ *
+ * @param enable When true enables USB data if disabled.
+ * When false disables USB data if enabled.
+ * @return {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or
+ * {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal
+ * error or
+ * {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or
+ * {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id
+ * mismatch or
+ * {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons.
+ */
+ @CheckResult
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ public @EnableUsbDataStatus int enableUsbData(boolean enable) {
+ // UID is added To minimize operationID overlap between two different packages.
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
+ Log.i(TAG, "enableUsbData opId:" + operationId
+ + " callingUid:" + Binder.getCallingUid());
+ UsbOperationInternal opCallback =
+ new UsbOperationInternal(operationId, mId);
+ if (mUsbManager.enableUsbData(this, enable, operationId, opCallback) == true) {
+ opCallback.waitForOperationComplete();
+ }
+
+ int result = opCallback.getStatus();
+ switch (result) {
+ case USB_OPERATION_SUCCESS:
+ return ENABLE_USB_DATA_SUCCESS;
+ case USB_OPERATION_ERROR_INTERNAL:
+ return ENABLE_USB_DATA_ERROR_INTERNAL;
+ case USB_OPERATION_ERROR_NOT_SUPPORTED:
+ return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED;
+ case USB_OPERATION_ERROR_PORT_MISMATCH:
+ return ENABLE_USB_DATA_ERROR_PORT_MISMATCH;
+ default:
+ return ENABLE_USB_DATA_ERROR_OTHER;
+ }
+ }
+
+ /**
* @hide
**/
public void enableContaminantDetection(boolean enable) {
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index bb7aff651b3d..bd2f9aa55bda 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -19,7 +19,6 @@ package android.hardware.usb;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.hardware.usb.V1_0.Constants;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,27 +35,29 @@ import java.lang.annotation.RetentionPolicy;
@Immutable
@SystemApi
public final class UsbPortStatus implements Parcelable {
+ private static final String TAG = "UsbPortStatus";
private final int mCurrentMode;
private final @UsbPowerRole int mCurrentPowerRole;
private final @UsbDataRole int mCurrentDataRole;
private final int mSupportedRoleCombinations;
private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
+ private final boolean mUsbDataEnabled;
/**
* Power role: This USB port does not have a power role.
*/
- public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
+ public static final int POWER_ROLE_NONE = 0;
/**
* Power role: This USB port can act as a source (provide power).
*/
- public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
+ public static final int POWER_ROLE_SOURCE = 1;
/**
* Power role: This USB port can act as a sink (receive power).
*/
- public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+ public static final int POWER_ROLE_SINK = 2;
@IntDef(prefix = { "POWER_ROLE_" }, value = {
POWER_ROLE_NONE,
@@ -69,17 +70,17 @@ public final class UsbPortStatus implements Parcelable {
/**
* Power role: This USB port does not have a data role.
*/
- public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
+ public static final int DATA_ROLE_NONE = 0;
/**
* Data role: This USB port can act as a host (access data services).
*/
- public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
+ public static final int DATA_ROLE_HOST = 1;
/**
* Data role: This USB port can act as a device (offer data services).
*/
- public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
+ public static final int DATA_ROLE_DEVICE = 2;
@IntDef(prefix = { "DATA_ROLE_" }, value = {
DATA_ROLE_NONE,
@@ -92,23 +93,23 @@ public final class UsbPortStatus implements Parcelable {
/**
* There is currently nothing connected to this USB port.
*/
- public static final int MODE_NONE = Constants.PortMode.NONE;
+ public static final int MODE_NONE = 0;
/**
- * This USB port can act as a downstream facing port (host).
+ * This USB port can act as an upstream facing port (device).
*
- * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
- * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well).
+ * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
+ * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
*/
- public static final int MODE_DFP = Constants.PortMode.DFP;
+ public static final int MODE_UFP = 1 << 0;
/**
- * This USB port can act as an upstream facing port (device).
+ * This USB port can act as a downstream facing port (host).
*
- * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
- * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
+ * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
+ * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well).
*/
- public static final int MODE_UFP = Constants.PortMode.UFP;
+ public static final int MODE_DFP = 1 << 1;
/**
* This USB port can act either as an downstream facing port (host) or as
@@ -120,87 +121,76 @@ public final class UsbPortStatus implements Parcelable {
*
* @hide
*/
- public static final int MODE_DUAL = Constants.PortMode.DRP;
+ public static final int MODE_DUAL = MODE_UFP | MODE_DFP;
/**
* This USB port can support USB Type-C Audio accessory.
*/
- public static final int MODE_AUDIO_ACCESSORY =
- android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
+ public static final int MODE_AUDIO_ACCESSORY = 1 << 2;
/**
* This USB port can support USB Type-C debug accessory.
*/
- public static final int MODE_DEBUG_ACCESSORY =
- android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
+ public static final int MODE_DEBUG_ACCESSORY = 1 << 3;
/**
* Contaminant presence detection not supported by the device.
* @hide
*/
- public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED =
- android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_SUPPORTED;
+ public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED = 0;
/**
* Contaminant presence detection supported but disabled.
* @hide
*/
- public static final int CONTAMINANT_DETECTION_DISABLED =
- android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DISABLED;
+ public static final int CONTAMINANT_DETECTION_DISABLED = 1;
/**
* Contaminant presence enabled but not detected.
* @hide
*/
- public static final int CONTAMINANT_DETECTION_NOT_DETECTED =
- android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_DETECTED;
+ public static final int CONTAMINANT_DETECTION_NOT_DETECTED = 2;
/**
* Contaminant presence enabled and detected.
* @hide
*/
- public static final int CONTAMINANT_DETECTION_DETECTED =
- android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DETECTED;
+ public static final int CONTAMINANT_DETECTION_DETECTED = 3;
/**
* Contaminant protection - No action performed upon detection of
* contaminant presence.
* @hide
*/
- public static final int CONTAMINANT_PROTECTION_NONE =
- android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.NONE;
+ public static final int CONTAMINANT_PROTECTION_NONE = 0;
/**
* Contaminant protection - Port is forced to sink upon detection of
* contaminant presence.
* @hide
*/
- public static final int CONTAMINANT_PROTECTION_SINK =
- android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SINK;
+ public static final int CONTAMINANT_PROTECTION_SINK = 1 << 0;
/**
* Contaminant protection - Port is forced to source upon detection of
* contaminant presence.
* @hide
*/
- public static final int CONTAMINANT_PROTECTION_SOURCE =
- android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SOURCE;
+ public static final int CONTAMINANT_PROTECTION_SOURCE = 1 << 1;
/**
* Contaminant protection - Port is disabled upon detection of
* contaminant presence.
* @hide
*/
- public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE =
- android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_DISABLE;
+ public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE = 1 << 2;
/**
* Contaminant protection - Port is disabled upon detection of
* contaminant presence.
* @hide
*/
- public static final int CONTAMINANT_PROTECTION_DISABLED =
- android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
+ public static final int CONTAMINANT_PROTECTION_DISABLED = 1 << 3;
@IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
CONTAMINANT_DETECTION_NOT_SUPPORTED,
@@ -234,6 +224,19 @@ public final class UsbPortStatus implements Parcelable {
/** @hide */
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
+ int contaminantDetectionStatus, boolean usbDataEnabled) {
+ mCurrentMode = currentMode;
+ mCurrentPowerRole = currentPowerRole;
+ mCurrentDataRole = currentDataRole;
+ mSupportedRoleCombinations = supportedRoleCombinations;
+ mContaminantProtectionStatus = contaminantProtectionStatus;
+ mContaminantDetectionStatus = contaminantDetectionStatus;
+ mUsbDataEnabled = usbDataEnabled;
+ }
+
+ /** @hide */
+ public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+ int supportedRoleCombinations, int contaminantProtectionStatus,
int contaminantDetectionStatus) {
mCurrentMode = currentMode;
mCurrentPowerRole = currentPowerRole;
@@ -241,6 +244,7 @@ public final class UsbPortStatus implements Parcelable {
mSupportedRoleCombinations = supportedRoleCombinations;
mContaminantProtectionStatus = contaminantProtectionStatus;
mContaminantDetectionStatus = contaminantDetectionStatus;
+ mUsbDataEnabled = true;
}
/**
@@ -323,6 +327,15 @@ public final class UsbPortStatus implements Parcelable {
return mContaminantProtectionStatus;
}
+ /**
+ * Returns UsbData status.
+ *
+ * @hide
+ */
+ public boolean getUsbDataStatus() {
+ return mUsbDataEnabled;
+ }
+
@NonNull
@Override
public String toString() {
@@ -336,6 +349,8 @@ public final class UsbPortStatus implements Parcelable {
+ getContaminantDetectionStatus()
+ ", contaminantProtectionStatus="
+ getContaminantProtectionStatus()
+ + ", usbDataEnabled="
+ + getUsbDataStatus()
+ "}";
}
@@ -352,6 +367,7 @@ public final class UsbPortStatus implements Parcelable {
dest.writeInt(mSupportedRoleCombinations);
dest.writeInt(mContaminantProtectionStatus);
dest.writeInt(mContaminantDetectionStatus);
+ dest.writeBoolean(mUsbDataEnabled);
}
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -364,9 +380,10 @@ public final class UsbPortStatus implements Parcelable {
int supportedRoleCombinations = in.readInt();
int contaminantProtectionStatus = in.readInt();
int contaminantDetectionStatus = in.readInt();
+ boolean usbDataEnabled = in.readBoolean();
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
- contaminantDetectionStatus);
+ contaminantDetectionStatus, usbDataEnabled);
}
@Override
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java
index 0f21a9d7f471..552a2c171f21 100644
--- a/core/java/android/net/VpnProfileState.java
+++ b/core/java/android/net/VpnProfileState.java
@@ -24,6 +24,7 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.StringJoiner;
/**
@@ -176,4 +177,19 @@ public final class VpnProfileState implements Parcelable {
resultJoiner.add("Lockdown: " + isLockdownEnabled());
return resultJoiner.toString();
}
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof VpnProfileState)) return false;
+ final VpnProfileState that = (VpnProfileState) obj;
+ return (getState() == that.getState()
+ && Objects.equals(getSessionId(), that.getSessionId())
+ && isAlwaysOn() == that.isAlwaysOn()
+ && isLockdownEnabled() == that.isLockdownEnabled());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getState(), getSessionId(), isAlwaysOn(), isLockdownEnabled());
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 394e7c3db17f..141b1412424a 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1167,6 +1167,11 @@ public class Build {
* Tiramisu.
*/
public static final int TIRAMISU = CUR_DEVELOPMENT;
+
+ /**
+ * Upside Down Cake.
+ */
+ public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index b5466b6d3cb5..49f4bf71c172 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -5,10 +5,14 @@ evanxinchen@google.com
ewol@google.com
guojing@google.com
jaysullivan@google.com
+kvakil@google.com
+mrulhania@google.com
+narayan@google.com
+ntmyren@google.com
olekarg@google.com
pyuli@google.com
-ntmyren@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+raphk@google.com
+rmacgregor@google.com
+sergeynv@google.com
theianchen@google.com
zhanghai@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4c1cc97e2ae6..71b5354e4d42 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -306,6 +306,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
/**
+ * Namespace for all Kernel Multi-Gen LRU feature.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native";
+
+ /**
* Namespace for all netd related features.
*
* @hide
diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS
index 32f482264103..462d8bed743c 100644
--- a/core/java/android/speech/OWNERS
+++ b/core/java/android/speech/OWNERS
@@ -1,3 +1,4 @@
volnov@google.com
eugeniom@google.com
schfan@google.com
+andreaambu@google.com
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f2ddf52351de..ffa577a47c88 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28283,7 +28283,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be
* available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li>
*
- * <li>Events from a touchpad will be delivered with the source
+ * <li>Events from a touchpad or trackpad will be delivered with the source
* {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers
* on the touchpad will be available through {@link MotionEvent#getX(int)} and
* {@link MotionEvent#getY(int)}, and their relative movements are stored in
@@ -28292,6 +28292,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <li>Events from other types of devices, such as touchscreens, will not be affected.</li>
* </ul>
* <p>
+ * When pointer capture changes, connected mouse and trackpad devices may be reconfigured,
+ * and their properties (such as their sources or motion ranges) may change. Use an
+ * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device
+ * changes (which may happen after enabling or disabling pointer capture), and use
+ * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}.
+ * <p>
* Events captured through pointer capture will be dispatched to
* {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an
* {@link OnCapturedPointerListener} is set, and otherwise to
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index 32601368f2fb..744fe595d283 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -244,7 +244,8 @@ public class DumpUtils {
writeContaminantPresenceStatus(dump, "contaminant_presence_status",
UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS,
status.getContaminantDetectionStatus());
-
+ dump.write("usb_data_enabled", UsbPortStatusProto.USB_DATA_ENABLED,
+ status.getUsbDataStatus());
dump.end(token);
}
}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 4072687c87cc..361988c5cde8 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -66,6 +66,7 @@ per-file com_android_internal_net_* = file:/services/core/java/com/android/serve
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_HardwareBuffer.cpp = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_SyncFence.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file android_os_GraphicsEnvironment.cpp = file:platform/frameworks/native:/opengl/OWNERS
### Text ###
per-file android_text_* = file:/core/java/android/text/OWNERS
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 51185d4d59c9..f4f9f9437eb0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1177,38 +1177,40 @@ static void relabelAllDirs(const char* path, const char* context, fail_fn_t fail
}
/**
- * Make other apps data directory not visible in CE, DE storage.
+ * Hide the CE and DE data directories of non-related apps.
*
- * Apps without app data isolation can detect if another app is installed on system,
- * by "touching" other apps data directory like /data/data/com.whatsapp, if it returns
- * "Permission denied" it means apps installed, otherwise it returns "File not found".
- * Traditional file permissions or SELinux can only block accessing those directories but
- * can't fix fingerprinting like this.
- * We fix it by "overlaying" data directory, and only relevant app data packages exists
- * in data directories.
+ * Without this, apps can detect if any app is installed by trying to "touch" the app's CE
+ * or DE data directory, e.g. /data/data/com.whatsapp. This fails with EACCES if the app
+ * is installed, or ENOENT if it's not. Traditional file permissions or SELinux can only
+ * block accessing those directories but can't fix fingerprinting like this.
*
- * Steps:
- * 1). Collect a list of all related apps (apps with same uid and allowlisted apps) data info
- * (package name, data stored volume uuid, and inode number of its CE data directory)
- * 2). Mount tmpfs on /data/data, /data/user(_de) and /mnt/expand, so apps no longer
- * able to access apps data directly.
- * 3). For each related app, create its app data directory and bind mount the actual content
- * from apps data mirror directory. This works on both CE and DE storage, as DE storage
- * is always available even storage is FBE locked, while we use inode number to find
- * the encrypted DE directory in mirror so we can still bind mount it successfully.
+ * Instead, we hide non-related apps' data directories from the filesystem entirely by
+ * mounting tmpfs instances over their parent directories and bind-mounting in just the
+ * needed app data directories. This is done in a private mount namespace.
*
- * Example:
- * 0). Assuming com.android.foo CE data is stored in /data/data and no shared uid
- * 1). Mount a tmpfs on /data/data, /data/user, /data/user_de, /mnt/expand
- * List = ["com.android.foo", "null" (volume uuid "null"=default),
- * 123456 (inode number)]
- * 2). On DE storage, we create a directory /data/user_de/0/com.com.android.foo, and bind
- * mount (in the app's mount namespace) it from /data_mirror/data_de/0/com.android.foo.
- * 3). We do similar for CE storage. But in direct boot mode, as /data_mirror/data_ce/0/ is
- * encrypted, we can't find a directory with name com.android.foo on it, so we will
- * use the inode number to find the right directory instead, which that directory content will
- * be decrypted after storage is decrypted.
+ * Steps:
+ * (1) Collect a list of all related apps (apps with same uid and allowlisted apps) data info
+ * (package name, data stored volume uuid, and inode number of its CE data directory)
+ * (2) Mount tmpfs on /data/data and /data/user{,_de}, and on /mnt/expand/$volume/user{,_de}
+ * for all adoptable storage volumes. This hides all app data directories.
+ * (3) For each related app, create stubs for its data directories in the relevant tmpfs
+ * instances, then bind mount in the actual directories from /data_mirror. This works
+ * for both the CE and DE directories. DE storage is always unlocked, whereas the
+ * app's CE directory can be found via inode number if CE storage is locked.
*
+ * Example assuming user 0, app "com.android.foo", no shared uid, and no adoptable storage:
+ * (1) Info = ["com.android.foo", "null" (volume uuid "null"=default), "123456" (inode number)]
+ * (2) Mount tmpfs on /data/data, /data/user, and /data/user_de.
+ * (3) For DE storage, create a directory /data/user_de/0/com.android.foo and bind mount
+ * /data_mirror/data_de/0/com.android.foo onto it.
+ * (4) Do similar for CE storage. But if the device is in direct boot mode, then CE
+ * storage will be locked, so the app's CE data directory won't exist at the usual
+ * path /data_mirror/data_ce/0/com.android.foo. It will still exist in
+ * /data_mirror/data_ce/0, but its filename will be an unpredictable no-key name. In
+ * this case, we use the inode number to find the right directory instead. Note that
+ * the bind-mounted app CE data directory will remain locked. It will be unlocked
+ * automatically if/when the user's CE storage is unlocked, since adding an encryption
+ * key takes effect on a whole filesystem instance including all its mounts.
*/
static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
uid_t uid, const char* process_name,
@@ -1599,10 +1601,11 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
// since the directory is owned by root.
if (!is_system_server && getuid() == 0) {
const int rc = createProcessGroup(uid, getpid());
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else if (rc != 0) {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ if (rc != 0) {
+ fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
+ "CONFIG_CGROUP_CPUACCT?")
+ : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
+ /* pid= */ 0, strerror(-rc)));
}
}
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 7e26952a92da..4f3eeb0733f4 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -434,8 +434,9 @@ message SystemPropertiesProto {
optional string vibrator = 37;
optional string virtual_device = 38;
optional string vulkan = 39;
+ optional string egl_legacy = 40;
- // Next Tag: 40
+ // Next Tag: 41
}
optional Hardware hardware = 27;
@@ -555,4 +556,3 @@ message SystemPropertiesProto {
// Next Tag: 32
}
-
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 45f8c132fbf0..cd002da38e20 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -195,9 +195,19 @@ message UsbIsHeadsetProto {
message UsbPortManagerProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ enum HalVersion {
+ V_UNKNOWN = 0;
+ V1_0 = 10;
+ V1_1 = 11;
+ V1_2 = 12;
+ V1_3 = 13;
+ V2 = 20;
+ }
+
optional bool is_simulation_active = 1;
repeated UsbPortInfoProto usb_ports = 2;
optional bool enable_usb_data_signaling = 3;
+ optional HalVersion hal_version = 4;
}
message UsbPortInfoProto {
@@ -253,6 +263,7 @@ message UsbPortStatusProto {
optional DataRole data_role = 4;
repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
+ optional bool usb_data_enabled = 7;
}
message UsbPortStatusRoleCombinationProto {
diff --git a/core/res/OWNERS b/core/res/OWNERS
index a20b89540a04..0608a35c29d0 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -34,4 +34,8 @@ per-file res/xml/public-final.xml = file:/tools/aapt2/OWNERS
per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
# Car
-per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS \ No newline at end of file
+per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
+
+# Telephony
+per-file res/values/config_telephony.xml = file:/platform/frameworks/opt/telephony:/OWNERS
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c5d50fb05fa2..a8ab1a88e4c7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2572,36 +2572,10 @@
<string-array name="config_mobile_tcp_buffers">
</string-array>
- <!-- Configure tcp buffer sizes per network type in the form:
- network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
-
- The network-type must be a valid DataConfigNetworkType value. If no value is found for the
- network-type in use, config_tcp_buffers will be used instead.
- -->
- <string-array name="config_network_type_tcp_buffers">
- </string-array>
-
- <!-- Configure tcp buffer sizes in the form:
- rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
- If this is configured as an empty string, the system default will be applied.
-
- For now this config is used by mobile data only. In the future it should be
- used by Wi-Fi as well.
- -->
- <string name="config_tcp_buffers" translatable="false"></string>
-
<!-- Configure ethernet tcp buffersizes in the form:
rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
<string name="config_ethernet_tcp_buffers" translatable="false">524288,1048576,3145728,524288,1048576,2097152</string>
- <!-- What source to use to estimate link upstream and downstream bandwidth capacities.
- Default is bandwidth_estimator.
- Values are bandwidth_estimator, carrier_config and modem. -->
- <string name="config_bandwidthEstimateSource">bandwidth_estimator</string>
-
- <!-- Whether force to enable telephony new data stack or not -->
- <bool name="config_force_enable_telephony_new_data_stack">false</bool>
-
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
Here are a few of them:
@@ -3148,27 +3122,6 @@
<!-- String array containing numbers that shouldn't be logged. Country-specific. -->
<string-array name="unloggable_phone_numbers" />
- <!-- Cellular data service package name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wwan_data_service_package" translatable="false">com.android.phone</string>
-
- <!-- IWLAN data service package name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wlan_data_service_package" translatable="false"></string>
-
- <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
- tunnels across service restart. If iwlan tunnels are not persisted across restart,
- Framework will clean up dangling data connections when service restarts -->
- <bool name="config_wlan_data_service_conn_persistence_on_restart">true</bool>
-
- <!-- Cellular data service class name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wwan_data_service_class" translatable="false"></string>
-
- <!-- IWLAN data service class name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wlan_data_service_class" translatable="false"></string>
-
<bool name="config_networkSamplingWakesDevice">true</bool>
<!--From SmsMessage-->
@@ -3254,11 +3207,6 @@
and one pSIM) -->
<integer name="config_num_physical_slots">1</integer>
- <!-- When a radio power off request is received, we will delay completing the request until
- either IMS moves to the deregistered state or the timeout defined by this configuration
- elapses. If 0, this feature is disabled and we do not delay radio power off requests.-->
- <integer name="config_delay_for_ims_dereg_millis">0</integer>
-
<!--Thresholds for LTE dbm in status bar-->
<integer-array translatable="false" name="config_lteDbmThresholds">
<item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
@@ -4194,24 +4142,6 @@
<bool name="config_keepRestrictedProfilesInBackground">true</bool>
- <!-- Cellular network service package name to bind to by default. -->
- <string name="config_wwan_network_service_package" translatable="false">com.android.phone</string>
-
- <!-- Cellular network service class name to bind to by default.-->
- <string name="config_wwan_network_service_class" translatable="false"></string>
-
- <!-- IWLAN network service package name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wlan_network_service_package" translatable="false"></string>
-
- <!-- IWLAN network service class name to bind to by default. If none is specified in an overlay, an
- empty string is passed in -->
- <string name="config_wlan_network_service_class" translatable="false"></string>
- <!-- Telephony qualified networks service package name to bind to by default. -->
- <string name="config_qualified_networks_service_package" translatable="false"></string>
-
- <!-- Telephony qualified networks service class name to bind to by default. -->
- <string name="config_qualified_networks_service_class" translatable="false"></string>
<!-- Wear devices: Controls the radios affected by Activity Mode. -->
<string-array name="config_wearActivityModeRadios">
<item>"wifi"</item>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
new file mode 100644
index 000000000000..cd3578c727f0
--- /dev/null
+++ b/core/res/res/values/config_telephony.xml
@@ -0,0 +1,112 @@
+<?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.
+ -->
+<resources>
+ <!-- This file defines Android telephony related resources -->
+
+ <!-- Whether force to enable telephony new data stack or not -->
+ <bool name="config_force_enable_telephony_new_data_stack">true</bool>
+ <java-symbol type="bool" name="config_force_enable_telephony_new_data_stack" />
+
+ <!-- Configure tcp buffer sizes per network type in the form:
+ network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
+
+ The network-type must be a valid DataConfigNetworkType value. If no value is found for the
+ network-type in use, config_tcp_buffers will be used instead.
+ -->
+ <string-array name="config_network_type_tcp_buffers">
+ </string-array>
+ <java-symbol type="array" name="config_network_type_tcp_buffers" />
+
+ <!-- Configure tcp buffer sizes in the form:
+ rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
+ If this is configured as an empty string, the system default will be applied.
+ -->
+ <string name="config_tcp_buffers" translatable="false"></string>
+ <java-symbol type="string" name="config_tcp_buffers" />
+
+ <!-- What source to use to estimate link upstream and downstream bandwidth capacities.
+ Default is bandwidth_estimator.
+ Values are bandwidth_estimator, carrier_config and modem. -->
+ <string name="config_bandwidthEstimateSource">bandwidth_estimator</string>
+ <java-symbol type="string" name="config_bandwidthEstimateSource" />
+
+ <!-- Whether to adopt the predefined handover policies for IWLAN.
+ {@see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY}
+ -->
+ <bool name="config_enable_iwlan_handover_policy">true</bool>
+ <java-symbol type="bool" name="config_enable_iwlan_handover_policy" />
+
+ <!-- When a radio power off request is received, we will delay completing the request until
+ either IMS moves to the deregistered state or the timeout defined by this configuration
+ elapses. If 0, this feature is disabled and we do not delay radio power off requests.-->
+ <integer name="config_delay_for_ims_dereg_millis">0</integer>
+ <java-symbol type="integer" name="config_delay_for_ims_dereg_millis" />
+
+ <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
+ tunnels across service restart. If iwlan tunnels are not persisted across restart,
+ Framework will clean up dangling data connections when service restarts -->
+ <bool name="config_wlan_data_service_conn_persistence_on_restart">true</bool>
+ <java-symbol type="bool" name="config_wlan_data_service_conn_persistence_on_restart" />
+
+ <!-- Cellular data service package name to bind to by default. If none is specified in an
+ overlay, an empty string is passed in -->
+ <string name="config_wwan_data_service_package" translatable="false">com.android.phone</string>
+ <java-symbol type="string" name="config_wwan_data_service_package" />
+
+ <!-- IWLAN data service package name to bind to by default. If none is specified in an overlay,
+ an empty string is passed in -->
+ <string name="config_wlan_data_service_package" translatable="false"></string>
+ <java-symbol type="string" name="config_wlan_data_service_package" />
+
+ <!-- Cellular data service class name to bind to by default. If none is specified in an overlay,
+ an empty string is passed in -->
+ <string name="config_wwan_data_service_class" translatable="false"></string>
+ <java-symbol type="string" name="config_wwan_data_service_class" />
+
+ <!-- IWLAN data service class name to bind to by default. If none is specified in an overlay, an
+ empty string is passed in -->
+ <string name="config_wlan_data_service_class" translatable="false"></string>
+ <java-symbol type="string" name="config_wlan_data_service_class" />
+
+ <!-- Cellular network service package name to bind to by default. -->
+ <string name="config_wwan_network_service_package" translatable="false">
+ com.android.phone
+ </string>
+ <java-symbol type="string" name="config_wwan_network_service_package" />
+
+ <!-- Cellular network service class name to bind to by default.-->
+ <string name="config_wwan_network_service_class" translatable="false"></string>
+ <java-symbol type="string" name="config_wwan_network_service_class" />
+
+ <!-- IWLAN network service package name to bind to by default. If none is specified in an
+ overlay, an empty string is passed in -->
+ <string name="config_wlan_network_service_package" translatable="false"></string>
+ <java-symbol type="string" name="config_wlan_network_service_package" />
+
+ <!-- IWLAN network service class name to bind to by default. If none is specified in an overlay,
+ an empty string is passed in -->
+ <string name="config_wlan_network_service_class" translatable="false"></string>
+ <java-symbol type="string" name="config_wlan_network_service_class" />
+
+ <!-- Telephony qualified networks service package name to bind to by default. -->
+ <string name="config_qualified_networks_service_package" translatable="false"></string>
+ <java-symbol type="string" name="config_qualified_networks_service_package" />
+
+ <!-- Telephony qualified networks service class name to bind to by default. -->
+ <string name="config_qualified_networks_service_class" translatable="false"></string>
+ <java-symbol type="string" name="config_qualified_networks_service_class" />
+</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6e0fd91cc915..4ad95b6fc877 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,17 +294,6 @@
<java-symbol type="bool" name="config_enableBurnInProtection" />
<java-symbol type="bool" name="config_hotswapCapable" />
<java-symbol type="bool" name="config_mms_content_disposition_support" />
- <java-symbol type="string" name="config_wwan_network_service_package" />
- <java-symbol type="string" name="config_wlan_network_service_package" />
- <java-symbol type="string" name="config_wwan_network_service_class" />
- <java-symbol type="string" name="config_wlan_network_service_class" />
- <java-symbol type="bool" name="config_wlan_data_service_conn_persistence_on_restart" />
- <java-symbol type="string" name="config_wwan_data_service_package" />
- <java-symbol type="string" name="config_wlan_data_service_package" />
- <java-symbol type="string" name="config_wwan_data_service_class" />
- <java-symbol type="string" name="config_wlan_data_service_class" />
- <java-symbol type="string" name="config_qualified_networks_service_package" />
- <java-symbol type="string" name="config_qualified_networks_service_class" />
<java-symbol type="bool" name="config_networkSamplingWakesDevice" />
<java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" />
<java-symbol type="bool" name="config_sip_wifi_only" />
@@ -466,9 +455,6 @@
<java-symbol type="integer" name="config_safe_media_volume_usb_mB" />
<java-symbol type="integer" name="config_mobile_mtu" />
<java-symbol type="array" name="config_mobile_tcp_buffers" />
- <java-symbol type="array" name="config_network_type_tcp_buffers" />
- <java-symbol type="string" name="config_tcp_buffers" />
- <java-symbol type="bool" name="config_force_enable_telephony_new_data_stack" />
<java-symbol type="integer" name="config_volte_replacement_rat"/>
<java-symbol type="integer" name="config_valid_wappush_index" />
<java-symbol type="integer" name="config_overrideHasPermanentMenuKey" />
@@ -480,10 +466,8 @@
<java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" />
<java-symbol type="string" name="config_deviceSpecificAudioService" />
<java-symbol type="integer" name="config_num_physical_slots" />
- <java-symbol type="integer" name="config_delay_for_ims_dereg_millis" />
<java-symbol type="array" name="config_integrityRuleProviderPackages" />
<java-symbol type="bool" name="config_useAssistantVolume" />
- <java-symbol type="string" name="config_bandwidthEstimateSource" />
<java-symbol type="integer" name="config_smartSelectionInitializedTimeoutMillis" />
<java-symbol type="integer" name="config_smartSelectionInitializingTimeoutMillis" />
<java-symbol type="bool" name="config_hibernationDeletesOatArtifactsEnabled"/>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index d1d86a782016..dab4f1bdda4d 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -156,7 +156,7 @@
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
- <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
+ <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
<!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
<shortcode country="jp" pattern="\\d{1,5}" free="8083" />
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index c112cbb47b55..de2a013df999 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -51,6 +51,5 @@ android_test {
],
platform_apis: true,
- sdk_version: "core_platform",
test_suites: ["device-tests"],
}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index f87797a90c90..43a96793447d 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -35,7 +35,6 @@ android_test {
"truth-prebuilt",
],
test_suites: ["general-tests"],
- sdk_version: "test_current",
platform_apis: true,
}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 05ec00fe84f0..b52118425a2d 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -73,7 +73,6 @@ android_test {
],
platform_apis: true,
- sdk_version: "core_platform",
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index 0b3f9bb62a9b..54351131a433 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -45,6 +45,10 @@ android_app {
jni_libs: ["libshim_jni"],
uses_libs: ["android.test.runner"],
+
+ apex_available: [
+ "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
+ ],
}
genrule {
@@ -84,6 +88,7 @@ android_app {
"//apex_available:platform",
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
+ "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
"com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
@@ -159,6 +164,7 @@ android_app {
"//apex_available:platform",
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
+ "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
"com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
diff --git a/packages/CtsShim/build/jni/Android.bp b/packages/CtsShim/build/jni/Android.bp
index ba586dbb2d88..2dbf2a212cc3 100644
--- a/packages/CtsShim/build/jni/Android.bp
+++ b/packages/CtsShim/build/jni/Android.bp
@@ -32,6 +32,7 @@ cc_library_shared {
"//apex_available:platform",
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
+ "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
"com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index e5fd0ba5d9bc..bbb1ec6a5623 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -16,6 +16,7 @@
package com.android.settingslib.datetime;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.icu.text.TimeZoneFormat;
@@ -35,6 +36,7 @@ import androidx.core.text.TextDirectionHeuristicsCompat;
import com.android.i18n.timezone.CountryTimeZones;
import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping;
import com.android.i18n.timezone.TimeZoneFinder;
+import com.android.internal.app.LocaleHelper;
import com.android.settingslib.R;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,7 +101,8 @@ public class ZoneGetter {
TimeZoneFormat tzFormatter = TimeZoneFormat.getInstance(locale);
CharSequence gmtText = getGmtOffsetText(tzFormatter, locale, tz, now);
TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
- String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+ String zoneNameString = capitalizeForStandaloneDisplay(
+ locale, getZoneLongName(locale, timeZoneNames, tz, now));
if (zoneNameString == null) {
return gmtText;
}
@@ -108,6 +111,24 @@ public class ZoneGetter {
return TextUtils.concat(gmtText, " ", zoneNameString);
}
+ /**
+ * Capitalizes {@code toCapitalize} for standalone display, i.e. in lists. This is intended for
+ * use with "display name" strings from sources like ICU/CLDR which typically capitalize strings
+ * for the inclusion in the middle of sentences. Some locales (such as Polish) do not capitalize
+ * terms like "Coordinated Universal Time" as in English but do capitalize the first letter for
+ * standalone locations like lists, and so must be explicitly capitalized.
+ *
+ * @return the capitalized string, or {@code null} if the argument is null
+ */
+ @Nullable
+ public static String capitalizeForStandaloneDisplay(
+ Locale locale, @Nullable String toCapitalize) {
+ if (TextUtils.isEmpty(toCapitalize)) {
+ return toCapitalize;
+ }
+ return LocaleHelper.toSentenceCase(toCapitalize, locale);
+ }
+
public static List<Map<String, Object>> getZonesList(Context context) {
final Locale locale = context.getResources().getConfiguration().locale;
final Date now = new Date();
@@ -116,7 +137,7 @@ public class ZoneGetter {
// Work out whether the display names we would show by default would be ambiguous.
final boolean useExemplarLocationForLocalNames =
- shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
+ shouldUseExemplarLocationForLocalNames(locale, data, timeZoneNames);
// Generate the list of zone entries to return.
List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>();
@@ -124,7 +145,7 @@ public class ZoneGetter {
TimeZone tz = data.timeZones[i];
CharSequence gmtOffsetText = data.gmtOffsetTexts[i];
- CharSequence displayName = getTimeZoneDisplayName(data, timeZoneNames,
+ CharSequence displayName = getTimeZoneDisplayName(locale, data, timeZoneNames,
useExemplarLocationForLocalNames, tz, data.olsonIdsToDisplay[i]);
if (TextUtils.isEmpty(displayName)) {
displayName = gmtOffsetText;
@@ -181,15 +202,15 @@ public class ZoneGetter {
return olsonIds;
}
- private static boolean shouldUseExemplarLocationForLocalNames(ZoneGetterData data,
- TimeZoneNames timeZoneNames) {
+ private static boolean shouldUseExemplarLocationForLocalNames(Locale locale,
+ ZoneGetterData data, TimeZoneNames timeZoneNames) {
final Set<CharSequence> localZoneNames = new HashSet<>();
final Date now = new Date();
for (int i = 0; i < data.zoneCount; i++) {
final String olsonId = data.olsonIdsToDisplay[i];
if (data.localZoneIds.contains(olsonId)) {
final TimeZone tz = data.timeZones[i];
- CharSequence displayName = getZoneLongName(timeZoneNames, tz, now);
+ CharSequence displayName = getZoneLongName(locale, timeZoneNames, tz, now);
if (displayName == null) {
displayName = data.gmtOffsetTexts[i];
}
@@ -203,7 +224,7 @@ public class ZoneGetter {
return false;
}
- private static CharSequence getTimeZoneDisplayName(ZoneGetterData data,
+ private static CharSequence getTimeZoneDisplayName(Locale locale, ZoneGetterData data,
TimeZoneNames timeZoneNames, boolean useExemplarLocationForLocalNames, TimeZone tz,
String olsonId) {
final Date now = new Date();
@@ -212,7 +233,7 @@ public class ZoneGetter {
String displayName;
if (preferLongName) {
- displayName = getZoneLongName(timeZoneNames, tz, now);
+ displayName = getZoneLongName(locale, timeZoneNames, tz, now);
} else {
// Canonicalize the zone ID for ICU. It will only return valid strings for zone IDs
// that match ICUs zone IDs (which are similar but not guaranteed the same as those
@@ -223,10 +244,11 @@ public class ZoneGetter {
if (canonicalZoneId == null) {
canonicalZoneId = tz.getID();
}
- displayName = timeZoneNames.getExemplarLocationName(canonicalZoneId);
+ displayName = capitalizeForStandaloneDisplay(
+ locale, timeZoneNames.getExemplarLocationName(canonicalZoneId));
if (displayName == null || displayName.isEmpty()) {
// getZoneExemplarLocation can return null. Fall back to the long name.
- displayName = getZoneLongName(timeZoneNames, tz, now);
+ displayName = getZoneLongName(locale, timeZoneNames, tz, now);
}
}
@@ -237,11 +259,13 @@ public class ZoneGetter {
* Returns the long name for the timezone for the given locale at the time specified.
* Can return {@code null}.
*/
- private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) {
+ private static String getZoneLongName(
+ Locale locale, TimeZoneNames names, TimeZone tz, Date now) {
final TimeZoneNames.NameType nameType =
tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT
: TimeZoneNames.NameType.LONG_STANDARD;
- return names.getDisplayName(getCanonicalZoneId(tz), nameType, now.getTime());
+ return capitalizeForStandaloneDisplay(locale,
+ names.getDisplayName(getCanonicalZoneId(tz), nameType, now.getTime()));
}
private static String getCanonicalZoneId(TimeZone timeZone) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 40662536e57e..4a3350e056bf 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -320,7 +320,7 @@ private class ControlHolderAccessibilityDelegate(
info.className = Switch::class.java.name
}
- override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
+ override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
if (super.performAccessibilityAction(host, action, args)) {
return true
}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index aac1035059ec..296b7bf24269 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -98,11 +98,13 @@ public class BootReceiver extends BroadcastReceiver {
// example: fs_stat,/dev/block/platform/soc/by-name/userdata,0x5
private static final String FS_STAT_PATTERN = "fs_stat,[^,]*/([^/,]+),(0x[0-9a-fA-F]+)";
- private static final int FS_STAT_FS_FIXED = 0x400; // should match with fs_mgr.cpp:FsStatFlags
+ private static final int FS_STAT_FSCK_FS_FIXED =
+ 0x400; // should match with fs_mgr.cpp:FsStatFlags
private static final String FSCK_PASS_PATTERN = "Pass ([1-9]E?):";
private static final String FSCK_TREE_OPTIMIZATION_PATTERN =
"Inode [0-9]+ extent tree.*could be shorter";
- private static final String FSCK_FS_MODIFIED = "FILE SYSTEM WAS MODIFIED";
+ private static final String E2FSCK_FS_MODIFIED = "FILE SYSTEM WAS MODIFIED";
+ private static final String F2FS_FSCK_FS_MODIFIED = "[FSCK] Unreachable";
// ro.boottime.init.mount_all. + postfix for mount_all duration
private static final String[] MOUNT_DURATION_PROPS_POSTFIX =
new String[] { "early", "default", "late" };
@@ -460,9 +462,9 @@ public class BootReceiver extends BroadcastReceiver {
int lineNumber = 0;
int lastFsStatLineNumber = 0;
for (String line : lines) { // should check all lines
- if (line.contains(FSCK_FS_MODIFIED)) {
+ if (line.contains(E2FSCK_FS_MODIFIED) || line.contains(F2FS_FSCK_FS_MODIFIED)) {
uploadNeeded = true;
- } else if (line.contains("fs_stat")){
+ } else if (line.contains("fs_stat")) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
handleFsckFsStat(matcher, lines, lastFsStatLineNumber, lineNumber);
@@ -474,12 +476,13 @@ public class BootReceiver extends BroadcastReceiver {
lineNumber++;
}
- if (uploadEnabled && uploadNeeded ) {
+ if (uploadEnabled && uploadNeeded) {
addFileToDropBox(db, timestamps, headers, "/dev/fscklogs/log", maxSize, tag);
}
- // Remove the file so we don't re-upload if the runtime restarts.
- file.delete();
+ // Rename the file so we don't re-upload if the runtime restarts.
+ File pfile = new File("/dev/fscklogs/fsck");
+ file.renameTo(pfile);
}
private static void logFsMountTime() {
@@ -673,7 +676,7 @@ public class BootReceiver extends BroadcastReceiver {
public static int fixFsckFsStat(String partition, int statOrg, String[] lines,
int startLineNumber, int endLineNumber) {
int stat = statOrg;
- if ((stat & FS_STAT_FS_FIXED) != 0) {
+ if ((stat & FS_STAT_FSCK_FS_FIXED) != 0) {
// fs was fixed. should check if quota warning was caused by tree optimization.
// This is not a real fix but optimization, so should not be counted as a fs fix.
Pattern passPattern = Pattern.compile(FSCK_PASS_PATTERN);
@@ -686,7 +689,8 @@ public class BootReceiver extends BroadcastReceiver {
String otherFixLine = null;
for (int i = startLineNumber; i < endLineNumber; i++) {
String line = lines[i];
- if (line.contains(FSCK_FS_MODIFIED)) { // no need to parse above this
+ if (line.contains(E2FSCK_FS_MODIFIED)
+ || line.contains(F2FS_FSCK_FS_MODIFIED)) { // no need to parse above this
break;
} else if (line.startsWith("Pass ")) {
Matcher matcher = passPattern.matcher(line);
@@ -714,9 +718,9 @@ public class BootReceiver extends BroadcastReceiver {
}
} else if (line.startsWith("Update quota info") && currentPass.equals("5")) {
// follows "[QUOTA WARNING]", ignore
- } else if (line.startsWith("Timestamp(s) on inode") &&
- line.contains("beyond 2310-04-04 are likely pre-1970") &&
- currentPass.equals("1")) {
+ } else if (line.startsWith("Timestamp(s) on inode")
+ && line.contains("beyond 2310-04-04 are likely pre-1970")
+ && currentPass.equals("1")) {
Slog.i(TAG, "fs_stat, partition:" + partition + " found timestamp adjustment:"
+ line);
// followed by next line, "Fix? yes"
@@ -744,7 +748,7 @@ public class BootReceiver extends BroadcastReceiver {
} else if ((foundTreeOptimization && foundQuotaFix) || foundTimestampAdjustment) {
// not a real fix, so clear it.
Slog.i(TAG, "fs_stat, partition:" + partition + " fix ignored");
- stat &= ~FS_STAT_FS_FIXED;
+ stat &= ~FS_STAT_FSCK_FS_FIXED;
}
}
return stat;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ab2147dff853..d0503f3f3ddc 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -168,8 +168,8 @@ public class AccountManagerService
}
@Override
- public void onUserStopping(@NonNull TargetUser user) {
- Slog.i(TAG, "onStopUser " + user);
+ public void onUserStopped(@NonNull TargetUser user) {
+ Slog.i(TAG, "onUserStopped " + user);
mService.purgeUserData(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ec9f1fe9212a..fd109ff12ba6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -91,7 +91,6 @@ import static android.os.Process.killProcessQuiet;
import static android.os.Process.myPid;
import static android.os.Process.myUid;
import static android.os.Process.readProcFile;
-import static android.os.Process.removeAllProcessGroups;
import static android.os.Process.sendSignal;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
@@ -2388,8 +2387,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private void start() {
- removeAllProcessGroups();
-
mBatteryStatsService.publish();
mAppOpsService.publish();
Slog.d("AppOps", "AppOpsService published");
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index dc80c4b33297..1257f1f4bc10 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2425,8 +2425,8 @@ public final class ProcessList {
if (!regularZygote) {
// webview and app zygote don't have the permission to create the nodes
if (Process.createProcessGroup(uid, startResult.pid) < 0) {
- Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
- + app.processName + " (" + startResult.pid + ")");
+ throw new AssertionError("Unable to create process group for " + app.processName
+ + " (" + startResult.pid + ")");
}
}
@@ -2897,6 +2897,15 @@ public final class ProcessList {
}
int N = procs.size();
+ for (int i = 0; i < N; ++i) {
+ final ProcessRecord proc = procs.get(i).first;
+ try {
+ Process.setProcessFrozen(proc.getPid(), proc.uid, true);
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to freeze " + proc.getPid() + " " + proc.processName);
+ }
+ }
+
for (int i=0; i<N; i++) {
final Pair<ProcessRecord, Boolean> proc = procs.get(i);
removeProcessLocked(proc.first, callerWillRestart, allowRestart || proc.second,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c5ac3907ecfe..d01030bed56d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -86,6 +86,7 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_LMKD_NATIVE,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
+ DeviceConfig.NAMESPACE_MGLRU_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
DeviceConfig.NAMESPACE_NNAPI_NATIVE,
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index d9db28a9aa78..64ec12f7c131 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -86,7 +86,10 @@ import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
+import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.ipsec.ike.exceptions.IkeTimeoutException;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -122,6 +125,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal;
@@ -207,7 +211,9 @@ public class Vpn {
private final Context mUserIdContext;
@VisibleForTesting final Dependencies mDeps;
private final NetworkInfo mNetworkInfo;
+ @GuardedBy("this")
private int mLegacyState;
+ @GuardedBy("this")
@VisibleForTesting protected String mPackage;
private int mOwnerUID;
private boolean mIsPackageTargetingAtLeastQ;
@@ -245,6 +251,7 @@ public class Vpn {
* Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
* only applies to {@link VpnService} connections.
*/
+ @GuardedBy("this")
@VisibleForTesting protected boolean mAlwaysOn = false;
/**
@@ -252,6 +259,7 @@ public class Vpn {
* apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is
* not set. Applies to all types of VPNs.
*/
+ @GuardedBy("this")
@VisibleForTesting protected boolean mLockdown = false;
/**
@@ -604,7 +612,7 @@ public class Vpn {
}
/** Returns the package name that is currently prepared. */
- public String getPackage() {
+ public synchronized String getPackage() {
return mPackage;
}
@@ -685,6 +693,36 @@ public class Vpn {
return true;
}
+ private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass,
+ int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
+ @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
+ @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
+ final Intent intent = new Intent(VpnManager.ACTION_VPN_MANAGER_EVENT);
+ intent.setPackage(packageName);
+ intent.addCategory(category);
+ intent.putExtra(VpnManager.EXTRA_VPN_PROFILE_STATE, profileState);
+ intent.putExtra(VpnManager.EXTRA_SESSION_KEY, sessionKey);
+ intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK, underlyingNetwork);
+ intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES, nc);
+ intent.putExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES, lp);
+ intent.putExtra(VpnManager.EXTRA_TIMESTAMP_MILLIS, System.currentTimeMillis());
+ if (!VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER.equals(category)
+ || !VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED.equals(category)) {
+ intent.putExtra(VpnManager.EXTRA_ERROR_CLASS, errorClass);
+ intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode);
+ }
+ try {
+ return mUserIdContext.startService(intent) != null;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e);
+ return false;
+ }
+ }
+
+ private boolean isVpnApp(String packageName) {
+ return packageName != null && !VpnConfig.LEGACY_VPN.equals(packageName);
+ }
+
/**
* Configures an always-on VPN connection through a specific application. This connection is
* automatically granted and persisted after a reboot.
@@ -707,9 +745,40 @@ public class Vpn {
boolean lockdown,
@Nullable List<String> lockdownAllowlist) {
enforceControlPermissionOrInternalCaller();
+ // Store mPackage since it might be reset or might be replaced with the other VPN app.
+ final String oldPackage = mPackage;
+ final boolean isPackageChanged = !Objects.equals(packageName, oldPackage);
+ // TODO: Remove "SdkLevel.isAtLeastT()" check once VpnManagerService is decoupled from
+ // ConnectivityServiceTest.
+ // Only notify VPN apps that were already always-on, and only if the always-on provider
+ // changed, or the lockdown mode changed.
+ final boolean shouldNotifyOldPkg = isVpnApp(oldPackage) && mAlwaysOn
+ && (lockdown != mLockdown || isPackageChanged);
+ // Also notify the new package if there was a provider change.
+ final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
saveAlwaysOnPackage();
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (shouldNotifyOldPkg && SdkLevel.isAtLeastT()) {
+ // If both of shouldNotifyOldPkg & isPackageChanged are true, which means the
+ // always-on of old package is disabled or the old package is replaced with the new
+ // package. In this case, VpnProfileState should be disconnected.
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
+ null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
+ : makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (shouldNotifyNewPkg && SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
return true;
}
return false;
@@ -1006,6 +1075,7 @@ public class Vpn {
return true;
}
+ @GuardedBy("this")
private boolean isCurrentPreparedPackage(String packageName) {
// We can't just check that packageName matches mPackage, because if the app was uninstalled
// and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
@@ -1043,6 +1113,17 @@ public class Vpn {
if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
mAppOpsManager.finishOp(
AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null);
+ // The underlying network, NetworkCapabilities and LinkProperties are not
+ // necessary to send to VPN app since the purpose of this event is to notify
+ // VPN app that VPN is deactivated by the user.
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
+ -1 /* errorClass */, -1 /* errorCode*/, mPackage,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
}
// cleanupVpnStateLocked() is called from mVpnRunner.exit()
mVpnRunner.exit();
@@ -1299,6 +1380,7 @@ public class Vpn {
return true;
}
+ @GuardedBy("this")
private void agentConnect() {
LinkProperties lp = makeLinkProperties();
@@ -1993,6 +2075,7 @@ public class Vpn {
return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY;
}
+ @GuardedBy("this")
private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
@@ -2431,6 +2514,21 @@ public class Vpn {
}
}
+ @Nullable
+ protected synchronized NetworkCapabilities getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ NetworkCapabilities nc) {
+ if (nc == null) return null;
+ return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage(
+ nc, mOwnerUID, mPackage);
+ }
+
+ @Nullable
+ protected synchronized LinkProperties getRedactedLinkPropertiesOfUnderlyingNetwork(
+ LinkProperties lp) {
+ if (lp == null) return null;
+ return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage);
+ }
+
/** This class represents the common interface for all VPN runners. */
@VisibleForTesting
abstract class VpnRunner extends Thread {
@@ -2465,6 +2563,10 @@ public class Vpn {
interface IkeV2VpnRunnerCallback {
void onDefaultNetworkChanged(@NonNull Network network);
+ void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc);
+
+ void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
+
void onChildOpened(
@NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
@@ -2521,13 +2623,17 @@ public class Vpn {
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
+ @Nullable private NetworkCapabilities mNetworkCapabilities;
+ @Nullable private LinkProperties mLinkProperties;
private final String mSessionKey;
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
super(TAG);
mProfile = profile;
mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this);
+ // Pass mExecutor into Ikev2VpnNetworkCallback and make sure that IkeV2VpnRunnerCallback
+ // will be called by the mExecutor thread.
+ mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor);
mSessionKey = UUID.randomUUID().toString();
}
@@ -2682,73 +2788,78 @@ public class Vpn {
* <p>The Ikev2VpnRunner will unconditionally switch to the new network, killing the old IKE
* state in the process, and starting a new IkeSession instance.
*
- * <p>This method is called multiple times over the lifetime of the Ikev2VpnRunner, and is
- * called on the ConnectivityService thread. Thus, the actual work MUST be proxied to the
- * mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields.
+ * <p>This method MUST always be called on the mExecutor thread in order to ensure
+ * consistency of the Ikev2VpnRunner fields.
*/
public void onDefaultNetworkChanged(@NonNull Network network) {
Log.d(TAG, "Starting IKEv2/IPsec session on new network: " + network);
- // Proxy to the Ikev2VpnRunner (single-thread) executor to ensure consistency in lieu
- // of locking.
- mExecutor.execute(() -> {
- try {
- if (!mIsRunning) {
- Log.d(TAG, "onDefaultNetworkChanged after exit");
- return; // VPN has been shut down.
- }
+ try {
+ if (!mIsRunning) {
+ Log.d(TAG, "onDefaultNetworkChanged after exit");
+ return; // VPN has been shut down.
+ }
- // Clear mInterface to prevent Ikev2VpnRunner being cleared when
- // interfaceRemoved() is called.
- mInterface = null;
- // Without MOBIKE, we have no way to seamlessly migrate. Close on old
- // (non-default) network, and start the new one.
- resetIkeState();
- mActiveNetwork = network;
-
- // Get Ike options from IkeTunnelConnectionParams if it's available in the
- // profile.
- final IkeTunnelConnectionParams ikeTunConnParams =
- mProfile.getIkeTunnelConnectionParams();
- final IkeSessionParams ikeSessionParams;
- final ChildSessionParams childSessionParams;
- if (ikeTunConnParams != null) {
- final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(
- ikeTunConnParams.getIkeSessionParams()).setNetwork(network);
- ikeSessionParams = builder.build();
- childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams();
- } else {
- ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams(
- mContext, mProfile, network);
- childSessionParams = VpnIkev2Utils.buildChildSessionParams(
- mProfile.getAllowedAlgorithms());
- }
+ // Clear mInterface to prevent Ikev2VpnRunner being cleared when
+ // interfaceRemoved() is called.
+ mInterface = null;
+ // Without MOBIKE, we have no way to seamlessly migrate. Close on old
+ // (non-default) network, and start the new one.
+ resetIkeState();
+ mActiveNetwork = network;
- // TODO: Remove the need for adding two unused addresses with
- // IPsec tunnels.
- final InetAddress address = InetAddress.getLocalHost();
- mTunnelIface =
- mIpSecManager.createIpSecTunnelInterface(
- address /* unused */,
- address /* unused */,
- network);
- NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
-
- mSession = mIkev2SessionCreator.createIkeSession(
- mContext,
- ikeSessionParams,
- childSessionParams,
- mExecutor,
- new VpnIkev2Utils.IkeSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network),
- new VpnIkev2Utils.ChildSessionCallbackImpl(
- TAG, IkeV2VpnRunner.this, network));
- Log.d(TAG, "Ike Session started for network " + network);
- } catch (Exception e) {
- Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
- onSessionLost(network, e);
+ // Get Ike options from IkeTunnelConnectionParams if it's available in the
+ // profile.
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ final IkeSessionParams ikeSessionParams;
+ final ChildSessionParams childSessionParams;
+ if (ikeTunConnParams != null) {
+ final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(
+ ikeTunConnParams.getIkeSessionParams()).setNetwork(network);
+ ikeSessionParams = builder.build();
+ childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams();
+ } else {
+ ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams(
+ mContext, mProfile, network);
+ childSessionParams = VpnIkev2Utils.buildChildSessionParams(
+ mProfile.getAllowedAlgorithms());
}
- });
+
+ // TODO: Remove the need for adding two unused addresses with
+ // IPsec tunnels.
+ final InetAddress address = InetAddress.getLocalHost();
+ mTunnelIface =
+ mIpSecManager.createIpSecTunnelInterface(
+ address /* unused */,
+ address /* unused */,
+ network);
+ NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName());
+
+ mSession = mIkev2SessionCreator.createIkeSession(
+ mContext,
+ ikeSessionParams,
+ childSessionParams,
+ mExecutor,
+ new VpnIkev2Utils.IkeSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, network),
+ new VpnIkev2Utils.ChildSessionCallbackImpl(
+ TAG, IkeV2VpnRunner.this, network));
+ Log.d(TAG, "Ike Session started for network " + network);
+ } catch (Exception e) {
+ Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
+ onSessionLost(network, e);
+ }
+ }
+
+ /** Called when the NetworkCapabilities of underlying network is changed */
+ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) {
+ mNetworkCapabilities = nc;
+ }
+
+ /** Called when the LinkProperties of underlying network is changed */
+ public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
+ mLinkProperties = lp;
}
/** Marks the state as FAILED, and disconnects. */
@@ -2781,28 +2892,120 @@ public class Vpn {
return;
}
- if (exception instanceof IkeProtocolException) {
- final IkeProtocolException ikeException = (IkeProtocolException) exception;
-
- switch (ikeException.getErrorType()) {
- case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
- // All the above failures are configuration errors, and are terminal
- markFailedAndDisconnect(exception);
- return;
- // All other cases possibly recoverable.
+ synchronized (Vpn.this) {
+ if (exception instanceof IkeProtocolException) {
+ final IkeProtocolException ikeException = (IkeProtocolException) exception;
+
+ switch (ikeException.getErrorType()) {
+ case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ markFailedAndDisconnect(exception);
+ return;
+ // All other cases possibly recoverable.
+ default:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ }
+ } else if (exception instanceof IllegalArgumentException) {
+ // Failed to build IKE/ChildSessionParams; fatal profile configuration error
+ markFailedAndDisconnect(exception);
+ return;
+ } else if (exception instanceof IkeNetworkLostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_LOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ } else if (exception instanceof IkeNonProtocolException) {
+ if (exception.getCause() instanceof UnknownHostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IkeTimeoutException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IOException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_IO,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ this.mNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ this.mLinkProperties));
+ }
+ }
+ } else if (exception != null) {
+ Log.wtf(TAG, "onSessionLost: exception = " + exception);
}
- } else if (exception instanceof IllegalArgumentException) {
- // Failed to build IKE/ChildSessionParams; fatal profile configuration error
- markFailedAndDisconnect(exception);
- return;
}
mActiveNetwork = null;
+ mNetworkCapabilities = null;
+ mLinkProperties = null;
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
// (Mirrors VpnService behavior)
@@ -2867,6 +3070,8 @@ public class Vpn {
*/
private void disconnectVpnRunner() {
mActiveNetwork = null;
+ mNetworkCapabilities = null;
+ mLinkProperties = null;
mIsRunning = false;
resetIkeState();
@@ -3493,11 +3698,19 @@ public class Vpn {
}
}
- private VpnProfileState makeVpnProfileState() {
+ @GuardedBy("this")
+ @NonNull
+ private VpnProfileState makeVpnProfileStateLocked() {
return new VpnProfileState(getStateFromLegacyState(mLegacyState),
isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown);
}
+ @NonNull
+ private VpnProfileState makeDisconnectedVpnProfileState() {
+ return new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, null /* sessionKey */,
+ false /* alwaysOn */, false /* lockdown */);
+ }
+
/**
* Retrieve the VpnProfileState for the profile provisioned by the given package.
*
@@ -3509,7 +3722,7 @@ public class Vpn {
@NonNull String packageName) {
requireNonNull(packageName, "No package name provided");
enforceNotRestrictedUser();
- return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileState() : null;
+ return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
}
/**
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index a0a596d998bf..e1e488db679f 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -50,7 +50,9 @@ import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecAlgorithm;
import android.net.IpSecTransform;
+import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.ChildSaProposal;
@@ -86,6 +88,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.ExecutorService;
/**
* Utility class to build and convert IKEv2/IPsec parameters.
@@ -376,22 +379,41 @@ public class VpnIkev2Utils {
static class Ikev2VpnNetworkCallback extends NetworkCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
+ private final ExecutorService mExecutor;
- Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback) {
+ Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback,
+ ExecutorService executor) {
mTag = tag;
mCallback = callback;
+ mExecutor = executor;
}
@Override
public void onAvailable(@NonNull Network network) {
Log.d(mTag, "Starting IKEv2/IPsec session on new network: " + network);
- mCallback.onDefaultNetworkChanged(network);
+ mExecutor.execute(() -> mCallback.onDefaultNetworkChanged(network));
+ }
+
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ Log.d(mTag, "NC changed for net " + network + " : " + networkCapabilities);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkCapabilitiesChanged(networkCapabilities));
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(@NonNull Network network,
+ @NonNull LinkProperties linkProperties) {
+ Log.d(mTag, "LP changed for net " + network + " : " + linkProperties);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkLinkPropertiesChanged(linkProperties));
}
@Override
public void onLost(@NonNull Network network) {
Log.d(mTag, "Tearing down; lost network: " + network);
- mCallback.onSessionLost(network, null);
+ mExecutor.execute(() -> mCallback.onSessionLost(network, null));
}
}
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 504769064808..5418dc59097c 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -150,14 +150,18 @@ class UserDataPreparer {
if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId));
- FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId));
+ // Delete the contents of /data/system_de/$userId, but not the directory itself
+ // since vold is responsible for that and system_server isn't allowed to do it.
+ FileUtils.deleteContents(getDataSystemDeDirectory(userId));
}
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId));
+ // Likewise, delete the contents of /data/system_ce/$userId but not the
+ // directory itself.
+ FileUtils.deleteContents(getDataSystemCeDirectory(userId));
}
}
- // Data with special labels is now gone, so finish the job
+ // All the user's data directories should be empty now, so finish the job.
storage.destroyUserStorage(volumeUuid, userId, flags);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 075275ac533c..be7e2dadc7ac 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3966,7 +3966,7 @@ public class UserManagerService extends IUserManager.Stub {
for (int i = 0; i < userSize; i++) {
final UserData user = mUsers.valueAt(i);
if (DBG) Slog.d(LOG_TAG, i + ":" + user.info.toFullString());
- if (user.info.preCreated && user.info.userType.equals(userType)) {
+ if (user.info.preCreated && !user.info.partial && user.info.userType.equals(userType)) {
if (!user.info.isInitialized()) {
Slog.w(LOG_TAG, "found pre-created user of type " + userType
+ ", but it's not initialized yet: " + user.info.toFullString());
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 7e4f0e72b62d..0a033380e6c9 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -25,7 +25,6 @@ package {
android_test_helper_app {
name: "PackageManagerServiceDeviceSideTests",
- sdk_version: "test_current",
srcs: ["src/**/*.kt"],
libs: [
"android.test.base",
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
index c489cf0a138d..de83e518067e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserDataPreparerTest.java
@@ -17,6 +17,8 @@
package com.android.server.pm;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.verify;
@@ -129,22 +131,16 @@ public class UserDataPreparerTest {
}
@Test
- public void testDestroyUserData() throws Exception {
- // Add file in CE
+ public void testDestroyUserData_De_DoesNotDestroyCe() throws Exception {
+ // Add file in CE storage
File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
systemCeDir.mkdirs();
File ceFile = new File(systemCeDir, "file");
writeFile(ceFile, "-----" );
- testDestroyUserData_De();
- // CE directory should be preserved
+ // Destroy DE storage, then verify that CE storage wasn't destroyed too.
+ mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty(
systemCeDir)));
-
- testDestroyUserData_Ce();
-
- // Verify that testDir is empty
- assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
- mUserDataPreparer.testDir)));
}
@Test
@@ -163,7 +159,13 @@ public class UserDataPreparerTest {
verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_DE));
- assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir)));
+ // systemDir (normal path: /data/system/users/$userId) should have been deleted.
+ assertFalse(systemDir.exists());
+ // systemDeDir (normal path: /data/system_de/$userId) should still exist but be empty, since
+ // UserDataPreparer itself is responsible for deleting the contents of this directory, but
+ // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
+ // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
+ assertTrue(systemDeDir.exists());
assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
systemDeDir)));
}
@@ -181,6 +183,11 @@ public class UserDataPreparerTest {
verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
+ // systemCeDir (normal path: /data/system_ce/$userId) should still exist but be empty, since
+ // UserDataPreparer itself is responsible for deleting the contents of this directory, but
+ // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
+ // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
+ assertTrue(systemCeDir.exists());
assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
systemCeDir)));
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ac1fcce20dc0..f5047bf82905 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -76,7 +76,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -140,13 +139,26 @@ public class UsageStatsService extends SystemService implements
private static final boolean ENABLE_KERNEL_UPDATES = true;
private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
- private static final File USAGE_STATS_LEGACY_DIR = new File(
- Environment.getDataSystemDirectory(), "usagestats");
- // For migration purposes, indicates whether to keep the legacy usage stats directory or not
- private static final boolean KEEP_LEGACY_DIR = false;
-
- private static final File COMMON_USAGE_STATS_DE_DIR =
+ // /data/system/usagestats. Now only used for globalcomponentusage. Previously per-user stats
+ // were stored here too, but they've been moved to /data/system_ce/$userId/usagestats.
+ private static final File COMMON_USAGE_STATS_DIR =
+ new File(Environment.getDataSystemDirectory(), "usagestats");
+ private static final File LEGACY_USER_USAGE_STATS_DIR = COMMON_USAGE_STATS_DIR;
+
+ // /data/system_de/usagestats. When the globalcomponentusage file was added, it was incorrectly
+ // added here instead of in /data/system/usagestats where it should be. We lazily migrate this
+ // file by reading it from here if needed, and always writing it to the new path. We don't
+ // delete the old directory, as system_server no longer has permission to do so.
+ //
+ // Note, this migration is *not* related to the migration of the per-user stats from
+ // /data/system/usagestats/$userId to /data/system_ce/$userId/usagestats mentioned above. Both
+ // of these just happen to involve /data/system/usagestats. /data/system is the right place for
+ // system data not tied to a user, but the wrong place for per-user data. So due to two
+ // separate mistakes, we've unfortunately ended up with one case where we need to move files out
+ // of /data/system, and one case where we need to move a different file *into* /data/system.
+ private static final File LEGACY_COMMON_USAGE_STATS_DIR =
new File(Environment.getDataSystemDeDirectory(), "usagestats");
+
private static final String GLOBAL_COMPONENT_USAGE_FILE_NAME = "globalcomponentusage";
private static final char TOKEN_DELIMITER = '/';
@@ -630,7 +642,7 @@ public class UsageStatsService extends SystemService implements
final int previousVersion = Integer.parseInt(reader.readLine());
// UsageStatsDatabase.BACKUP_VERSION was 4 when usage stats were migrated to CE.
if (previousVersion >= 4) {
- deleteLegacyDir(userId);
+ deleteLegacyUserDir(userId);
return;
}
// If migration logic needs to be changed in a future version, do it here.
@@ -651,7 +663,7 @@ public class UsageStatsService extends SystemService implements
}
Slog.i(TAG, "Starting migration to system CE for user " + userId);
- final File legacyUserDir = new File(USAGE_STATS_LEGACY_DIR, Integer.toString(userId));
+ final File legacyUserDir = new File(LEGACY_USER_USAGE_STATS_DIR, Integer.toString(userId));
if (legacyUserDir.exists()) {
copyRecursively(usageStatsDir, legacyUserDir);
}
@@ -666,8 +678,8 @@ public class UsageStatsService extends SystemService implements
}
Slog.i(TAG, "Finished migration to system CE for user " + userId);
- // Migration was successful - delete the legacy directory
- deleteLegacyDir(userId);
+ // Migration was successful - delete the legacy user directory
+ deleteLegacyUserDir(userId);
}
private static void copyRecursively(final File parent, File f) {
@@ -698,21 +710,14 @@ public class UsageStatsService extends SystemService implements
}
}
- private void deleteLegacyDir(int userId) {
- final File legacyUserDir = new File(USAGE_STATS_LEGACY_DIR, Integer.toString(userId));
- if (!KEEP_LEGACY_DIR && legacyUserDir.exists()) {
+ private void deleteLegacyUserDir(int userId) {
+ final File legacyUserDir = new File(LEGACY_USER_USAGE_STATS_DIR, Integer.toString(userId));
+ if (legacyUserDir.exists()) {
deleteRecursively(legacyUserDir);
if (legacyUserDir.exists()) {
Slog.w(TAG, "Error occurred while attempting to delete legacy usage stats "
+ "dir for user " + userId);
}
- // If all users have been migrated, delete the parent legacy usage stats directory
- if (USAGE_STATS_LEGACY_DIR.list() != null
- && USAGE_STATS_LEGACY_DIR.list().length == 0) {
- if (!USAGE_STATS_LEGACY_DIR.delete()) {
- Slog.w(TAG, "Error occurred while attempting to delete legacy usage stats dir");
- }
- }
}
}
@@ -807,13 +812,16 @@ public class UsageStatsService extends SystemService implements
}
private void loadGlobalComponentUsageLocked() {
- final File[] packageUsageFile = COMMON_USAGE_STATS_DE_DIR.listFiles(
- (dir, name) -> TextUtils.equals(name, GLOBAL_COMPONENT_USAGE_FILE_NAME));
- if (packageUsageFile == null || packageUsageFile.length == 0) {
- return;
+ AtomicFile af = new AtomicFile(new File(COMMON_USAGE_STATS_DIR,
+ GLOBAL_COMPONENT_USAGE_FILE_NAME));
+ if (!af.exists()) {
+ af = new AtomicFile(new File(LEGACY_COMMON_USAGE_STATS_DIR,
+ GLOBAL_COMPONENT_USAGE_FILE_NAME));
+ if (!af.exists()) {
+ return;
+ }
+ Slog.i(TAG, "Reading " + GLOBAL_COMPONENT_USAGE_FILE_NAME + " file from old location");
}
-
- final AtomicFile af = new AtomicFile(packageUsageFile[0]);
final Map<String, Long> tmpUsage = new ArrayMap<>();
try {
try (FileInputStream in = af.openRead()) {
@@ -831,7 +839,7 @@ public class UsageStatsService extends SystemService implements
}
} catch (Exception e) {
// Most likely trying to read a corrupted file - log the failure
- Slog.e(TAG, "Could not read " + packageUsageFile[0]);
+ Slog.e(TAG, "Could not read " + af.getBaseFile());
}
}
@@ -840,11 +848,11 @@ public class UsageStatsService extends SystemService implements
return;
}
- if (!COMMON_USAGE_STATS_DE_DIR.mkdirs() && !COMMON_USAGE_STATS_DE_DIR.exists()) {
- throw new IllegalStateException("Common usage stats DE directory does not exist: "
- + COMMON_USAGE_STATS_DE_DIR.getAbsolutePath());
+ if (!COMMON_USAGE_STATS_DIR.mkdirs() && !COMMON_USAGE_STATS_DIR.exists()) {
+ throw new IllegalStateException("Common usage stats directory does not exist: "
+ + COMMON_USAGE_STATS_DIR.getAbsolutePath());
}
- final File lastTimePackageFile = new File(COMMON_USAGE_STATS_DE_DIR,
+ final File lastTimePackageFile = new File(COMMON_USAGE_STATS_DIR,
GLOBAL_COMPONENT_USAGE_FILE_NAME);
final AtomicFile af = new AtomicFile(lastTimePackageFile);
FileOutputStream fos = null;
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 01feacd826c5..4dc5423caeef 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -29,6 +29,7 @@ java_library_static {
"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.gadget-V1.0-java",
"android.hardware.usb.gadget-V1.1-java",
"android.hardware.usb.gadget-V1.2-java",
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index ec28040f82d8..d4726397b5eb 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,6 +16,8 @@
package com.android.server.usb;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
@@ -25,6 +27,12 @@ import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
import static android.hardware.usb.UsbPortStatus.MODE_UFP;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SOURCE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SINK;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_HOST;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_DEVICE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_DFP;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_UFP;
import static com.android.internal.usb.DumpUtils.writePort;
import static com.android.internal.usb.DumpUtils.writePortStatus;
@@ -38,6 +46,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
@@ -74,9 +83,13 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
+import com.android.server.usb.hal.port.RawPortInfo;
+import com.android.server.usb.hal.port.UsbPortHal;
+import com.android.server.usb.hal.port.UsbPortHalInstance;
import java.util.ArrayList;
import java.util.NoSuchElementException;
+import java.util.Objects;
/**
* Allows trusted components to control the properties of physical USB ports
@@ -109,16 +122,9 @@ public class UsbPortManager {
// The system context.
private final Context mContext;
- // Proxy object for the usb hal daemon.
- @GuardedBy("mLock")
- private IUsb mProxy = null;
-
// Callback when the UsbPort status is changed by the kernel.
// Mostly due a command sent by the remote Usb device.
- private HALCallback mHALCallback = new HALCallback(null, this);
-
- // Cookie sent for usb hal death notification.
- private static final int USB_HAL_DEATH_COOKIE = 1000;
+ //private HALCallback mHALCallback = new HALCallback(null, this);
// Used as the key while sending the bundle to Main thread.
private static final String PORT_INFO = "port_info";
@@ -156,36 +162,23 @@ public class UsbPortManager {
*/
private int mIsPortContaminatedNotificationId;
- private boolean mEnableUsbDataSignaling;
- protected int mCurrentUsbHalVersion;
+ private UsbPortHal mUsbPortHal;
+
+ private long mTransactionId;
public UsbPortManager(Context context) {
mContext = context;
- try {
- ServiceNotification serviceNotification = new ServiceNotification();
-
- boolean ret = IServiceManager.getService()
- .registerForNotifications("android.hardware.usb@1.0::IUsb",
- "", serviceNotification);
- if (!ret) {
- logAndPrint(Log.ERROR, null,
- "Failed to register service start notification");
- }
- } catch (RemoteException e) {
- logAndPrintException(null,
- "Failed to register service start notification", e);
- return;
- }
- connectToProxy(null);
+ mUsbPortHal = UsbPortHalInstance.getInstance(this, null);
+ logAndPrint(Log.DEBUG, null, "getInstance done");
}
public void systemReady() {
- mSystemReady = true;
- if (mProxy != null) {
+ mSystemReady = true;
+ if (mUsbPortHal != null) {
+ mUsbPortHal.systemReady();
try {
- mProxy.queryPortStatus();
- mEnableUsbDataSignaling = true;
- } catch (RemoteException e) {
+ mUsbPortHal.queryPortStatus(++mTransactionId);
+ } catch (Exception e) {
logAndPrintException(null,
"ServiceStart: Failed to query port status", e);
}
@@ -340,13 +333,9 @@ public class UsbPortManager {
}
try {
- // Oneway call into the hal. Use the castFrom method from HIDL.
- android.hardware.usb.V1_2.IUsb proxy = android.hardware.usb.V1_2.IUsb.castFrom(mProxy);
- proxy.enableContaminantPresenceDetection(portId, enable);
- } catch (RemoteException e) {
+ mUsbPortHal.enableContaminantPresenceDetection(portId, enable, ++mTransactionId);
+ } catch (Exception e) {
logAndPrintException(pw, "Failed to set contaminant detection", e);
- } catch (ClassCastException e) {
- logAndPrintException(pw, "Method only applicable to V1.2 or above implementation", e);
}
}
@@ -355,46 +344,79 @@ public class UsbPortManager {
*
* @param enable enable or disable USB data signaling
*/
- public boolean enableUsbDataSignal(boolean enable) {
+ public boolean enableUsbData(@NonNull String portId, boolean enable, int transactionId,
+ @NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(portId);
+ final PortInfo portInfo = mPorts.get(portId);
+ if (portInfo == null) {
+ logAndPrint(Log.ERROR, pw, "enableUsbData: No such port: " + portId
+ + " opId:" + transactionId);
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_PORT_MISMATCH);
+ } catch (RemoteException e) {
+ logAndPrintException(pw,
+ "enableUsbData: Failed to call OperationComplete. opId:"
+ + transactionId, e);
+ }
+ return false;
+ }
+
try {
- mEnableUsbDataSignaling = enable;
- // Call into the hal. Use the castFrom method from HIDL.
- android.hardware.usb.V1_3.IUsb proxy = android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
- return proxy.enableUsbDataSignal(enable);
+ try {
+ return mUsbPortHal.enableUsbData(portId, enable, transactionId, callback);
+ } catch (Exception e) {
+ logAndPrintException(pw,
+ "enableUsbData: Failed to invoke enableUsbData. opId:"
+ + transactionId , e);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ }
} catch (RemoteException e) {
- logAndPrintException(null, "Failed to set USB data signaling", e);
- return false;
- } catch (ClassCastException e) {
- logAndPrintException(null, "Method only applicable to V1.3 or above implementation", e);
- return false;
+ logAndPrintException(pw,
+ "enableUsbData: Failed to call onOperationComplete. opId:"
+ + transactionId, e);
}
+
+ return false;
}
/**
* Get USB HAL version
*
* @param none
+ * @return {@link UsbManager#USB_HAL_RETRY} returned when hal version
+ * is yet to be determined.
*/
public int getUsbHalVersion() {
- return mCurrentUsbHalVersion;
+ if (mUsbPortHal != null) {
+ try {
+ return mUsbPortHal.getUsbHalVersion();
+ } catch (RemoteException e) {
+ return UsbManager.USB_HAL_RETRY;
+ }
+ }
+ return UsbManager.USB_HAL_RETRY;
}
- /**
- * update USB HAL version
- *
- * @param none
- */
- private void updateUsbHalVersion() {
- if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
- mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_3;
- } else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
- mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_2;
- } else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
- mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_1;
- } else {
- mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0;
- }
- logAndPrint(Log.INFO, null, "USB HAL version: " + mCurrentUsbHalVersion);
+ private int toHalUsbDataRole(int usbDataRole) {
+ if (usbDataRole == DATA_ROLE_DEVICE)
+ return HAL_DATA_ROLE_DEVICE;
+ else
+ return HAL_DATA_ROLE_HOST;
+ }
+
+ private int toHalUsbPowerRole(int usbPowerRole) {
+ if (usbPowerRole == POWER_ROLE_SINK)
+ return HAL_POWER_ROLE_SINK;
+ else
+ return HAL_POWER_ROLE_SOURCE;
+ }
+
+ private int toHalUsbMode(int usbMode) {
+ if (usbMode == MODE_UFP)
+ return HAL_MODE_UFP;
+ else
+ return HAL_MODE_DFP;
}
public void setPortRoles(String portId, int newPowerRole, int newDataRole,
@@ -473,7 +495,7 @@ public class UsbPortManager {
sim.currentPowerRole = newPowerRole;
sim.currentDataRole = newDataRole;
updatePortsLocked(pw, null);
- } else if (mProxy != null) {
+ } else if (mUsbPortHal != null) {
if (currentMode != newMode) {
// Changing the mode will have the side-effect of also changing
// the power and data roles but it might take some time to apply
@@ -485,44 +507,37 @@ public class UsbPortManager {
logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newMode));
- PortRole newRole = new PortRole();
- newRole.type = PortRoleType.MODE;
- newRole.role = newMode;
try {
- mProxy.switchRole(portId, newRole);
- } catch (RemoteException e) {
+ mUsbPortHal.switchMode(portId, toHalUsbMode(newMode), ++mTransactionId);
+ } catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port mode: "
+ "portId=" + portId
- + ", newMode=" + UsbPort.modeToString(newRole.role), e);
+ + ", newMode=" + UsbPort.modeToString(newMode), e);
}
} else {
// Change power and data role independently as needed.
if (currentPowerRole != newPowerRole) {
- PortRole newRole = new PortRole();
- newRole.type = PortRoleType.POWER_ROLE;
- newRole.role = newPowerRole;
try {
- mProxy.switchRole(portId, newRole);
- } catch (RemoteException e) {
+ mUsbPortHal.switchPowerRole(portId, toHalUsbPowerRole(newPowerRole),
+ ++mTransactionId);
+ } catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port power role: "
+ "portId=" + portId
+ ", newPowerRole=" + UsbPort.powerRoleToString
- (newRole.role),
+ (newPowerRole),
e);
return;
}
}
if (currentDataRole != newDataRole) {
- PortRole newRole = new PortRole();
- newRole.type = PortRoleType.DATA_ROLE;
- newRole.role = newDataRole;
try {
- mProxy.switchRole(portId, newRole);
- } catch (RemoteException e) {
+ mUsbPortHal.switchDataRole(portId, toHalUsbDataRole(newDataRole),
+ ++mTransactionId);
+ } catch (Exception e) {
logAndPrintException(pw, "Failed to set the USB port data role: "
+ "portId=" + portId
- + ", newDataRole=" + UsbPort.dataRoleToString(newRole
- .role),
+ + ", newDataRole=" + UsbPort.dataRoleToString
+ (newDataRole),
e);
}
}
@@ -531,6 +546,15 @@ public class UsbPortManager {
}
}
+ public void updatePorts(ArrayList<RawPortInfo> newPortInfo) {
+ Message message = mHandler.obtainMessage();
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
+ message.what = MSG_UPDATE_PORTS;
+ message.setData(bundle);
+ mHandler.sendMessage(message);
+ }
+
public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) {
synchronized (mLock) {
if (mSimulatedPorts.containsKey(portId)) {
@@ -662,191 +686,12 @@ public class UsbPortManager {
portInfo.dump(dump, "usb_ports", UsbPortManagerProto.USB_PORTS);
}
- dump.write("enable_usb_data_signaling", UsbPortManagerProto.ENABLE_USB_DATA_SIGNALING,
- mEnableUsbDataSignaling);
+ dump.write("usb_hal_version", UsbPortManagerProto.HAL_VERSION, getUsbHalVersion());
}
dump.end(token);
}
- private static class HALCallback extends IUsbCallback.Stub {
- public IndentingPrintWriter pw;
- public UsbPortManager portManager;
-
- HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
- this.pw = pw;
- this.portManager = portManager;
- }
-
- public void notifyPortStatusChange(
- ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
- if (!portManager.mSystemReady) {
- return;
- }
-
- if (retval != Status.SUCCESS) {
- logAndPrint(Log.ERROR, pw, "port status enquiry failed");
- return;
- }
-
- ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
- for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
- RawPortInfo temp = new RawPortInfo(current.portName,
- current.supportedModes, CONTAMINANT_PROTECTION_NONE,
- current.currentMode,
- current.canChangeMode, current.currentPowerRole,
- current.canChangePowerRole,
- current.currentDataRole, current.canChangeDataRole,
- false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
- newPortInfo.add(temp);
- logAndPrint(Log.INFO, pw, "ClientCallback V1_0: " + current.portName);
- }
-
- Message message = portManager.mHandler.obtainMessage();
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
- message.what = MSG_UPDATE_PORTS;
- message.setData(bundle);
- portManager.mHandler.sendMessage(message);
- }
-
-
- public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
- int retval) {
- if (!portManager.mSystemReady) {
- return;
- }
-
- if (retval != Status.SUCCESS) {
- logAndPrint(Log.ERROR, pw, "port status enquiry failed");
- return;
- }
-
- ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
- int numStatus = currentPortStatus.size();
- for (int i = 0; i < numStatus; i++) {
- PortStatus_1_1 current = currentPortStatus.get(i);
- RawPortInfo temp = new RawPortInfo(current.status.portName,
- current.supportedModes, CONTAMINANT_PROTECTION_NONE,
- current.currentMode,
- current.status.canChangeMode, current.status.currentPowerRole,
- current.status.canChangePowerRole,
- current.status.currentDataRole, current.status.canChangeDataRole,
- false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
- newPortInfo.add(temp);
- logAndPrint(Log.INFO, pw, "ClientCallback V1_1: " + current.status.portName);
- }
-
- Message message = portManager.mHandler.obtainMessage();
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
- message.what = MSG_UPDATE_PORTS;
- message.setData(bundle);
- portManager.mHandler.sendMessage(message);
- }
-
- public void notifyPortStatusChange_1_2(
- ArrayList<PortStatus> currentPortStatus, int retval) {
- if (!portManager.mSystemReady) {
- return;
- }
-
- if (retval != Status.SUCCESS) {
- logAndPrint(Log.ERROR, pw, "port status enquiry failed");
- return;
- }
-
- ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
- int numStatus = currentPortStatus.size();
- for (int i = 0; i < numStatus; i++) {
- PortStatus current = currentPortStatus.get(i);
- RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
- current.status_1_1.supportedModes,
- current.supportedContaminantProtectionModes,
- current.status_1_1.currentMode,
- current.status_1_1.status.canChangeMode,
- current.status_1_1.status.currentPowerRole,
- current.status_1_1.status.canChangePowerRole,
- current.status_1_1.status.currentDataRole,
- current.status_1_1.status.canChangeDataRole,
- current.supportsEnableContaminantPresenceProtection,
- current.contaminantProtectionStatus,
- current.supportsEnableContaminantPresenceDetection,
- current.contaminantDetectionStatus);
- newPortInfo.add(temp);
- logAndPrint(Log.INFO, pw, "ClientCallback V1_2: "
- + current.status_1_1.status.portName);
- }
-
- Message message = portManager.mHandler.obtainMessage();
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
- message.what = MSG_UPDATE_PORTS;
- message.setData(bundle);
- portManager.mHandler.sendMessage(message);
- }
-
- public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
- if (retval == Status.SUCCESS) {
- logAndPrint(Log.INFO, pw, portName + " role switch successful");
- } else {
- logAndPrint(Log.ERROR, pw, portName + " role switch failed");
- }
- }
- }
-
- final class DeathRecipient implements HwBinder.DeathRecipient {
- public IndentingPrintWriter pw;
-
- DeathRecipient(IndentingPrintWriter pw) {
- this.pw = pw;
- }
-
- @Override
- public void serviceDied(long cookie) {
- if (cookie == USB_HAL_DEATH_COOKIE) {
- logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
- synchronized (mLock) {
- mProxy = null;
- }
- }
- }
- }
-
- final class ServiceNotification extends IServiceNotification.Stub {
- @Override
- public void onRegistration(String fqName, String name, boolean preexisting) {
- logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
- connectToProxy(null);
- }
- }
-
- private void connectToProxy(IndentingPrintWriter pw) {
- synchronized (mLock) {
- if (mProxy != null) {
- return;
- }
-
- try {
- mProxy = IUsb.getService();
- mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
- mProxy.setCallback(mHALCallback);
- mProxy.queryPortStatus();
- updateUsbHalVersion();
- } catch (NoSuchElementException e) {
- logAndPrintException(pw, "connectToProxy: usb hal service not found."
- + " Did the service fail to start?", e);
- } catch (RemoteException e) {
- logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
- }
- }
- }
-
/**
* Simulated ports directly add the new roles to mSimulatedPorts before calling.
* USB hal callback populates and sends the newPortInfo.
@@ -869,7 +714,8 @@ public class UsbPortManager {
portInfo.supportsEnableContaminantPresenceProtection,
portInfo.contaminantProtectionStatus,
portInfo.supportsEnableContaminantPresenceDetection,
- portInfo.contaminantDetectionStatus, pw);
+ portInfo.contaminantDetectionStatus,
+ portInfo.usbDataEnabled, pw);
}
} else {
for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -881,7 +727,8 @@ public class UsbPortManager {
currentPortInfo.supportsEnableContaminantPresenceProtection,
currentPortInfo.contaminantProtectionStatus,
currentPortInfo.supportsEnableContaminantPresenceDetection,
- currentPortInfo.contaminantDetectionStatus, pw);
+ currentPortInfo.contaminantDetectionStatus,
+ currentPortInfo.usbDataEnabled, pw);
}
}
@@ -917,6 +764,7 @@ public class UsbPortManager {
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
+ boolean usbDataEnabled,
IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
@@ -975,7 +823,7 @@ public class UsbPortManager {
currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
- contaminantDetectionStatus);
+ contaminantDetectionStatus, usbDataEnabled);
mPorts.put(portId, portInfo);
} else {
// Validate that ports aren't changing definition out from under us.
@@ -1012,7 +860,7 @@ public class UsbPortManager {
currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
- contaminantDetectionStatus)) {
+ contaminantDetectionStatus, usbDataEnabled)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1141,14 +989,14 @@ public class UsbPortManager {
}
}
- private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+ public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
Slog.println(priority, TAG, msg);
if (pw != null) {
pw.println(msg);
}
}
- private static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+ public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
Slog.e(TAG, msg, e);
if (pw != null) {
pw.println(msg + e);
@@ -1179,7 +1027,7 @@ public class UsbPortManager {
/**
* Describes a USB port.
*/
- private static final class PortInfo {
+ public static final class PortInfo {
public static final int DISPOSITION_ADDED = 0;
public static final int DISPOSITION_CHANGED = 1;
public static final int DISPOSITION_READY = 2;
@@ -1224,7 +1072,7 @@ public class UsbPortManager {
!= supportedRoleCombinations) {
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
- UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED);
+ UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED, true);
dispositionChanged = true;
}
@@ -1243,7 +1091,7 @@ public class UsbPortManager {
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
- int contaminantDetectionStatus) {
+ int contaminantDetectionStatus, boolean usbDataEnabled) {
boolean dispositionChanged = false;
mCanChangeMode = canChangeMode;
@@ -1258,10 +1106,12 @@ public class UsbPortManager {
|| mUsbPortStatus.getContaminantProtectionStatus()
!= contaminantProtectionStatus
|| mUsbPortStatus.getContaminantDetectionStatus()
- != contaminantDetectionStatus) {
+ != contaminantDetectionStatus
+ || mUsbPortStatus.getUsbDataStatus()
+ != usbDataEnabled){
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
- contaminantDetectionStatus);
+ contaminantDetectionStatus, usbDataEnabled);
dispositionChanged = true;
}
@@ -1290,7 +1140,6 @@ public class UsbPortManager {
UsbPortInfoProto.CONNECTED_AT_MILLIS, mConnectedAtMillis);
dump.write("last_connect_duration_millis",
UsbPortInfoProto.LAST_CONNECT_DURATION_MILLIS, mLastConnectDurationMillis);
-
dump.end(token);
}
@@ -1304,115 +1153,4 @@ public class UsbPortManager {
+ ", lastConnectDurationMillis=" + mLastConnectDurationMillis;
}
}
-
- /**
- * Used for storing the raw data from the kernel
- * Values of the member variables mocked directly incase of emulation.
- */
- private static final class RawPortInfo implements Parcelable {
- public final String portId;
- public final int supportedModes;
- public final int supportedContaminantProtectionModes;
- public int currentMode;
- public boolean canChangeMode;
- public int currentPowerRole;
- public boolean canChangePowerRole;
- public int currentDataRole;
- public boolean canChangeDataRole;
- public boolean supportsEnableContaminantPresenceProtection;
- public int contaminantProtectionStatus;
- public boolean supportsEnableContaminantPresenceDetection;
- public int contaminantDetectionStatus;
-
- RawPortInfo(String portId, int supportedModes) {
- this.portId = portId;
- this.supportedModes = supportedModes;
- this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
- this.supportsEnableContaminantPresenceProtection = false;
- this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
- this.supportsEnableContaminantPresenceDetection = false;
- this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
- }
-
- RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
- int currentMode, boolean canChangeMode,
- int currentPowerRole, boolean canChangePowerRole,
- int currentDataRole, boolean canChangeDataRole,
- boolean supportsEnableContaminantPresenceProtection,
- int contaminantProtectionStatus,
- boolean supportsEnableContaminantPresenceDetection,
- int contaminantDetectionStatus) {
- this.portId = portId;
- this.supportedModes = supportedModes;
- this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
- this.currentMode = currentMode;
- this.canChangeMode = canChangeMode;
- this.currentPowerRole = currentPowerRole;
- this.canChangePowerRole = canChangePowerRole;
- this.currentDataRole = currentDataRole;
- this.canChangeDataRole = canChangeDataRole;
- this.supportsEnableContaminantPresenceProtection =
- supportsEnableContaminantPresenceProtection;
- this.contaminantProtectionStatus = contaminantProtectionStatus;
- this.supportsEnableContaminantPresenceDetection =
- supportsEnableContaminantPresenceDetection;
- this.contaminantDetectionStatus = contaminantDetectionStatus;
- }
-
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(portId);
- dest.writeInt(supportedModes);
- dest.writeInt(supportedContaminantProtectionModes);
- dest.writeInt(currentMode);
- dest.writeByte((byte) (canChangeMode ? 1 : 0));
- dest.writeInt(currentPowerRole);
- dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
- dest.writeInt(currentDataRole);
- dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
- dest.writeBoolean(supportsEnableContaminantPresenceProtection);
- dest.writeInt(contaminantProtectionStatus);
- dest.writeBoolean(supportsEnableContaminantPresenceDetection);
- dest.writeInt(contaminantDetectionStatus);
- }
-
- public static final Parcelable.Creator<RawPortInfo> CREATOR =
- new Parcelable.Creator<RawPortInfo>() {
- @Override
- public RawPortInfo createFromParcel(Parcel in) {
- String id = in.readString();
- int supportedModes = in.readInt();
- int supportedContaminantProtectionModes = in.readInt();
- int currentMode = in.readInt();
- boolean canChangeMode = in.readByte() != 0;
- int currentPowerRole = in.readInt();
- boolean canChangePowerRole = in.readByte() != 0;
- int currentDataRole = in.readInt();
- boolean canChangeDataRole = in.readByte() != 0;
- boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
- int contaminantProtectionStatus = in.readInt();
- boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
- int contaminantDetectionStatus = in.readInt();
- return new RawPortInfo(id, supportedModes,
- supportedContaminantProtectionModes, currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole,
- supportsEnableContaminantPresenceProtection,
- contaminantProtectionStatus,
- supportsEnableContaminantPresenceDetection,
- contaminantDetectionStatus);
- }
-
- @Override
- public RawPortInfo[] newArray(int size) {
- return new RawPortInfo[size];
- }
- };
- }
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 3d3538d7ae49..28227fcf0468 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,7 @@
package com.android.server.usb;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
import static android.hardware.usb.UsbPortStatus.MODE_DFP;
@@ -35,6 +36,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager;
+import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
@@ -44,6 +46,7 @@ import android.hardware.usb.UsbPortStatus;
import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.usb.UsbServiceDumpProto;
@@ -762,19 +765,30 @@ public class UsbService extends IUsbManager.Stub {
}
@Override
- public boolean enableUsbDataSignal(boolean enable) {
+ public boolean enableUsbData(String portId, boolean enable, int operationId,
+ IUsbOperationInternal callback) {
+ Objects.requireNonNull(portId, "enableUsbData: portId must not be null. opId:"
+ + operationId);
+ Objects.requireNonNull(callback, "enableUsbData: callback must not be null. opId:"
+ + operationId);
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-
final long ident = Binder.clearCallingIdentity();
+ boolean wait;
try {
if (mPortManager != null) {
- return mPortManager.enableUsbDataSignal(enable);
+ wait = mPortManager.enableUsbData(portId, enable, operationId, callback, null);
} else {
- return false;
+ wait = false;
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "enableUsbData: Failed to call onOperationComplete", e);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
}
+ return wait;
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
new file mode 100644
index 000000000000..9c6cbbd96460
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 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.port;
+
+import android.hardware.usb.UsbPortStatus;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Used for storing the raw data from the HAL.
+ * Values of the member variables mocked directly in case of emulation.
+ */
+public final class RawPortInfo implements Parcelable {
+ public final String portId;
+ public final int supportedModes;
+ public final int supportedContaminantProtectionModes;
+ public int currentMode;
+ public boolean canChangeMode;
+ public int currentPowerRole;
+ public boolean canChangePowerRole;
+ public int currentDataRole;
+ public boolean canChangeDataRole;
+ public boolean supportsEnableContaminantPresenceProtection;
+ public int contaminantProtectionStatus;
+ public boolean supportsEnableContaminantPresenceDetection;
+ public int contaminantDetectionStatus;
+ public boolean usbDataEnabled;
+
+ public RawPortInfo(String portId, int supportedModes) {
+ this.portId = portId;
+ this.supportedModes = supportedModes;
+ this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+ this.supportsEnableContaminantPresenceProtection = false;
+ this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+ this.supportsEnableContaminantPresenceDetection = false;
+ this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+ this.usbDataEnabled = true;
+ }
+
+ public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole,
+ boolean supportsEnableContaminantPresenceProtection,
+ int contaminantProtectionStatus,
+ boolean supportsEnableContaminantPresenceDetection,
+ int contaminantDetectionStatus,
+ boolean usbDataEnabled) {
+ this.portId = portId;
+ this.supportedModes = supportedModes;
+ this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
+ this.currentMode = currentMode;
+ this.canChangeMode = canChangeMode;
+ this.currentPowerRole = currentPowerRole;
+ this.canChangePowerRole = canChangePowerRole;
+ this.currentDataRole = currentDataRole;
+ this.canChangeDataRole = canChangeDataRole;
+ this.supportsEnableContaminantPresenceProtection =
+ supportsEnableContaminantPresenceProtection;
+ this.contaminantProtectionStatus = contaminantProtectionStatus;
+ this.supportsEnableContaminantPresenceDetection =
+ supportsEnableContaminantPresenceDetection;
+ this.contaminantDetectionStatus = contaminantDetectionStatus;
+ this.usbDataEnabled = usbDataEnabled;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(portId);
+ dest.writeInt(supportedModes);
+ dest.writeInt(supportedContaminantProtectionModes);
+ dest.writeInt(currentMode);
+ dest.writeByte((byte) (canChangeMode ? 1 : 0));
+ dest.writeInt(currentPowerRole);
+ dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
+ dest.writeInt(currentDataRole);
+ dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
+ dest.writeBoolean(supportsEnableContaminantPresenceProtection);
+ dest.writeInt(contaminantProtectionStatus);
+ dest.writeBoolean(supportsEnableContaminantPresenceDetection);
+ dest.writeInt(contaminantDetectionStatus);
+ dest.writeBoolean(usbDataEnabled);
+ }
+
+ public static final Parcelable.Creator<RawPortInfo> CREATOR =
+ new Parcelable.Creator<RawPortInfo>() {
+ @Override
+ public RawPortInfo createFromParcel(Parcel in) {
+ String id = in.readString();
+ int supportedModes = in.readInt();
+ int supportedContaminantProtectionModes = in.readInt();
+ int currentMode = in.readInt();
+ boolean canChangeMode = in.readByte() != 0;
+ int currentPowerRole = in.readInt();
+ boolean canChangePowerRole = in.readByte() != 0;
+ int currentDataRole = in.readInt();
+ boolean canChangeDataRole = in.readByte() != 0;
+ boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
+ int contaminantProtectionStatus = in.readInt();
+ boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
+ int contaminantDetectionStatus = in.readInt();
+ boolean usbDataEnabled = in.readBoolean();
+ return new RawPortInfo(id, supportedModes,
+ supportedContaminantProtectionModes, currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportsEnableContaminantPresenceProtection,
+ contaminantProtectionStatus,
+ supportsEnableContaminantPresenceDetection,
+ contaminantDetectionStatus, usbDataEnabled);
+ }
+
+ @Override
+ public RawPortInfo[] newArray(int size) {
+ return new RawPortInfo[size];
+ }
+ };
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
new file mode 100644
index 000000000000..1efcd9ca5d65
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2021 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.port;
+
+import static android.hardware.usb.UsbManager.USB_HAL_V2_0;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+import static com.android.server.usb.UsbPortManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.ContaminantProtectionStatus;
+import android.hardware.usb.IUsb;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.PortMode;
+import android.hardware.usb.Status;
+import android.hardware.usb.IUsbCallback;
+import android.hardware.usb.PortRole;
+import android.hardware.usb.PortStatus;
+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.UsbPortManager;
+import com.android.server.usb.hal.port.RawPortInfo;
+
+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 UsbPortAidl implements UsbPortHal {
+ private static final String TAG = UsbPortAidl.class.getSimpleName();
+ private static final String USB_AIDL_SERVICE =
+ "android.hardware.usb.IUsb/default";
+ private static final LongSparseArray<IUsbOperationInternal>
+ sCallbacks = new LongSparseArray<>();
+ // Proxy object for the usb hal daemon.
+ @GuardedBy("mLock")
+ private IUsb mProxy;
+ private UsbPortManager mPortManager;
+ public IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mLock = new Object();
+ // Callback when the UsbPort status is changed by the kernel.
+ private HALCallback mHALCallback;
+ private IBinder mBinder;
+ private boolean mSystemReady;
+ private long mTransactionId;
+
+ public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ throw new RemoteException("IUsb not initialized yet");
+ }
+ }
+ logAndPrint(Log.INFO, null, "USB HAL AIDL version: USB_HAL_V2_0");
+ return USB_HAL_V2_0;
+ }
+
+ @Override
+ public void systemReady() {
+ mSystemReady = true;
+ }
+
+ public void serviceDied() {
+ logAndPrint(Log.ERROR, mPw, "Usb AIDL hal service died");
+ synchronized (mLock) {
+ mProxy = null;
+ }
+ connectToProxy(null);
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ if (mProxy != null) {
+ return;
+ }
+
+ try {
+ mBinder = ServiceManager.waitForService(USB_AIDL_SERVICE);
+ mProxy = IUsb.Stub.asInterface(mBinder);
+ mBinder.linkToDeath(this::serviceDied, 0);
+ mProxy.setCallback(mHALCallback);
+ mProxy.queryPortStatus(++mTransactionId);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb hal service not found."
+ + " Did the service fail to start?", e);
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
+ }
+ }
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ return ServiceManager.isDeclared(USB_AIDL_SERVICE);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb Aidl hal service not found.", e);
+ }
+
+ return false;
+ }
+
+ public UsbPortAidl(UsbPortManager portManager, IndentingPrintWriter pw) {
+ mPortManager = Objects.requireNonNull(portManager);
+ mPw = pw;
+ mHALCallback = new HALCallback(null, mPortManager, this);
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void enableContaminantPresenceDetection(String portName, boolean enable,
+ long operationID) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID: "
+ + operationID);
+ return;
+ }
+
+ try {
+ // Oneway call into the hal. Use the castFrom method from HIDL.
+ mProxy.enableContaminantPresenceDetection(portName, enable, operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set contaminant detection. opID:"
+ + operationID, e);
+ }
+ }
+ }
+
+ @Override
+ public void queryPortStatus(long operationID) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ + operationID);
+ return;
+ }
+
+ try {
+ mProxy.queryPortStatus(operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(null, "ServiceStart: Failed to query port status. opID:"
+ + operationID, e);
+ }
+ }
+ }
+
+ @Override
+ public void switchMode(String portId, @HalUsbPortMode int newMode, long operationID) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ + operationID);
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.setMode((byte)newMode);
+ try {
+ mProxy.switchRole(portId, newRole, operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB port mode: "
+ + "portId=" + portId
+ + ", newMode=" + UsbPort.modeToString(newMode)
+ + "opID:" + operationID, e);
+ }
+ }
+ }
+
+ @Override
+ public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
+ long operationID) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ + operationID);
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.setPowerRole((byte)newPowerRole);
+ try {
+ mProxy.switchRole(portId, newRole, operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ + "opID:" + operationID, e);
+ }
+ }
+ }
+
+ @Override
+ public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long operationID) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+ + operationID);
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.setDataRole((byte)newDataRole);
+ try {
+ mProxy.switchRole(portId, newRole, operationID);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+ + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)
+ + "opID:" + operationID, e);
+ }
+ }
+ }
+
+ @Override
+ public boolean enableUsbData(String portName, boolean enable, long operationID,
+ IUsbOperationInternal callback) {
+ Objects.requireNonNull(portName);
+ Objects.requireNonNull(callback);
+ long key = operationID;
+ synchronized (mLock) {
+ try {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw,
+ "enableUsbData: Proxy is null. Retry !opID:"
+ + operationID);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ return false;
+ }
+ while (sCallbacks.get(key) != null) {
+ key = ThreadLocalRandom.current().nextInt();
+ }
+ if (key != operationID) {
+ logAndPrint(Log.INFO, mPw, "enableUsbData: operationID exists ! opID:"
+ + operationID + " key:" + key);
+ }
+ try {
+ sCallbacks.put(key, callback);
+ mProxy.enableUsbData(portName, enable, key);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "enableUsbData: Failed to invoke enableUsbData: portID="
+ + portName + "opID:" + operationID, e);
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ sCallbacks.remove(key);
+ return false;
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "enableUsbData: Failed to call onOperationComplete portID="
+ + portName + "opID:" + operationID, e);
+ sCallbacks.remove(key);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private static class HALCallback extends IUsbCallback.Stub {
+ public IndentingPrintWriter mPw;
+ public UsbPortManager mPortManager;
+ public UsbPortAidl mUsbPortAidl;
+
+ HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortAidl usbPortAidl) {
+ this.mPw = pw;
+ this.mPortManager = portManager;
+ this.mUsbPortAidl = usbPortAidl;
+ }
+
+ /**
+ * Converts from AIDL defined mode constants to UsbPortStatus constants.
+ * AIDL does not gracefully support bitfield when combined with enums.
+ */
+ private int toPortMode(byte aidlPortMode) {
+ switch (aidlPortMode) {
+ case PortMode.NONE:
+ return UsbPortStatus.MODE_NONE;
+ case PortMode.UFP:
+ return UsbPortStatus.MODE_UFP;
+ case PortMode.DFP:
+ return UsbPortStatus.MODE_DFP;
+ case PortMode.DRP:
+ return UsbPortStatus.MODE_DUAL;
+ case PortMode.AUDIO_ACCESSORY:
+ return UsbPortStatus.MODE_AUDIO_ACCESSORY;
+ case PortMode.DEBUG_ACCESSORY:
+ return UsbPortStatus.MODE_DEBUG_ACCESSORY;
+ default:
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, "Unrecognized aidlPortMode:"
+ + aidlPortMode);
+ return UsbPortStatus.MODE_NONE;
+ }
+ }
+
+ private int toSupportedModes(byte[] aidlPortModes) {
+ int supportedModes = UsbPortStatus.MODE_NONE;
+
+ for (byte aidlPortMode : aidlPortModes) {
+ supportedModes |= toPortMode(aidlPortMode);
+ }
+
+ return supportedModes;
+ }
+
+ /**
+ * Converts from AIDL defined contaminant protection constants to UsbPortStatus constants.
+ * AIDL does not gracefully support bitfield when combined with enums.
+ * Common to both ContaminantProtectionMode and ContaminantProtectionStatus.
+ */
+ private int toContaminantProtectionStatus(byte aidlContaminantProtection) {
+ switch (aidlContaminantProtection) {
+ case ContaminantProtectionStatus.NONE:
+ return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+ case ContaminantProtectionStatus.FORCE_SINK:
+ return UsbPortStatus.CONTAMINANT_PROTECTION_SINK;
+ case ContaminantProtectionStatus.FORCE_SOURCE:
+ return UsbPortStatus.CONTAMINANT_PROTECTION_SOURCE;
+ case ContaminantProtectionStatus.FORCE_DISABLE:
+ return UsbPortStatus.CONTAMINANT_PROTECTION_FORCE_DISABLE;
+ case ContaminantProtectionStatus.DISABLED:
+ return UsbPortStatus.CONTAMINANT_PROTECTION_DISABLED;
+ default:
+ UsbPortManager.logAndPrint(Log.ERROR, mPw,
+ "Unrecognized aidlContaminantProtection:"
+ + aidlContaminantProtection);
+ return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+ }
+ }
+
+ private int toSupportedContaminantProtectionModes(byte[] aidlModes) {
+ int supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+
+ for (byte aidlMode : aidlModes) {
+ supportedContaminantProtectionModes |= toContaminantProtectionStatus(aidlMode);
+ }
+
+ return supportedContaminantProtectionModes;
+ }
+
+ @Override
+ public void notifyPortStatusChange(
+ android.hardware.usb.PortStatus[] currentPortStatus, int retval) {
+ if (!mUsbPortAidl.mSystemReady) {
+ return;
+ }
+
+ if (retval != Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+ int numStatus = currentPortStatus.length;
+ for (int i = 0; i < numStatus; i++) {
+ PortStatus current = currentPortStatus[i];
+ RawPortInfo temp = new RawPortInfo(current.portName,
+ toSupportedModes(current.supportedModes),
+ toSupportedContaminantProtectionModes(current
+ .supportedContaminantProtectionModes),
+ toPortMode(current.currentMode),
+ current.canChangeMode,
+ current.currentPowerRole,
+ current.canChangePowerRole,
+ current.currentDataRole,
+ current.canChangeDataRole,
+ current.supportsEnableContaminantPresenceProtection,
+ toContaminantProtectionStatus(current.contaminantProtectionStatus),
+ current.supportsEnableContaminantPresenceDetection,
+ current.contaminantDetectionStatus,
+ current.usbDataEnabled);
+ newPortInfo.add(temp);
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback AIDL V1: "
+ + current.portName);
+ }
+ mPortManager.updatePorts(newPortInfo);
+ }
+
+ @Override
+ public void notifyRoleSwitchStatus(String portName, PortRole role, int retval,
+ long operationID) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, portName
+ + " role switch successful. opID:"
+ + operationID);
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed. err:"
+ + retval
+ + "opID:" + operationID);
+ }
+ }
+
+ @Override
+ public void notifyQueryPortStatus(String portName, int retval, long operationID) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, portName + ": opID:"
+ + operationID + " successful");
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + ": opID:"
+ + operationID + " failed. err:" + retval);
+ }
+ }
+
+ @Override
+ public void notifyEnableUsbDataStatus(String portName, boolean enable, int retval,
+ long operationID) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyEnableUsbDataStatus:"
+ + portName + ": opID:"
+ + operationID + " enable:" + enable);
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+ + "notifyEnableUsbDataStatus: opID:"
+ + operationID + " failed. err:" + retval);
+ }
+ try {
+ sCallbacks.get(operationID).onOperationComplete(retval == Status.SUCCESS
+ ? USB_OPERATION_SUCCESS
+ : USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "notifyEnableUsbDataStatus: Failed to call onOperationComplete",
+ e);
+ }
+ }
+
+ @Override
+ public void notifyContaminantEnabledStatus(String portName, boolean enable, int retval,
+ long operationID) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyContaminantEnabledStatus:"
+ + portName + ": opID:"
+ + operationID + " enable:" + enable);
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+ + "notifyContaminantEnabledStatus: opID:"
+ + operationID + " failed. err:" + retval);
+ }
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return IUsbCallback.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return IUsbCallback.VERSION;
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
new file mode 100644
index 000000000000..e7f9bc2fe7c3
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 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.port;
+
+import android.annotation.IntDef;
+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 UsbPortHal {
+ /**
+ * 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();
+
+ /**
+ * Invoked to enable/disable contaminant presence detection on the USB port.
+ *
+ * @param portName Port Identifier.
+ * @param enable Enable contaminant presence detection when true.
+ * Disable when false.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void enableContaminantPresenceDetection(String portName, boolean enable,
+ long transactionId);
+
+ /**
+ * Invoked to query port status of all the ports.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void queryPortStatus(long transactionId);
+
+ /**
+ * Invoked to switch USB port mode.
+ *
+ * @param portName Port Identifier.
+ * @param mode New mode that the port is switching into.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void switchMode(String portName, @HalUsbPortMode int mode, long transactionId);
+
+ /**
+ * Invoked to switch USB port power role.
+ *
+ * @param portName Port Identifier.
+ * @param powerRole New power role that the port is switching into.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void switchPowerRole(String portName, @HalUsbPowerRole int powerRole,
+ long transactionId);
+
+ /**
+ * Invoked to switch USB port data role.
+ *
+ * @param portName Port Identifier.
+ * @param dataRole New data role that the port is switching into.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void switchDataRole(String portName, @HalUsbDataRole int dataRole, long transactionId);
+
+ /**
+ * Invoked to query the version of current hal implementation.
+ */
+ public @UsbHalVersion int getUsbHalVersion() throws RemoteException;
+
+ /**
+ * Invoked to enable/disable UsbData on the specified port.
+ *
+ * @param portName Port Identifier.
+ * @param enable Enable USB data when true.
+ * Disable when false.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ * @param callback callback object to be invoked to invoke the status of the operation upon
+ * completion.
+ * @param callback callback object to be invoked when the operation is complete.
+ * @return True when the operation is asynchronous. The caller of
+ * {@link UsbOperationCallbackInternal} must therefore call
+ * {@link UsbOperationCallbackInternal#waitForOperationComplete} for processing
+ * the result.
+ * False when the operation is synchronous. Caller can proceed reading the result
+ * through {@link UsbOperationCallbackInternal#getStatus}
+ */
+ public boolean enableUsbData(String portName, boolean enable, long transactionId,
+ IUsbOperationInternal callback);
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java
new file mode 100644
index 000000000000..41f9faef99df
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 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.port;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.port.UsbPortHidl;
+import com.android.server.usb.hal.port.UsbPortAidl;
+import com.android.server.usb.UsbPortManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbPortHalInstance {
+
+ public static UsbPortHal getInstance(UsbPortManager portManager, IndentingPrintWriter pw) {
+
+ logAndPrint(Log.DEBUG, null, "Querying USB HAL version");
+ if (UsbPortHidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, null, "USB HAL HIDL present");
+ return new UsbPortHidl(portManager, pw);
+ }
+ if (UsbPortAidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, null, "USB HAL AIDL present");
+ return new UsbPortAidl(portManager, pw);
+ }
+
+ return null;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
new file mode 100644
index 000000000000..00d0d06705fc
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2021 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.port;
+
+import static android.hardware.usb.UsbManager.USB_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_0;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_1;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_2;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_3;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+import static com.android.server.usb.UsbPortManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.V1_0.IUsb;
+import android.hardware.usb.V1_0.PortRoleType;
+import android.hardware.usb.V1_0.Status;
+import android.hardware.usb.V1_1.PortStatus_1_1;
+import android.hardware.usb.V1_2.IUsbCallback;
+import android.hardware.usb.V1_0.PortRole;
+import android.hardware.usb.V1_2.PortStatus;
+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 android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbPortManager;
+import com.android.server.usb.hal.port.RawPortInfo;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbPortHidl implements UsbPortHal {
+ private static final String TAG = UsbPortHidl.class.getSimpleName();
+ // Cookie sent for usb hal death notification.
+ private static final int USB_HAL_DEATH_COOKIE = 1000;
+ // Proxy object for the usb hal daemon.
+ @GuardedBy("mLock")
+ private IUsb mProxy;
+ private UsbPortManager mPortManager;
+ public IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mLock = new Object();
+ // Callback when the UsbPort status is changed by the kernel.
+ private HALCallback mHALCallback;
+ private boolean mSystemReady;
+ // Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
+ private static boolean sUsbDataEnabled = true;
+
+ public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
+ int version;
+ synchronized(mLock) {
+ if (mProxy == null) {
+ throw new RemoteException("IUsb not initialized yet");
+ }
+ if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
+ version = USB_HAL_V1_3;
+ } else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
+ version = USB_HAL_V1_2;
+ } else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
+ version = USB_HAL_V1_1;
+ } else {
+ version = USB_HAL_V1_0;
+ }
+ logAndPrint(Log.INFO, null, "USB HAL HIDL version: " + version);
+ return version;
+ }
+ }
+
+ final class DeathRecipient implements IHwBinder.DeathRecipient {
+ public IndentingPrintWriter pw;
+
+ DeathRecipient(IndentingPrintWriter pw) {
+ this.pw = pw;
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_HAL_DEATH_COOKIE) {
+ logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
+ synchronized (mLock) {
+ mProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
+ connectToProxy(null);
+ }
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ if (mProxy != null) {
+ return;
+ }
+
+ try {
+ mProxy = IUsb.getService();
+ mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
+ mProxy.setCallback(mHALCallback);
+ mProxy.queryPortStatus();
+ //updateUsbHalVersion();
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb hal service not found."
+ + " Did the service fail to start?", e);
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
+ }
+ }
+ }
+
+ @Override
+ public void systemReady() {
+ mSystemReady = true;
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ IUsb.getService(true);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb hidl hal service not found.", e);
+ return false;
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "IUSB hal service present but failed to get service", e);
+ }
+
+ return true;
+ }
+
+ public UsbPortHidl(UsbPortManager portManager, IndentingPrintWriter pw) {
+ mPortManager = Objects.requireNonNull(portManager);
+ mPw = pw;
+ mHALCallback = new HALCallback(null, mPortManager, this);
+ try {
+ ServiceNotification serviceNotification = new ServiceNotification();
+
+ boolean ret = IServiceManager.getService()
+ .registerForNotifications("android.hardware.usb@1.0::IUsb",
+ "", serviceNotification);
+ if (!ret) {
+ logAndPrint(Log.ERROR, null,
+ "Failed to register service start notification");
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(null,
+ "Failed to register service start notification", e);
+ return;
+ }
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void enableContaminantPresenceDetection(String portName, boolean enable,
+ long transactionId) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+ return;
+ }
+
+ try {
+ // Oneway call into the hal. Use the castFrom method from HIDL.
+ android.hardware.usb.V1_2.IUsb proxy =
+ android.hardware.usb.V1_2.IUsb.castFrom(mProxy);
+ proxy.enableContaminantPresenceDetection(portName, enable);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set contaminant detection", e);
+ } catch (ClassCastException e) {
+ logAndPrintException(mPw, "Method only applicable to V1.2 or above implementation",
+ e);
+ }
+ }
+ }
+
+ @Override
+ public void queryPortStatus(long transactionId) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+ return;
+ }
+
+ try {
+ mProxy.queryPortStatus();
+ } catch (RemoteException e) {
+ logAndPrintException(null, "ServiceStart: Failed to query port status", e);
+ }
+ }
+ }
+
+ @Override
+ public void switchMode(String portId, @HalUsbPortMode int newMode, long transactionId) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.MODE;
+ newRole.role = newMode;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB port mode: "
+ + "portId=" + portId
+ + ", newMode=" + UsbPort.modeToString(newRole.role), e);
+ }
+ }
+ }
+
+ @Override
+ public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
+ long transactionId) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.POWER_ROLE;
+ newRole.role = newPowerRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newRole.role), e);
+ }
+ }
+ }
+
+ @Override
+ public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long transactionId) {
+ synchronized (mLock) {
+ if (mProxy == null) {
+ logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+ return;
+ }
+
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.DATA_ROLE;
+ newRole.role = newDataRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+ + ", newDataRole=" + UsbPort.dataRoleToString(newRole.role), e);
+ }
+ }
+ }
+
+ @Override
+ public boolean enableUsbData(String portName, boolean enable, long transactionId,
+ IUsbOperationInternal callback) {
+ int halVersion;
+
+ try {
+ halVersion = getUsbHalVersion();
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to query USB HAL version. opID:"
+ + transactionId
+ + " portId:" + portName, e);
+ return false;
+ }
+
+ if (halVersion != USB_HAL_V1_3) {
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ + transactionId
+ + " portId:" + portName, e);
+ }
+ return false;
+ }
+
+ boolean success;
+ synchronized(mLock) {
+ try {
+ android.hardware.usb.V1_3.IUsb proxy
+ = android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
+ success = proxy.enableUsbDataSignal(enable);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "Failed enableUsbData: opId:" + transactionId
+ + " portId=" + portName , e);
+ try {
+ callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException r) {
+ logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ + transactionId
+ + " portId:" + portName, r);
+ }
+ return false;
+ }
+ }
+ if (success) {
+ sUsbDataEnabled = enable;
+ }
+
+ try {
+ callback.onOperationComplete(success
+ ? USB_OPERATION_SUCCESS
+ : USB_OPERATION_ERROR_INTERNAL);
+ } catch (RemoteException r) {
+ logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+ + transactionId
+ + " portId:" + portName, r);
+ }
+ return false;
+ }
+
+ private static class HALCallback extends IUsbCallback.Stub {
+ public IndentingPrintWriter mPw;
+ public UsbPortManager mPortManager;
+ public UsbPortHidl mUsbPortHidl;
+
+ HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortHidl usbPortHidl) {
+ this.mPw = pw;
+ this.mPortManager = portManager;
+ this.mUsbPortHidl = usbPortHidl;
+ }
+
+ public void notifyPortStatusChange(
+ ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
+ if (!mUsbPortHidl.mSystemReady) {
+ return;
+ }
+
+ if (retval != Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+ for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
+ RawPortInfo temp = new RawPortInfo(current.portName,
+ current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+ current.currentMode,
+ current.canChangeMode, current.currentPowerRole,
+ current.canChangePowerRole,
+ current.currentDataRole, current.canChangeDataRole,
+ false, CONTAMINANT_PROTECTION_NONE,
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
+ newPortInfo.add(temp);
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
+ + current.portName);
+ }
+
+ mPortManager.updatePorts(newPortInfo);
+ }
+
+
+ public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
+ int retval) {
+ if (!mUsbPortHidl.mSystemReady) {
+ return;
+ }
+
+ if (retval != Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+ int numStatus = currentPortStatus.size();
+ for (int i = 0; i < numStatus; i++) {
+ PortStatus_1_1 current = currentPortStatus.get(i);
+ RawPortInfo temp = new RawPortInfo(current.status.portName,
+ current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+ current.currentMode,
+ current.status.canChangeMode, current.status.currentPowerRole,
+ current.status.canChangePowerRole,
+ current.status.currentDataRole, current.status.canChangeDataRole,
+ false, CONTAMINANT_PROTECTION_NONE,
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
+ newPortInfo.add(temp);
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
+ + current.status.portName);
+ }
+ mPortManager.updatePorts(newPortInfo);
+ }
+
+ public void notifyPortStatusChange_1_2(
+ ArrayList<PortStatus> currentPortStatus, int retval) {
+ if (!mUsbPortHidl.mSystemReady) {
+ return;
+ }
+
+ if (retval != Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+ int numStatus = currentPortStatus.size();
+ for (int i = 0; i < numStatus; i++) {
+ PortStatus current = currentPortStatus.get(i);
+ RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
+ current.status_1_1.supportedModes,
+ current.supportedContaminantProtectionModes,
+ current.status_1_1.currentMode,
+ current.status_1_1.status.canChangeMode,
+ current.status_1_1.status.currentPowerRole,
+ current.status_1_1.status.canChangePowerRole,
+ current.status_1_1.status.currentDataRole,
+ current.status_1_1.status.canChangeDataRole,
+ current.supportsEnableContaminantPresenceProtection,
+ current.contaminantProtectionStatus,
+ current.supportsEnableContaminantPresenceDetection,
+ current.contaminantDetectionStatus,
+ sUsbDataEnabled);
+ newPortInfo.add(temp);
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
+ + current.status_1_1.status.portName);
+ }
+ mPortManager.updatePorts(newPortInfo);
+ }
+
+ public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
+ if (retval == Status.SUCCESS) {
+ UsbPortManager.logAndPrint(Log.INFO, mPw, portName + " role switch successful");
+ } else {
+ UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed");
+ }
+ }
+ }
+}
diff --git a/telephony/java/Android.bp b/telephony/java/Android.bp
index 3941b300206f..76a420c430d1 100644
--- a/telephony/java/Android.bp
+++ b/telephony/java/Android.bp
@@ -13,6 +13,15 @@ filegroup {
srcs: [
"**/*.java",
"**/*.aidl",
+ ":statslog-telephony-java-gen",
],
visibility: ["//frameworks/base"],
}
+
+genrule {
+ name: "statslog-telephony-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyStatsLog",
+ out: ["com/android/internal/telephony/TelephonyStatsLog.java"],
+}
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index ffdb23f98fb8..f47cf3384791 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_ANOMALY_DETECTED;
+
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.content.Context;
@@ -24,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.ParcelUuid;
+import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;
@@ -83,6 +86,12 @@ public final class AnomalyReporter {
return;
}
+ TelephonyStatsLog.write(
+ TELEPHONY_ANOMALY_DETECTED,
+ 0, // TODO: carrier id needs to be populated
+ eventId.getLeastSignificantBits(),
+ eventId.getMostSignificantBits());
+
// If this event has already occurred, skip sending intents for it; regardless log its
// invocation here.
Integer count = sEvents.containsKey(eventId) ? sEvents.get(eventId) + 1 : 1;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b4825153bf0a..56988ae0944d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9051,6 +9051,7 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
+ networkTypeBitmask = checkNetworkTypeBitmask(networkTypeBitmask);
return telephony.setAllowedNetworkTypesForReason(getSubId(),
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, networkTypeBitmask);
}
@@ -9061,6 +9062,20 @@ public class TelephonyManager {
}
/**
+ * If {@link #NETWORK_TYPE_BITMASK_LTE_CA} bit is set, convert it to NETWORK_TYPE_BITMASK_LTE.
+ *
+ * @param networkTypeBitmask The networkTypeBitmask being checked
+ * @return The checked/converted networkTypeBitmask
+ */
+ private long checkNetworkTypeBitmask(@NetworkTypeBitMask long networkTypeBitmask) {
+ if ((networkTypeBitmask & NETWORK_TYPE_BITMASK_LTE_CA) != 0) {
+ networkTypeBitmask ^= NETWORK_TYPE_BITMASK_LTE_CA;
+ networkTypeBitmask |= NETWORK_TYPE_BITMASK_LTE;
+ }
+ return networkTypeBitmask;
+ }
+
+ /**
* Set the allowed network types of the device. This is for carrier or privileged apps to
* enable/disable certain network types on the device. The user preferred network types should
* be set through {@link #setPreferredNetworkTypeBitmask}.
@@ -9086,6 +9101,7 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
+ allowedNetworkTypes = checkNetworkTypeBitmask(allowedNetworkTypes);
return telephony.setAllowedNetworkTypesForReason(getSubId(),
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER, allowedNetworkTypes);
}
@@ -9171,6 +9187,7 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
+ allowedNetworkTypes = checkNetworkTypeBitmask(allowedNetworkTypes);
telephony.setAllowedNetworkTypesForReason(getSubId(), reason,
allowedNetworkTypes);
} else {
@@ -13429,7 +13446,11 @@ public class TelephonyManager {
*/
public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1));
/**
+ * NOT USED; this bitmask is exposed accidentally, will be deprecated in U.
+ * If used, will be converted to {@link #NETWORK_TYPE_BITMASK_LTE}.
* network type bitmask indicating the support of radio tech LTE CA (carrier aggregation).
+ *
+ * @see #NETWORK_TYPE_BITMASK_LTE
*/
public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1));
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 7ea4ab13961d..0aca2939cee0 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@ namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
static const auto sDevelopmentSdkCodeNames =
- std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu"});
+ std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},
diff --git a/tools/bit/adb.cpp b/tools/bit/adb.cpp
index f521a63255e1..201028ba900a 100644
--- a/tools/bit/adb.cpp
+++ b/tools/bit/adb.cpp
@@ -73,7 +73,7 @@ string
get_system_property(const string& name, int* err)
{
Command cmd("adb");
- cmd.AddArg("shell");
+ cmd.AddArg("exec-out");
cmd.AddArg("getprop");
cmd.AddArg(name);
@@ -278,7 +278,7 @@ run_instrumentation_test(const string& packageName, const string& runner, const
InstrumentationCallbacks* callbacks)
{
Command cmd("adb");
- cmd.AddArg("shell");
+ cmd.AddArg("exec-out");
cmd.AddArg("am");
cmd.AddArg("instrument");
cmd.AddArg("-w");
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index fd184f50091a..0d48070fd0c6 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -52,24 +52,22 @@ struct Target {
int testPassCount;
int testFailCount;
+ int testIgnoreCount;
int unknownFailureCount; // unknown failure == "Process crashed", etc.
- bool actionsWithNoTests;
Target(bool b, bool i, bool t, const string& p);
};
Target::Target(bool b, bool i, bool t, const string& p)
- :build(b),
- install(i),
- test(t),
- pattern(p),
- testActionCount(0),
- testPassCount(0),
- testFailCount(0),
- unknownFailureCount(0),
- actionsWithNoTests(false)
-{
-}
+ : build(b),
+ install(i),
+ test(t),
+ pattern(p),
+ testActionCount(0),
+ testPassCount(0),
+ testFailCount(0),
+ testIgnoreCount(0),
+ unknownFailureCount(0) {}
/**
* Command line options.
@@ -188,13 +186,12 @@ struct TestAction {
// The number of tests that failed
int failCount;
+
+ // The number of tests that were ignored (because of @Ignore)
+ int ignoreCount;
};
-TestAction::TestAction()
- :passCount(0),
- failCount(0)
-{
-}
+TestAction::TestAction() : passCount(0), failCount(0), ignoreCount(0) {}
/**
* Record for an activity that is going to be launched.
@@ -278,7 +275,7 @@ TestResults::OnTestStatus(TestStatus& status)
line << " of " << testCount;
}
}
- line << ": " << m_currentAction->target->name << ':' << className << "\\#" << testName;
+ line << ": " << m_currentAction->target->name << ':' << className << "#" << testName;
print_one_line("%s", line.str().c_str());
} else if ((resultCode == -1) || (resultCode == -2)) {
// test failed
@@ -286,9 +283,9 @@ TestResults::OnTestStatus(TestStatus& status)
// all as "failures".
m_currentAction->failCount++;
m_currentAction->target->testFailCount++;
- printf("%s\n%sFailed: %s:%s\\#%s%s\n", g_escapeClearLine, g_escapeRedBold,
- m_currentAction->target->name.c_str(), className.c_str(),
- testName.c_str(), g_escapeEndColor);
+ printf("%s\n%sFailed: %s:%s#%s%s\n", g_escapeClearLine, g_escapeRedBold,
+ m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
+ g_escapeEndColor);
bool stackFound;
string stack = get_bundle_string(results, &stackFound, "stack", NULL);
@@ -300,6 +297,13 @@ TestResults::OnTestStatus(TestStatus& status)
} else if (stackFound) {
printf("%s\n", stack.c_str());
}
+ } else if (resultCode == -3) {
+ // test ignored
+ m_currentAction->ignoreCount++;
+ m_currentAction->target->testIgnoreCount++;
+ printf("%s\n%sIgnored: %s:%s#%s%s\n", g_escapeClearLine, g_escapeYellowBold,
+ m_currentAction->target->name.c_str(), className.c_str(), testName.c_str(),
+ g_escapeEndColor);
}
}
@@ -403,11 +407,14 @@ print_usage(FILE* out) {
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs all the\n");
fprintf(out, " tests in the ProtoOutputStreamBoolTest class.\n");
fprintf(out, "\n");
- fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite\n");
+ fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite\n");
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
fprintf(out, " test method on that class.\n");
fprintf(out, "\n");
- fprintf(out, " bit CtsProtoTestCases:.ProtoOutputStreamBoolTest\\#testWrite,.ProtoOutputStreamBoolTest\\#testRepeated\n");
+ fprintf(out,
+ " bit "
+ "CtsProtoTestCases:.ProtoOutputStreamBoolTest#testWrite,.ProtoOutputStreamBoolTest#"
+ "testRepeated\n");
fprintf(out, " Builds and installs CtsProtoTestCases.apk, and runs the testWrite\n");
fprintf(out, " and testRepeated test methods on that class.\n");
fprintf(out, "\n");
@@ -450,6 +457,35 @@ print_usage(FILE* out) {
fprintf(out, "\n");
}
+/**
+ * Prints a possibly color-coded summary of test results. Example output:
+ *
+ * "34 passed, 0 failed, 1 ignored\n"
+ */
+static void print_results(int passed, int failed, int ignored) {
+ char const* nothing = "";
+ char const* cp = nothing;
+ char const* cf = nothing;
+ char const* ci = nothing;
+
+ if (failed > 0) {
+ cf = g_escapeRedBold;
+ } else if (passed > 0 || ignored > 0) {
+ cp = passed > 0 ? g_escapeGreenBold : nothing;
+ ci = ignored > 0 ? g_escapeYellowBold : nothing;
+ } else {
+ cp = g_escapeYellowBold;
+ cf = g_escapeYellowBold;
+ }
+
+ if (ignored > 0) {
+ printf("%s%d passed%s, %s%d failed%s, %s%d ignored%s\n", cp, passed, g_escapeEndColor, cf,
+ failed, g_escapeEndColor, ci, ignored, g_escapeEndColor);
+ } else {
+ printf("%s%d passed%s, %s%d failed%s\n", cp, passed, g_escapeEndColor, cf, failed,
+ g_escapeEndColor);
+ }
+}
/**
* Sets the appropriate flag* variables. If there is a problem with the
@@ -812,7 +848,7 @@ run_phases(vector<Target*> targets, const Options& options)
// Stop & Sync
if (!options.noRestart) {
- err = run_adb("shell", "stop", NULL);
+ err = run_adb("exec-out", "stop", NULL);
check_error(err);
}
err = run_adb("remount", NULL);
@@ -831,9 +867,9 @@ run_phases(vector<Target*> targets, const Options& options)
} else {
print_status("Restarting the runtime");
- err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
+ err = run_adb("exec-out", "setprop", "sys.boot_completed", "0", NULL);
check_error(err);
- err = run_adb("shell", "start", NULL);
+ err = run_adb("exec-out", "start", NULL);
check_error(err);
}
@@ -846,7 +882,7 @@ run_phases(vector<Target*> targets, const Options& options)
sleep(2);
}
sleep(1);
- err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
+ err = run_adb("exec-out", "wm", "dismiss-keyguard", NULL);
check_error(err);
}
}
@@ -863,7 +899,7 @@ run_phases(vector<Target*> targets, const Options& options)
continue;
}
// TODO: if (!apk.file.fileInfo.exists || apk.file.HasChanged())
- err = run_adb("shell", "mkdir", "-p", dir.c_str(), NULL);
+ err = run_adb("exec-out", "mkdir", "-p", dir.c_str(), NULL);
check_error(err);
err = run_adb("push", pushed.file.filename.c_str(), pushed.dest.c_str(), NULL);
check_error(err);
@@ -945,9 +981,9 @@ run_phases(vector<Target*> targets, const Options& options)
}
}
if (runAll) {
- err = run_adb("shell", installedPath.c_str(), NULL);
+ err = run_adb("exec-out", installedPath.c_str(), NULL);
} else {
- err = run_adb("shell", installedPath.c_str(), filterArg.c_str(), NULL);
+ err = run_adb("exec-out", installedPath.c_str(), filterArg.c_str(), NULL);
}
if (err == 0) {
target->testPassCount++;
@@ -1035,22 +1071,10 @@ run_phases(vector<Target*> targets, const Options& options)
err = run_instrumentation_test(action.packageName, action.runner, action.className,
&testResults);
check_error(err);
- if (action.passCount == 0 && action.failCount == 0) {
- action.target->actionsWithNoTests = true;
- }
int total = action.passCount + action.failCount;
printf("%sRan %d test%s for %s. ", g_escapeClearLine,
total, total > 1 ? "s" : "", action.target->name.c_str());
- if (action.passCount == 0 && action.failCount == 0) {
- printf("%s%d passed, %d failed%s\n", g_escapeYellowBold, action.passCount,
- action.failCount, g_escapeEndColor);
- } else if (action.failCount > 0) {
- printf("%d passed, %s%d failed%s\n", action.passCount, g_escapeRedBold,
- action.failCount, g_escapeEndColor);
- } else {
- printf("%s%d passed%s, %d failed\n", g_escapeGreenBold, action.passCount,
- g_escapeEndColor, action.failCount);
- }
+ print_results(action.passCount, action.failCount, action.ignoreCount);
if (!testResults.IsSuccess()) {
printf("\n%sTest didn't finish successfully: %s%s\n", g_escapeRedBold,
testResults.GetErrorMessage().c_str(), g_escapeEndColor);
@@ -1073,7 +1097,7 @@ run_phases(vector<Target*> targets, const Options& options)
const ActivityAction& action = activityActions[0];
string componentName = action.packageName + "/" + action.className;
- err = run_adb("shell", "am", "start", componentName.c_str(), NULL);
+ err = run_adb("exec-out", "am", "start", componentName.c_str(), NULL);
check_error(err);
}
@@ -1147,17 +1171,11 @@ run_phases(vector<Target*> targets, const Options& options)
printf(" %sUnknown failure, see above message.%s\n",
g_escapeRedBold, g_escapeEndColor);
hasErrors = true;
- } else if (target->actionsWithNoTests) {
- printf(" %s%d passed, %d failed%s\n", g_escapeYellowBold,
- target->testPassCount, target->testFailCount, g_escapeEndColor);
- hasErrors = true;
- } else if (target->testFailCount > 0) {
- printf(" %d passed, %s%d failed%s\n", target->testPassCount,
- g_escapeRedBold, target->testFailCount, g_escapeEndColor);
- hasErrors = true;
} else {
- printf(" %s%d passed%s, %d failed\n", g_escapeGreenBold,
- target->testPassCount, g_escapeEndColor, target->testFailCount);
+ printf(" %s%s ", target->name.c_str(),
+ padding.c_str() + target->name.length());
+ print_results(target->testPassCount, target->testFailCount,
+ target->testIgnoreCount);
}
}
}