Merge "Dump mNetworkToIfaces in NetworkPolicyManagerService"
diff --git a/Android.bp b/Android.bp
index b0a1f93..287f271 100644
--- a/Android.bp
+++ b/Android.bp
@@ -298,6 +298,7 @@
"contacts-provider-platform-compat-config",
],
libs: [
+ "androidx.annotation_annotation",
"app-compat-annotations",
"ext",
"framework-updatable-stubs-module_libs_api",
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index 2182f0b..23464f8 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -43,12 +43,13 @@
"apct-perftests-resources-manager-apps",
"apct-perftests-utils",
"collector-device-lib",
+ "core-tests-support",
"guava",
],
libs: ["android.test.base"],
- java_resources: [ ":GoogleFontDancingScript", ],
+ java_resources: [":GoogleFontDancingScript"],
data: [":perfetto_artifacts"],
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 03c9d43..adcd571 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -158,14 +158,6 @@
}
@Test
- public void timeNewSimpleDateFormat() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- new SimpleDateFormat();
- }
- }
-
- @Test
public void timeClonedSimpleDateFormat() {
SimpleDateFormat sdf = new SimpleDateFormat();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
new file mode 100644
index 0000000..694d609
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 libcore.java.security.TestKeyStore;
+import libcore.javax.net.ssl.TestSSLContext;
+import libcore.javax.net.ssl.TestSSLSocketPair;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.net.ssl.SSLSocket;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SSLLoopbackPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void time() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TestSSLContext context =
+ TestSSLContext.create(TestKeyStore.getClient(), TestKeyStore.getServer());
+ SSLSocket[] sockets = TestSSLSocketPair.connect(context, null, null);
+ context.close();
+ sockets[0].close();
+ sockets[1].close();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
new file mode 100644
index 0000000..bdbbcb0
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 javax.net.ssl.SSLSocketFactory;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SSLSocketFactoryPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void time() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ SSLSocketFactory.getDefault();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
new file mode 100644
index 0000000..42dc581
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public final class SchemePrefixPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ enum Strategy {
+ JAVA() {
+ @Override
+ String execute(String spec) {
+ int colon = spec.indexOf(':');
+
+ if (colon < 1) {
+ return null;
+ }
+
+ for (int i = 0; i < colon; i++) {
+ char c = spec.charAt(i);
+ if (!isValidSchemeChar(i, c)) {
+ return null;
+ }
+ }
+
+ return spec.substring(0, colon).toLowerCase(Locale.US);
+ }
+
+ private boolean isValidSchemeChar(int index, char c) {
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ return true;
+ }
+ if (index > 0 && ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')) {
+ return true;
+ }
+ return false;
+ }
+ },
+
+ REGEX() {
+ private final Pattern mPattern = Pattern.compile("^([a-zA-Z][a-zA-Z0-9+\\-.]*):");
+
+ @Override
+ String execute(String spec) {
+ Matcher matcher = mPattern.matcher(spec);
+ if (matcher.find()) {
+ return matcher.group(1).toLowerCase(Locale.US);
+ } else {
+ return null;
+ }
+ }
+ };
+
+ abstract String execute(String spec);
+ }
+
+ @Parameters(name = "mStrategy={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{Strategy.REGEX}, {Strategy.JAVA}});
+ }
+
+ @Parameterized.Parameter(0)
+ public Strategy mStrategy;
+
+ @Test
+ public void timeSchemePrefix() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStrategy.execute("http://android.com");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
new file mode 100644
index 0000000..1ec22d2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
@@ -0,0 +1,292 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SerializationPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static byte[] bytes(Object o) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ ObjectOutputStream out = new ObjectOutputStream(baos);
+ out.writeObject(o);
+ out.close();
+ return baos.toByteArray();
+ }
+
+ @Test
+ public void timeReadIntArray() throws Exception {
+ int[] intArray = new int[256];
+ readSingleObject(intArray);
+ }
+
+ @Test
+ public void timeWriteIntArray() throws Exception {
+ int[] intArray = new int[256];
+ writeSingleObject(intArray);
+ }
+
+ @Test
+ public void timeReadArrayListInteger() throws Exception {
+ ArrayList<Integer> object = new ArrayList<Integer>();
+ for (int i = 0; i < 256; ++i) {
+ object.add(i);
+ }
+ readSingleObject(object);
+ }
+
+ @Test
+ public void timeWriteArrayListInteger() throws Exception {
+ ArrayList<Integer> object = new ArrayList<Integer>();
+ for (int i = 0; i < 256; ++i) {
+ object.add(i);
+ }
+ writeSingleObject(object);
+ }
+
+ @Test
+ public void timeReadString() throws Exception {
+ readSingleObject("hello");
+ }
+
+ @Test
+ public void timeReadObjectStreamClass() throws Exception {
+ // A special case because serialization itself requires this class.
+ // (This should really be a unit test.)
+ ObjectStreamClass osc = ObjectStreamClass.lookup(String.class);
+ readSingleObject(osc);
+ }
+
+ @Test
+ public void timeWriteString() throws Exception {
+ // String is a special case that avoids JNI.
+ writeSingleObject("hello");
+ }
+
+ @Test
+ public void timeWriteObjectStreamClass() throws Exception {
+ // A special case because serialization itself requires this class.
+ // (This should really be a unit test.)
+ ObjectStreamClass osc = ObjectStreamClass.lookup(String.class);
+ writeSingleObject(osc);
+ }
+
+ // This is
+ //
+ // @Testa baseline for the others.
+ public void timeWriteNoObjects() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ ObjectOutputStream out = new ObjectOutputStream(baos);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ out.reset();
+ baos.reset();
+ }
+ out.close();
+ }
+
+ private void readSingleObject(Object object) throws Exception {
+ byte[] bytes = bytes(object);
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ObjectInputStream in = new ObjectInputStream(bais);
+ in.readObject();
+ in.close();
+ bais.reset();
+ }
+ }
+
+ private void writeSingleObject(Object o) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ ObjectOutputStream out = new ObjectOutputStream(baos);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ out.writeObject(o);
+ out.reset();
+ baos.reset();
+ }
+ out.close();
+ }
+
+ @Test
+ public void timeWriteEveryKindOfField() throws Exception {
+ writeSingleObject(new LittleBitOfEverything());
+ }
+
+ @Test
+ public void timeWriteSerializableBoolean() throws Exception {
+ writeSingleObject(new SerializableBoolean());
+ }
+
+ @Test
+ public void timeWriteSerializableByte() throws Exception {
+ writeSingleObject(new SerializableByte());
+ }
+
+ @Test
+ public void timeWriteSerializableChar() throws Exception {
+ writeSingleObject(new SerializableChar());
+ }
+
+ @Test
+ public void timeWriteSerializableDouble() throws Exception {
+ writeSingleObject(new SerializableDouble());
+ }
+
+ @Test
+ public void timeWriteSerializableFloat() throws Exception {
+ writeSingleObject(new SerializableFloat());
+ }
+
+ @Test
+ public void timeWriteSerializableInt() throws Exception {
+ writeSingleObject(new SerializableInt());
+ }
+
+ @Test
+ public void timeWriteSerializableLong() throws Exception {
+ writeSingleObject(new SerializableLong());
+ }
+
+ @Test
+ public void timeWriteSerializableShort() throws Exception {
+ writeSingleObject(new SerializableShort());
+ }
+
+ @Test
+ public void timeWriteSerializableReference() throws Exception {
+ writeSingleObject(new SerializableReference());
+ }
+
+ @Test
+ public void timeReadEveryKindOfField() throws Exception {
+ readSingleObject(new LittleBitOfEverything());
+ }
+
+ @Test
+ public void timeReadSerializableBoolean() throws Exception {
+ readSingleObject(new SerializableBoolean());
+ }
+
+ @Test
+ public void timeReadSerializableByte() throws Exception {
+ readSingleObject(new SerializableByte());
+ }
+
+ @Test
+ public void timeReadSerializableChar() throws Exception {
+ readSingleObject(new SerializableChar());
+ }
+
+ @Test
+ public void timeReadSerializableDouble() throws Exception {
+ readSingleObject(new SerializableDouble());
+ }
+
+ @Test
+ public void timeReadSerializableFloat() throws Exception {
+ readSingleObject(new SerializableFloat());
+ }
+
+ @Test
+ public void timeReadSerializableInt() throws Exception {
+ readSingleObject(new SerializableInt());
+ }
+
+ @Test
+ public void timeReadSerializableLong() throws Exception {
+ readSingleObject(new SerializableLong());
+ }
+
+ @Test
+ public void timeReadSerializableShort() throws Exception {
+ readSingleObject(new SerializableShort());
+ }
+
+ @Test
+ public void timeReadSerializableReference() throws Exception {
+ readSingleObject(new SerializableReference());
+ }
+
+ public static class SerializableBoolean implements Serializable {
+ boolean mZ;
+ }
+
+ public static class SerializableByte implements Serializable {
+ byte mB;
+ }
+
+ public static class SerializableChar implements Serializable {
+ char mC;
+ }
+
+ public static class SerializableDouble implements Serializable {
+ double mD;
+ }
+
+ public static class SerializableFloat implements Serializable {
+ float mF;
+ }
+
+ public static class SerializableInt implements Serializable {
+ int mI;
+ }
+
+ public static class SerializableLong implements Serializable {
+ long mJ;
+ }
+
+ public static class SerializableShort implements Serializable {
+ short mS;
+ }
+
+ public static class SerializableReference implements Serializable {
+ Object mL;
+ }
+
+ public static class LittleBitOfEverything implements Serializable {
+ boolean mZ;
+ byte mB;
+ char mC;
+ double mD;
+ float mF;
+ int mI;
+ long mJ;
+ short mS;
+ Object mL;
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
new file mode 100644
index 0000000..96e7cb2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Tests RSA and DSA mSignature creation and verification. */
+@RunWith(Parameterized.class)
+@LargeTest
+public class SignaturePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mAlgorithm={0}, mImplementation={1}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {Algorithm.MD5WithRSA, Implementation.OpenSSL},
+ {Algorithm.SHA1WithRSA, Implementation.OpenSSL},
+ {Algorithm.SHA256WithRSA, Implementation.OpenSSL},
+ {Algorithm.SHA384WithRSA, Implementation.OpenSSL},
+ {Algorithm.SHA512WithRSA, Implementation.OpenSSL},
+ {Algorithm.SHA1withDSA, Implementation.BouncyCastle}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public Algorithm mAlgorithm;
+
+ @Parameterized.Parameter(1)
+ public Implementation mImplementation;
+
+ private static final int DATA_SIZE = 8192;
+ private static final byte[] DATA = new byte[DATA_SIZE];
+
+ static {
+ for (int i = 0; i < DATA_SIZE; i++) {
+ DATA[i] = (byte) i;
+ }
+ }
+
+ public enum Algorithm {
+ MD5WithRSA,
+ SHA1WithRSA,
+ SHA256WithRSA,
+ SHA384WithRSA,
+ SHA512WithRSA,
+ SHA1withDSA
+ };
+
+ public enum Implementation {
+ OpenSSL,
+ BouncyCastle
+ };
+
+ // Key generation and signing aren't part of the benchmark for verification
+ // so cache the results
+ private static Map<String, KeyPair> sKeyPairs = new HashMap<String, KeyPair>();
+ private static Map<String, byte[]> sSignatures = new HashMap<String, byte[]>();
+
+ private String mSignatureAlgorithm;
+ private byte[] mSignature;
+ private PrivateKey mPrivateKey;
+ private PublicKey mPublicKey;
+
+ @Before
+ public void setUp() throws Exception {
+ this.mSignatureAlgorithm = mAlgorithm.toString();
+
+ String keyAlgorithm =
+ mSignatureAlgorithm.substring(
+ mSignatureAlgorithm.length() - 3, mSignatureAlgorithm.length());
+ KeyPair keyPair = sKeyPairs.get(keyAlgorithm);
+ if (keyPair == null) {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(keyAlgorithm);
+ keyPair = generator.generateKeyPair();
+ sKeyPairs.put(keyAlgorithm, keyPair);
+ }
+ this.mPrivateKey = keyPair.getPrivate();
+ this.mPublicKey = keyPair.getPublic();
+
+ this.mSignature = sSignatures.get(mSignatureAlgorithm);
+ if (this.mSignature == null) {
+ Signature signer = Signature.getInstance(mSignatureAlgorithm);
+ signer.initSign(keyPair.getPrivate());
+ signer.update(DATA);
+ this.mSignature = signer.sign();
+ sSignatures.put(mSignatureAlgorithm, mSignature);
+ }
+ }
+
+ @Test
+ public void timeSign() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Signature signer;
+ switch (mImplementation) {
+ case OpenSSL:
+ signer = Signature.getInstance(mSignatureAlgorithm, "AndroidOpenSSL");
+ break;
+ case BouncyCastle:
+ signer = Signature.getInstance(mSignatureAlgorithm, "BC");
+ break;
+ default:
+ throw new RuntimeException(mImplementation.toString());
+ }
+ signer.initSign(mPrivateKey);
+ signer.update(DATA);
+ signer.sign();
+ }
+ }
+
+ @Test
+ public void timeVerify() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Signature verifier;
+ switch (mImplementation) {
+ case OpenSSL:
+ verifier = Signature.getInstance(mSignatureAlgorithm, "AndroidOpenSSL");
+ break;
+ case BouncyCastle:
+ verifier = Signature.getInstance(mSignatureAlgorithm, "BC");
+ break;
+ default:
+ throw new RuntimeException(mImplementation.toString());
+ }
+ verifier.initVerify(mPublicKey);
+ verifier.update(DATA);
+ verifier.verify(mSignature);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
new file mode 100644
index 0000000..c25b0ce
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Benchmark for java.text.SimpleDateFormat. This tests common formatting, parsing and creation
+ * operations with a specific focus on TimeZone handling.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SimpleDateFormatPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void time_createFormatWithTimeZone() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
+ }
+ }
+
+ @Test
+ public void time_parseWithTimeZoneShort() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.parse("2000.01.01 PST");
+ }
+ }
+
+ @Test
+ public void time_parseWithTimeZoneLong() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.parse("2000.01.01 Pacific Standard Time");
+ }
+ }
+
+ @Test
+ public void time_parseWithoutTimeZone() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.parse("2000.01.01");
+ }
+ }
+
+ @Test
+ public void time_createAndParseWithTimeZoneShort() throws ParseException {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
+ sdf.parse("2000.01.01 PST");
+ }
+ }
+
+ @Test
+ public void time_createAndParseWithTimeZoneLong() throws ParseException {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
+ sdf.parse("2000.01.01 Pacific Standard Time");
+ }
+ }
+
+ @Test
+ public void time_formatWithTimeZoneShort() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.format(new Date());
+ }
+ }
+
+ @Test
+ public void time_formatWithTimeZoneLong() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ sdf.format(new Date());
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
new file mode 100644
index 0000000..eeccb5b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
@@ -0,0 +1,510 @@
+/*
+ * 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;
+
+/**
+ * Many of these tests are bogus in that the cost will vary wildly depending on inputs. For _my_
+ * current purposes, that's okay. But beware!
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StrictMathPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final double mDouble = 1.2;
+ private final float mFloat = 1.2f;
+ private final int mInt = 1;
+ private final long mLong = 1L;
+
+ /* Values for full line coverage of ceiling function */
+ private static final double[] CEIL_DOUBLES =
+ new double[] {
+ 3245817.2018463886,
+ 1418139.083668501,
+ 3.572936802189103E15,
+ -4.7828929737254625E249,
+ 213596.58636369856,
+ 6.891928421440976E-96,
+ -7.9318566885477E-36,
+ -1.9610339084804148E15,
+ -4.696725715628246E10,
+ 3742491.296880909,
+ 7.140274745333553E11
+ };
+
+ /* Values for full line coverage of floor function */
+ private static final double[] FLOOR_DOUBLES =
+ new double[] {
+ 7.140274745333553E11,
+ 3742491.296880909,
+ -4.696725715628246E10,
+ -1.9610339084804148E15,
+ 7.049948629370372E-56,
+ -7.702933170334643E-16,
+ -1.99657681810579,
+ -1.1659287182288336E236,
+ 4.085518816513057E15,
+ -1500948.440658056,
+ -2.2316479921415575E7
+ };
+
+ @Test
+ public void timeAbsD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.abs(mDouble);
+ }
+ }
+
+ @Test
+ public void timeAbsF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.abs(mFloat);
+ }
+ }
+
+ @Test
+ public void timeAbsI() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.abs(mInt);
+ }
+ }
+
+ @Test
+ public void timeAbsL() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.abs(mLong);
+ }
+ }
+
+ @Test
+ public void timeAcos() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.acos(mDouble);
+ }
+ }
+
+ @Test
+ public void timeAsin() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.asin(mDouble);
+ }
+ }
+
+ @Test
+ public void timeAtan() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.atan(mDouble);
+ }
+ }
+
+ @Test
+ public void timeAtan2() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.atan2(3, 4);
+ }
+ }
+
+ @Test
+ public void timeCbrt() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.cbrt(mDouble);
+ }
+ }
+
+ @Test
+ public void timeCeilOverInterestingValues() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < CEIL_DOUBLES.length; ++i) {
+ StrictMath.ceil(CEIL_DOUBLES[i]);
+ }
+ }
+ }
+
+ @Test
+ public void timeCopySignD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.copySign(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeCopySignF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.copySign(mFloat, mFloat);
+ }
+ }
+
+ @Test
+ public void timeCos() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.cos(mDouble);
+ }
+ }
+
+ @Test
+ public void timeCosh() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.cosh(mDouble);
+ }
+ }
+
+ @Test
+ public void timeExp() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.exp(mDouble);
+ }
+ }
+
+ @Test
+ public void timeExpm1() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.expm1(mDouble);
+ }
+ }
+
+ @Test
+ public void timeFloorOverInterestingValues() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < FLOOR_DOUBLES.length; ++i) {
+ StrictMath.floor(FLOOR_DOUBLES[i]);
+ }
+ }
+ }
+
+ @Test
+ public void timeGetExponentD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.getExponent(mDouble);
+ }
+ }
+
+ @Test
+ public void timeGetExponentF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.getExponent(mFloat);
+ }
+ }
+
+ @Test
+ public void timeHypot() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.hypot(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeIEEEremainder() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.IEEEremainder(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeLog() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.log(mDouble);
+ }
+ }
+
+ @Test
+ public void timeLog10() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.log10(mDouble);
+ }
+ }
+
+ @Test
+ public void timeLog1p() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.log1p(mDouble);
+ }
+ }
+
+ @Test
+ public void timeMaxD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.max(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeMaxF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.max(mFloat, mFloat);
+ }
+ }
+
+ @Test
+ public void timeMaxI() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.max(mInt, mInt);
+ }
+ }
+
+ @Test
+ public void timeMaxL() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.max(mLong, mLong);
+ }
+ }
+
+ @Test
+ public void timeMinD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.min(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeMinF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.min(mFloat, mFloat);
+ }
+ }
+
+ @Test
+ public void timeMinI() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.min(mInt, mInt);
+ }
+ }
+
+ @Test
+ public void timeMinL() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.min(mLong, mLong);
+ }
+ }
+
+ @Test
+ public void timeNextAfterD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.nextAfter(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeNextAfterF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.nextAfter(mFloat, mFloat);
+ }
+ }
+
+ @Test
+ public void timeNextUpD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.nextUp(mDouble);
+ }
+ }
+
+ @Test
+ public void timeNextUpF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.nextUp(mFloat);
+ }
+ }
+
+ @Test
+ public void timePow() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.pow(mDouble, mDouble);
+ }
+ }
+
+ @Test
+ public void timeRandom() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.random();
+ }
+ }
+
+ @Test
+ public void timeRint() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.rint(mDouble);
+ }
+ }
+
+ @Test
+ public void timeRoundD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.round(mDouble);
+ }
+ }
+
+ @Test
+ public void timeRoundF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.round(mFloat);
+ }
+ }
+
+ @Test
+ public void timeScalbD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.scalb(mDouble, 5);
+ }
+ }
+
+ @Test
+ public void timeScalbF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.scalb(mFloat, 5);
+ }
+ }
+
+ @Test
+ public void timeSignumD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.signum(mDouble);
+ }
+ }
+
+ @Test
+ public void timeSignumF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.signum(mFloat);
+ }
+ }
+
+ @Test
+ public void timeSin() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.sin(mDouble);
+ }
+ }
+
+ @Test
+ public void timeSinh() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.sinh(mDouble);
+ }
+ }
+
+ @Test
+ public void timeSqrt() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.sqrt(mDouble);
+ }
+ }
+
+ @Test
+ public void timeTan() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.tan(mDouble);
+ }
+ }
+
+ @Test
+ public void timeTanh() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.tanh(mDouble);
+ }
+ }
+
+ @Test
+ public void timeToDegrees() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.toDegrees(mDouble);
+ }
+ }
+
+ @Test
+ public void timeToRadians() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.toRadians(mDouble);
+ }
+ }
+
+ @Test
+ public void timeUlpD() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.ulp(mDouble);
+ }
+ }
+
+ @Test
+ public void timeUlpF() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StrictMath.ulp(mFloat);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
new file mode 100644
index 0000000..34fb88b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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;
+
+/** Tests the performance of various StringBuilder methods. */
+@RunWith(Parameterized.class)
+@LargeTest
+public class StringBuilderPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mLength={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{1}, {10}, {100}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int mLength;
+
+ @Test
+ public void timeAppendBoolean() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(true);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendChar() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append('c');
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendCharArray() {
+ char[] chars = "chars".toCharArray();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(chars);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendCharSequence() {
+ CharSequence cs = "chars";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(cs);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendSubCharSequence() {
+ CharSequence cs = "chars";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(cs);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendDouble() {
+ double d = 1.2;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(d);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendFloat() {
+ float f = 1.2f;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(f);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendInt() {
+ int n = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(n);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendLong() {
+ long l = 123;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(l);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendObject() {
+ // We don't want to time the toString, so ensure we're calling a trivial one...
+ Object o =
+ new Object() {
+ @Override
+ public String toString() {
+ return "constant";
+ }
+ };
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(o);
+ }
+ }
+ }
+
+ @Test
+ public void timeAppendString() {
+ String s = "chars";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < mLength; ++j) {
+ sb.append(s);
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
new file mode 100644
index 0000000..6854c0d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
@@ -0,0 +1,313 @@
+/*
+ * 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 junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Benchmarks to measure the performance of String.equals for Strings of varying lengths. Each
+ * benchmarks makes 5 measurements, aiming at covering cases like strings of equal length that are
+ * not equal, identical strings with different references, strings with different endings, interned
+ * strings, and strings of different lengths.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringEqualsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final String mLong1 =
+ "Ahead-of-time compilation is possible as the compiler may just convert an instruction"
+ + " thus: dex code: add-int v1000, v2000, v3000 C code: setIntRegter(1000,"
+ + " call_dex_add_int(getIntRegister(2000), getIntRegister(3000)) This means even"
+ + " lidinstructions may have code generated, however, it is not expected that code"
+ + " generate inthis way will perform well. The job of AOT verification is to tell"
+ + " the compiler thatinstructions are sound and provide tests to detect unsound"
+ + " sequences so slow path codemay be generated. Other than for totally invalid"
+ + " code, the verification may fail at AOrrun-time. At AOT time it can be because"
+ + " of incomplete information, at run-time it can ethat code in a different apk"
+ + " that the application depends upon has changed. The Dalvikverifier would return"
+ + " a bool to state whether a Class were good or bad. In ART the fail case becomes"
+ + " either a soft or hard failure. Classes have new states to represent that a soft"
+ + " failure occurred at compile time and should be re-verified at run-time.";
+
+ private final String mVeryLong =
+ "Garbage collection has two phases. The first distinguishes live objects from garbage"
+ + " objects. The second is reclaiming the rage of garbage objectIn the mark-sweep"
+ + " algorithm used by Dalvik, the first phase is achievd by computing the closure"
+ + " of all reachable objects in a process known as tracing from theoots. After"
+ + " thetrace has completed, garbage objects are reclaimed. Each of these"
+ + " operations can beparallelized and can be interleaved with the operation of the"
+ + " applicationTraditionally,the tracing phase dominates the time spent in garbage"
+ + " collection. The greatreduction ipause time can be achieved by interleaving as"
+ + " much of this phase as possible with theapplication. If we simply ran the GC in"
+ + " a separate thread with no other changes, normaloperation of an application"
+ + " would confound the trace. Abstractly, the GC walks the h oall reachable"
+ + " objects. When the application is paused, the object graph cannot change.The GC"
+ + " can therefore walk this structure and assume that all reachable objects"
+ + " live.When the application is running, this graph may be altered. New nodes may"
+ + " be addnd edgemay be changed. These changes may cause live objects to be hidden"
+ + " and falsely recla bythe GC. To avoid this problem a write barrier is used to"
+ + " intercept and record modifionto objects in a separate structure. After"
+ + " performing its walk, the GC will revisit theupdated objects and re-validate its"
+ + " assumptions. Without a card table, the garbagecollector would have to visit"
+ + " all objects reached during the trace looking for dirtied objects. The cost of"
+ + " this operation would be proportional to the amount of live data.With a card"
+ + " table, the cost of this operation is proportional to the amount of updateatThe"
+ + " write barrier in Dalvik is a card marking write barrier. Card marking is the"
+ + " proceof noting the location of object connectivity changes on a sub-page"
+ + " granularity. A caris merely a colorful term for a contiguous extent of memory"
+ + " smaller than a page, commonsomewhere between 128- and 512-bytes. Card marking"
+ + " is implemented by instrumenting alllocations in the virtual machine which can"
+ + " assign a pointer to an object. After themalpointer assignment has occurred, a"
+ + " byte is written to a byte-map spanning the heap whiccorresponds to the location"
+ + " of the updated object. This byte map is known as a card taThe garbage"
+ + " collector visits this card table and looks for written bytes to reckon"
+ + " thelocation of updated objects. It then rescans all objects located on the"
+ + " dirty card,correcting liveness assumptions that were invalidated by the"
+ + " application. While cardmarking imposes a small burden on the application"
+ + " outside of a garbage collection, theoverhead of maintaining the card table is"
+ + " paid for by the reduced time spent insidegarbage collection. With the"
+ + " concurrent garbage collection thread and a write barriersupported by the"
+ + " interpreter, JIT, and Runtime we modify garbage collection";
+
+ private final String[][] mShortStrings =
+ new String[][] {
+ // Equal, constant comparison
+ {"a", "a"},
+ // Different constants, first character different
+ {":", " :"},
+ // Different constants, last character different, same length
+ {"ja M", "ja N"},
+ // Different constants, different lengths
+ {"$$$", "$$"},
+ // Force execution of code beyond reference equality check
+ {"hi", new String("hi")}
+ };
+
+ private final String[][] mMediumStrings =
+ new String[][] {
+ // Equal, constant comparison
+ {"Hello my name is ", "Hello my name is "},
+ // Different constants, different lengths
+ {"What's your name?", "Whats your name?"},
+ // Force execution of code beyond reference equality check
+ {"Android Runtime", new String("Android Runtime")},
+ // Different constants, last character different, same length
+ {"v3ry Cre@tiVe?****", "v3ry Cre@tiVe?***."},
+ // Different constants, first character different, same length
+ {"!@#$%^&*()_++*^$#@", "0@#$%^&*()_++*^$#@"}
+ };
+
+ private final String[][] mLongStrings =
+ new String[][] {
+ // Force execution of code beyond reference equality check
+ {mLong1, new String(mLong1)},
+ // Different constants, last character different, same length
+ {mLong1 + "fun!", mLong1 + "----"},
+ // Equal, constant comparison
+ {mLong1 + mLong1, mLong1 + mLong1},
+ // Different constants, different lengths
+ {mLong1 + "123456789", mLong1 + "12345678"},
+ // Different constants, first character different, same length
+ {"Android Runtime" + mLong1, "android Runtime" + mLong1}
+ };
+
+ private final String[][] mVeryLongStrings =
+ new String[][] {
+ // Force execution of code beyond reference equality check
+ {mVeryLong, new String(mVeryLong)},
+ // Different constants, different lengths
+ {mVeryLong + mVeryLong, mVeryLong + " " + mVeryLong},
+ // Equal, constant comparison
+ {mVeryLong + mVeryLong + mVeryLong, mVeryLong + mVeryLong + mVeryLong},
+ // Different constants, last character different, same length
+ {mVeryLong + "77777", mVeryLong + "99999"},
+ // Different constants, first character different
+ {"Android Runtime" + mVeryLong, "android Runtime" + mVeryLong}
+ };
+
+ private final String[][] mEndStrings =
+ new String[][] {
+ // Different constants, medium but different lengths
+ {"Hello", "Hello "},
+ // Different constants, long but different lengths
+ {mLong1, mLong1 + "x"},
+ // Different constants, very long but different lengths
+ {mVeryLong, mVeryLong + "?"},
+ // Different constants, same medium lengths
+ {"How are you doing today?", "How are you doing today "},
+ // Different constants, short but different lengths
+ {"1", "1."}
+ };
+
+ private final String mTmpStr1 =
+ "012345678901234567890"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789";
+
+ private final String mTmpStr2 =
+ "z012345678901234567890"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "012345678901234567890123456789012345678x";
+
+ private final String[][] mNonalignedStrings =
+ new String[][] {
+ // Different non-word aligned medium length strings
+ {mTmpStr1, mTmpStr1.substring(1)},
+ // Different differently non-word aligned medium length strings
+ {mTmpStr2, mTmpStr2.substring(2)},
+ // Different non-word aligned long length strings
+ {mLong1, mLong1.substring(3)},
+ // Different non-word aligned very long length strings
+ {mVeryLong, mVeryLong.substring(1)},
+ // Equal non-word aligned constant strings
+ {"hello", "hello".substring(1)}
+ };
+
+ private final Object[] mObjects =
+ new Object[] {
+ // Compare to Double object
+ new Double(1.5),
+ // Compare to Integer object
+ new Integer(9999999),
+ // Compare to String array
+ new String[] {"h", "i"},
+ // Compare to int array
+ new int[] {1, 2, 3},
+ // Compare to Character object
+ new Character('a')
+ };
+
+ // Check assumptions about how the compiler, new String(String), and String.intern() work.
+ // Any failures here would invalidate these benchmarks.
+ @Before
+ public void setUp() throws Exception {
+ // String constants are the same object
+ Assert.assertSame("abc", "abc");
+ // new String(String) makes a copy
+ Assert.assertNotSame("abc", new String("abc"));
+ // Interned strings are treated like constants, so it is not necessary to
+ // separately benchmark interned strings.
+ Assert.assertSame("abc", "abc".intern());
+ Assert.assertSame("abc", new String("abc").intern());
+ // Compiler folds constant strings into new constants
+ Assert.assertSame(mLong1 + mLong1, mLong1 + mLong1);
+ }
+
+ // Benchmark cases of String.equals(null)
+ @Test
+ public void timeEqualsNull() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mMediumStrings.length; i++) {
+ mMediumStrings[i][0].equals(null);
+ }
+ }
+ }
+
+ // Benchmark cases with very short (<5 character) Strings
+ @Test
+ public void timeEqualsShort() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mShortStrings.length; i++) {
+ mShortStrings[i][0].equals(mShortStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases with medium length (10-15 character) Strings
+ @Test
+ public void timeEqualsMedium() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mMediumStrings.length; i++) {
+ mMediumStrings[i][0].equals(mMediumStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases with long (>100 character) Strings
+ @Test
+ public void timeEqualsLong() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mLongStrings.length; i++) {
+ mLongStrings[i][0].equals(mLongStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases with very long (>1000 character) Strings
+ @Test
+ public void timeEqualsVeryLong() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mVeryLongStrings.length; i++) {
+ mVeryLongStrings[i][0].equals(mVeryLongStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases with non-word aligned Strings
+ @Test
+ public void timeEqualsNonWordAligned() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mNonalignedStrings.length; i++) {
+ mNonalignedStrings[i][0].equals(mNonalignedStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases with slight differences in the endings
+ @Test
+ public void timeEqualsEnd() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mEndStrings.length; i++) {
+ mEndStrings[i][0].equals(mEndStrings[i][1]);
+ }
+ }
+ }
+
+ // Benchmark cases of comparing a string to a non-string object
+ @Test
+ public void timeEqualsNonString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mMediumStrings.length; i++) {
+ mMediumStrings[i][0].equals(mObjects[i]);
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
new file mode 100644
index 0000000..79ff646
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringIsEmptyPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeIsEmpty_NonEmpty() {
+ boolean result = true;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".isEmpty());
+ }
+ if (!result) throw new RuntimeException();
+ }
+
+ @Test
+ public void timeIsEmpty_Empty() {
+ boolean result = true;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result &= ("".isEmpty());
+ }
+ if (!result) throw new RuntimeException();
+ }
+
+ @Test
+ public void timeLengthEqualsZero() {
+ boolean result = true;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length() == 0);
+ }
+ if (!result) throw new RuntimeException();
+ }
+
+ @Test
+ public void timeEqualsEmpty() {
+ boolean result = true;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result &= !"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".equals("");
+ }
+ if (!result) throw new RuntimeException();
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
new file mode 100644
index 0000000..8dbf9f5
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringLengthPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeLength() {
+ int length = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ length = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length();
+ }
+ if (length != 51) throw new RuntimeException();
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
new file mode 100644
index 0000000..02194b1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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 StringPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ enum StringLengths {
+ EMPTY(""),
+ SHORT("short"),
+ EIGHTY(makeString(80)),
+ EIGHT_KI(makeString(8192));
+ final String mValue;
+
+ StringLengths(String value) {
+ this.mValue = value;
+ }
+ }
+
+ @Parameters(name = "mStringLengths={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {StringLengths.EIGHT_KI},
+ {StringLengths.EIGHTY},
+ {StringLengths.SHORT},
+ {StringLengths.EMPTY}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public StringLengths mStringLengths;
+
+ private static String makeString(int length) {
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ result.append((char) i);
+ }
+ return result.toString();
+ }
+
+ @Test
+ public void timeHashCode() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.hashCode();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
new file mode 100644
index 0000000..b0d1ee4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.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 StringReplaceAllPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ // NOTE: These estimates of MOVEABLE / NON_MOVEABLE are based on a knowledge of
+ // ART implementation details. They make a difference here because JNI calls related
+ // to strings took different paths depending on whether the String in question was
+ // moveable or not.
+ enum StringLengths {
+ EMPTY(""),
+ MOVEABLE_16(makeString(16)),
+ MOVEABLE_256(makeString(256)),
+ MOVEABLE_1024(makeString(1024)),
+ NON_MOVEABLE(makeString(64 * 1024)),
+ BOOT_IMAGE(java.util.jar.JarFile.MANIFEST_NAME);
+
+ private final String mValue;
+
+ StringLengths(String s) {
+ this.mValue = s;
+ }
+ }
+
+ private static String makeString(int length) {
+ final String sequence8 = "abcdefghijklmnop";
+ final int numAppends = (length / 16) - 1;
+ StringBuilder stringBuilder = new StringBuilder(length);
+
+ // (n-1) occurrences of "abcdefghijklmnop"
+ for (int i = 0; i < numAppends; ++i) {
+ stringBuilder.append(sequence8);
+ }
+
+ // and one final occurrence of qrstuvwx.
+ stringBuilder.append("qrstuvwx");
+
+ return stringBuilder.toString();
+ }
+
+ @Parameters(name = "mStringLengths={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {StringLengths.BOOT_IMAGE},
+ {StringLengths.EMPTY},
+ {StringLengths.MOVEABLE_16},
+ {StringLengths.MOVEABLE_256},
+ {StringLengths.MOVEABLE_1024},
+ {StringLengths.NON_MOVEABLE}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public StringLengths mStringLengths;
+
+ @Test
+ public void timeReplaceAllTrivialPatternNonExistent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replaceAll("fish", "0");
+ }
+ }
+
+ @Test
+ public void timeReplaceTrivialPatternAllRepeated() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replaceAll("jklm", "0");
+ }
+ }
+
+ @Test
+ public void timeReplaceAllTrivialPatternSingleOccurrence() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replaceAll("qrst", "0");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
new file mode 100644
index 0000000..d2e657a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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 StringReplacePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ enum StringLengths {
+ EMPTY(""),
+ L_16(makeString(16)),
+ L_64(makeString(64)),
+ L_256(makeString(256)),
+ L_512(makeString(512));
+
+ private final String mValue;
+
+ StringLengths(String s) {
+ this.mValue = s;
+ }
+ }
+
+ private static String makeString(int length) {
+ final String sequence8 = "abcdefghijklmnop";
+ final int numAppends = (length / 16) - 1;
+ StringBuilder stringBuilder = new StringBuilder(length);
+
+ // (n-1) occurrences of "abcdefghijklmnop"
+ for (int i = 0; i < numAppends; ++i) {
+ stringBuilder.append(sequence8);
+ }
+
+ // and one final occurrence of qrstuvwx.
+ stringBuilder.append("qrstuvwx");
+
+ return stringBuilder.toString();
+ }
+
+ @Parameters(name = "mStringLengths={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {StringLengths.EMPTY},
+ {StringLengths.L_16},
+ {StringLengths.L_64},
+ {StringLengths.L_256},
+ {StringLengths.L_512}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public StringLengths mStringLengths;
+
+ @Test
+ public void timeReplaceCharNonExistent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace('z', '0');
+ }
+ }
+
+ @Test
+ public void timeReplaceCharRepeated() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace('a', '0');
+ }
+ }
+
+ @Test
+ public void timeReplaceSingleChar() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace('q', '0');
+ }
+ }
+
+ @Test
+ public void timeReplaceSequenceNonExistent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace("fish", "0");
+ }
+ }
+
+ @Test
+ public void timeReplaceSequenceRepeated() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace("jklm", "0");
+ }
+ }
+
+ @Test
+ public void timeReplaceSingleSequence() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.replace("qrst", "0");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
new file mode 100644
index 0000000..2bb25ac
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.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.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringSplitPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeStringSplitComma() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ "this,is,a,simple,example".split(",");
+ }
+ }
+
+ @Test
+ public void timeStringSplitLiteralDot() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ "this.is.a.simple.example".split("\\.");
+ }
+ }
+
+ @Test
+ public void timeStringSplitNewline() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ "this\nis\na\nsimple\nexample\n".split("\n");
+ }
+ }
+
+ @Test
+ public void timePatternSplitComma() {
+ Pattern p = Pattern.compile(",");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ p.split("this,is,a,simple,example");
+ }
+ }
+
+ @Test
+ public void timePatternSplitLiteralDot() {
+ Pattern p = Pattern.compile("\\.");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ p.split("this.is.a.simple.example");
+ }
+ }
+
+ @Test
+ public void timeStringSplitHard() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ "this,is,a,harder,example".split("[,]");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
new file mode 100644
index 0000000..1efc188
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class StringToBytesPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ enum StringLengths {
+ EMPTY(""),
+ L_16(makeString(16)),
+ L_64(makeString(64)),
+ L_256(makeString(256)),
+ L_512(makeString(512)),
+ A_16(makeAsciiString(16)),
+ A_64(makeAsciiString(64)),
+ A_256(makeAsciiString(256)),
+ A_512(makeAsciiString(512));
+
+ private final String mValue;
+
+ StringLengths(String s) {
+ this.mValue = s;
+ }
+ }
+
+ @Parameters(name = "mStringLengths={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {StringLengths.EMPTY},
+ {StringLengths.L_16},
+ {StringLengths.L_64},
+ {StringLengths.L_256},
+ {StringLengths.L_512},
+ {StringLengths.A_16},
+ {StringLengths.A_64},
+ {StringLengths.A_256},
+ {StringLengths.A_512}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public StringLengths mStringLengths;
+
+ private static String makeString(int length) {
+ char[] chars = new char[length];
+ for (int i = 0; i < length; ++i) {
+ chars[i] = (char) i;
+ }
+ return new String(chars);
+ }
+
+ private static String makeAsciiString(int length) {
+ char[] chars = new char[length];
+ for (int i = 0; i < length; ++i) {
+ chars[i] = ((i & 0x7f) != 0) ? (char) (i & 0x7f) : '?';
+ }
+ return new String(chars);
+ }
+
+ @Test
+ public void timeGetBytesUtf8() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.getBytes(StandardCharsets.UTF_8);
+ }
+ }
+
+ @Test
+ public void timeGetBytesIso88591() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.getBytes(StandardCharsets.ISO_8859_1);
+ }
+ }
+
+ @Test
+ public void timeGetBytesAscii() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mStringLengths.mValue.getBytes(StandardCharsets.US_ASCII);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
new file mode 100644
index 0000000..b01948a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 StringToRealPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mString={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {"NaN"},
+ {"-1"},
+ {"0"},
+ {"1"},
+ {"1.2"},
+ {"-123.45"},
+ {"-123.45e8"},
+ {"-123.45e36"}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public String mString;
+
+ @Test
+ public void timeFloat_parseFloat() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Float.parseFloat(mString);
+ }
+ }
+
+ @Test
+ public void timeDouble_parseDouble() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Double.parseDouble(mString);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
new file mode 100644
index 0000000..f256555
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.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;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ThreadLocalPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final ThreadLocal<char[]> BUFFER =
+ new ThreadLocal<char[]>() {
+ @Override
+ protected char[] initialValue() {
+ return new char[20];
+ }
+ };
+
+ @Test
+ public void timeThreadLocal_get() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ BUFFER.get();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
new file mode 100644
index 0000000..8274512
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.TimeZone;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class TimeZonePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeTimeZone_getDefault() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getDefault();
+ }
+ }
+
+ @Test
+ public void timeTimeZone_getTimeZoneUTC() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getTimeZone("UTC");
+ }
+ }
+
+ @Test
+ public void timeTimeZone_getTimeZone_default() throws Exception {
+ String defaultId = TimeZone.getDefault().getID();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getTimeZone(defaultId);
+ }
+ }
+
+ // A time zone with relatively few transitions.
+ @Test
+ public void timeTimeZone_getTimeZone_America_Caracas() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getTimeZone("America/Caracas");
+ }
+ }
+
+ // A time zone with a lot of transitions.
+ @Test
+ public void timeTimeZone_getTimeZone_America_Santiago() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getTimeZone("America/Santiago");
+ }
+ }
+
+ @Test
+ public void timeTimeZone_getTimeZone_GMT_plus_10() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ TimeZone.getTimeZone("GMT+10");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
new file mode 100644
index 0000000..2ea834d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 org.xml.sax.InputSource;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+// http://code.google.com/p/android/issues/detail?id=18102
+@RunWith(Parameterized.class)
+@LargeTest
+public final class XMLEntitiesPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mLength={0}, mEntityFraction={1}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {10, 0},
+ {10, 0.5f},
+ {10, 1.0f},
+ {100, 0},
+ {100, 0.5f},
+ {100, 1.0f},
+ {1000, 0},
+ {1000, 0.5f},
+ {1000, 1.0f}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public int mLength;
+
+ @Parameterized.Parameter(1)
+ public float mEntityFraction;
+
+ private XmlPullParserFactory mXmlPullParserFactory;
+ private DocumentBuilderFactory mDocumentBuilderFactory;
+
+ /** a string like {@code <doc>&&++</doc>}. */
+ private String mXml;
+
+ @Before
+ public void setUp() throws Exception {
+ mXmlPullParserFactory = XmlPullParserFactory.newInstance();
+ mDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+ StringBuilder xmlBuilder = new StringBuilder();
+ xmlBuilder.append("<doc>");
+ for (int i = 0; i < (mLength * mEntityFraction); i++) {
+ xmlBuilder.append("&");
+ }
+ while (xmlBuilder.length() < mLength) {
+ xmlBuilder.append("+");
+ }
+ xmlBuilder.append("</doc>");
+ mXml = xmlBuilder.toString();
+ }
+
+ @Test
+ public void timeXmlParser() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ XmlPullParser parser = mXmlPullParserFactory.newPullParser();
+ parser.setInput(new StringReader(mXml));
+ while (parser.next() != XmlPullParser.END_DOCUMENT) {
+ // Keep running
+ }
+ }
+ }
+
+ @Test
+ public void timeDocumentBuilder() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ DocumentBuilder documentBuilder = mDocumentBuilderFactory.newDocumentBuilder();
+ documentBuilder.parse(new InputSource(new StringReader(mXml)));
+ }
+ }
+}
diff --git a/config/boot-image-profile-extra.txt b/config/boot-image-profile-extra.txt
new file mode 100644
index 0000000..e3b187e
--- /dev/null
+++ b/config/boot-image-profile-extra.txt
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# A list of methods that are found to be latency sensitive. We have this manual
+# due to current limitations of our boot image profiling, where knowing what
+# methods are latency sensitive is difficult. For example, this method is executed
+# in the system server, not on the UI thread of an app.
+HSPLandroid/graphics/Color;->luminance()F
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index abc2b74..cf3f07f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -230,6 +230,7 @@
field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
field public static final String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
field public static final String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
+ field public static final String RECEIVE_BLUETOOTH_MAP = "android.permission.RECEIVE_BLUETOOTH_MAP";
field public static final String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE";
field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
@@ -311,6 +312,7 @@
field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
+ field public static final String WRITE_SMS = "android.permission.WRITE_SMS";
}
public static final class Manifest.permission_group {
@@ -1978,6 +1980,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
+ method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
@@ -2077,6 +2080,7 @@
field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
+ field public static final String ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED";
field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
@@ -2097,7 +2101,9 @@
field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
+ field public static final String EXTRA_USER_HANDLE = "android.intent.extra.user_handle";
field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
+ field public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 16777216; // 0x1000000
field public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 67108864; // 0x4000000
field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index bfbb910..51ecd4c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -149,6 +149,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener);
method public static void setExitTransitionTimeout(long);
method public void setLaunchActivityType(int);
+ method public void setLaunchTaskDisplayAreaFeatureId(int);
method public void setLaunchWindowingMode(int);
method public void setLaunchedFromBubble(boolean);
method public void setTaskAlwaysOnTop(boolean);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 6a877f9..d7ff7e9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4366,8 +4366,8 @@
try {
getService().broadcastIntentWithFeature(
null, null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*requiredPermissions*/, null /*excludedPermissions*/, appOp, null, false,
- true, userId);
+ null /*requiredPermissions*/, null /*excludedPermissions*/,
+ null /*excludedPackages*/, appOp, null, false, true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0ff9f66..a92cbf3 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -208,6 +209,14 @@
"android.activity.launchTaskDisplayAreaToken";
/**
+ * The task display area feature id the activity should be launched into.
+ * @see #setLaunchTaskDisplayAreaFeatureId(int)
+ * @hide
+ */
+ private static final String KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID =
+ "android.activity.launchTaskDisplayAreaFeatureId";
+
+ /**
* The root task token the activity should be launched into.
* @see #setLaunchRootTask(WindowContainerToken)
* @hide
@@ -404,6 +413,7 @@
private int mLaunchDisplayId = INVALID_DISPLAY;
private int mCallerDisplayId = INVALID_DISPLAY;
private WindowContainerToken mLaunchTaskDisplayArea;
+ private int mLaunchTaskDisplayAreaFeatureId = FEATURE_UNDEFINED;
private WindowContainerToken mLaunchRootTask;
private IBinder mLaunchTaskFragmentToken;
@WindowConfiguration.WindowingMode
@@ -1147,6 +1157,8 @@
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
+ mLaunchTaskDisplayAreaFeatureId = opts.getInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID,
+ FEATURE_UNDEFINED);
mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
mLaunchTaskFragmentToken = opts.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
@@ -1472,6 +1484,23 @@
}
/** @hide */
+ public int getLaunchTaskDisplayAreaFeatureId() {
+ return mLaunchTaskDisplayAreaFeatureId;
+ }
+
+ /**
+ * Sets the TaskDisplayArea feature Id the activity should launch into.
+ * Note: It is possible to have TaskDisplayAreas with the same featureId on multiple displays.
+ * If launch display id is not specified, the TaskDisplayArea on the default display will be
+ * used.
+ * @hide
+ */
+ @TestApi
+ public void setLaunchTaskDisplayAreaFeatureId(int launchTaskDisplayAreaFeatureId) {
+ mLaunchTaskDisplayAreaFeatureId = launchTaskDisplayAreaFeatureId;
+ }
+
+ /** @hide */
public WindowContainerToken getLaunchRootTask() {
return mLaunchRootTask;
}
@@ -1902,6 +1931,9 @@
if (mLaunchTaskDisplayArea != null) {
b.putParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN, mLaunchTaskDisplayArea);
}
+ if (mLaunchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+ b.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mLaunchTaskDisplayAreaFeatureId);
+ }
if (mLaunchRootTask != null) {
b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 24046c0..52228e5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1185,7 +1185,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1202,7 +1202,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1218,7 +1218,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1235,8 +1235,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- getUserId());
+ null /*excludedPermissions=*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, options, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1251,7 +1251,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1260,7 +1260,7 @@
@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
- String[] excludedPermissions) {
+ String[] excludedPermissions, String[] excludedPackages) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
@@ -1268,7 +1268,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ excludedPackages, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1285,8 +1285,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- getUserId());
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, false,
+ false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1303,7 +1303,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1320,7 +1320,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1384,7 +1384,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1398,7 +1398,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1421,8 +1421,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- user.getIdentifier());
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, false,
+ false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1439,7 +1439,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, null, appOp, null, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1490,7 +1491,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false,
+ null /*excludedPermissions=*/, null, appOp, options, true, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1532,7 +1533,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1571,7 +1572,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, options, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1607,7 +1608,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1640,7 +1641,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1655,7 +1656,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1690,7 +1691,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index df95f8f..f2c808b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -138,7 +138,7 @@
int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
in String resultData, in Bundle map, in String[] requiredPermissions, in String[] excludePermissions,
- int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
+ in String[] excludePackages, int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
diff --git a/core/java/android/app/smartspace/OWNERS b/core/java/android/app/smartspace/OWNERS
index 19ef9d7..4d9a633 100644
--- a/core/java/android/app/smartspace/OWNERS
+++ b/core/java/android/app/smartspace/OWNERS
@@ -1,2 +1 @@
-srazdan@google.com
-alexmang@google.com
\ No newline at end of file
+include /core/java/android/service/smartspace/OWNERS
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 402007d..de9d491 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -37,6 +37,7 @@
import android.annotation.UiContext;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.BroadcastOptions;
import android.app.GameManager;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -2224,6 +2225,19 @@
*/
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
@NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions, null);
+ }
+
+
+ /**
+ * Like {@link #sendBroadcastMultiplePermissions(Intent, String[], String[])}, but also allows
+ * specification of a list of excluded packages.
+ *
+ * @hide
+ */
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -2248,6 +2262,27 @@
}
/**
+ * Version of {@link #sendBroadcastMultiplePermissions(Intent, String[])} that allows you to
+ * specify the {@link android.app.BroadcastOptions}.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param receiverPermissions Array of names of permissions that a receiver must hold
+ * in order to receive your broadcast.
+ * If empty, no permissions are required.
+ * @param options Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ * @see #sendBroadcastMultiplePermissions(Intent, String[])
+ * @see android.app.BroadcastOptions
+ * @hide
+ */
+ @SystemApi
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable BroadcastOptions options) {
+ sendBroadcastMultiplePermissions(intent, receiverPermissions, options.toBundle());
+ }
+
+ /**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
* an array of required permissions to be enforced. This call is asynchronous; it returns
* immediately, and you will continue executing while the receivers are run. No results are
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3a02004..18a46cf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -494,8 +494,10 @@
/** @hide */
@Override
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
- @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
- mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions);
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
+ mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions,
+ excludedPackages);
}
/** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 22c838c..76591ca 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3836,7 +3836,7 @@
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @SystemApi
public static final String ACTION_USER_SWITCHED =
"android.intent.action.USER_SWITCHED";
@@ -5970,6 +5970,8 @@
*
* @hide
*/
+ @SystemApi
+ @SuppressLint("ActionValue")
public static final String EXTRA_USER_HANDLE =
"android.intent.extra.user_handle";
@@ -6824,6 +6826,7 @@
*
* @hide
*/
+ @SystemApi
public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
/**
* If set, the broadcast will never go to manifest receivers in background (cached
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a411eee..61325bc 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -168,7 +168,7 @@
* signature checks} or
* <a href="https://developer.android.com/training/articles/security-tips#Permissions">permissions</a>.
*
- * <p><b>Warning:</b> Note that does flag not behave the same as
+ * <p><b>Warning:</b> Note that this flag does not behave the same as
* {@link android.R.attr#protectionLevel android:protectionLevel} {@code system} or
* {@code signatureOrSystem}.
*/
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index d06bc1d..3e41d63 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -122,6 +122,9 @@
}
private IHdmiControlCallback getCallbackWrapper(final OneTouchPlayCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("OneTouchPlayCallback cannot be null.");
+ }
return new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
@@ -131,6 +134,9 @@
}
private IHdmiControlCallback getCallbackWrapper(final DisplayStatusCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("DisplayStatusCallback cannot be null.");
+ }
return new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int status) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 59db8f4..a7c7ce2 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -350,7 +350,7 @@
}
/**
- * Reset the identity of the incoming IPC on the current thread. This can
+ * Reset the kernel binder identity of the incoming IPC on the current thread. This can
* be useful if, while handling an incoming call, you will be calling
* on interfaces of other objects that may be local to your process and
* need to do permission checks on the calls coming into them (so they
@@ -369,7 +369,7 @@
public static final native long clearCallingIdentity();
/**
- * Restore the identity of the incoming IPC on the current thread
+ * Restore the kernel binder identity of the incoming IPC on the current thread
* back to a previously identity that was returned by {@link
* #clearCallingIdentity}.
*
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 40e6780..9649d38 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -33,6 +33,7 @@
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.MathUtils;
+import android.util.Pair;
import android.util.Size;
import android.util.SizeF;
import android.util.Slog;
@@ -4858,28 +4859,36 @@
if (name == null) {
return null;
}
- Parcelable.Creator<?> creator;
- HashMap<String, Parcelable.Creator<?>> map;
- synchronized (mCreators) {
- map = mCreators.get(loader);
+
+ Pair<Parcelable.Creator<?>, Class<?>> creatorAndParcelableClass;
+ synchronized (sPairedCreators) {
+ HashMap<String, Pair<Parcelable.Creator<?>, Class<?>>> map =
+ sPairedCreators.get(loader);
if (map == null) {
- map = new HashMap<>();
- mCreators.put(loader, map);
+ sPairedCreators.put(loader, new HashMap<>());
+ mCreators.put(loader, new HashMap<>());
+ creatorAndParcelableClass = null;
+ } else {
+ creatorAndParcelableClass = map.get(name);
}
- creator = map.get(name);
}
- if (creator != null) {
+
+ if (creatorAndParcelableClass != null) {
+ Parcelable.Creator<?> creator = creatorAndParcelableClass.first;
+ Class<?> parcelableClass = creatorAndParcelableClass.second;
if (clazz != null) {
- Class<?> parcelableClass = creator.getClass().getEnclosingClass();
if (!clazz.isAssignableFrom(parcelableClass)) {
throw new BadTypeParcelableException("Parcelable creator " + name + " is not "
+ "a subclass of required class " + clazz.getName()
+ " provided in the parameter");
}
}
+
return (Parcelable.Creator<T>) creator;
}
+ Parcelable.Creator<?> creator;
+ Class<?> parcelableClass;
try {
// If loader == null, explicitly emulate Class.forName(String) "caller
// classloader" behavior.
@@ -4887,7 +4896,7 @@
(loader == null ? getClass().getClassLoader() : loader);
// Avoid initializing the Parcelable class until we know it implements
// Parcelable and has the necessary CREATOR field. http://b/1171613.
- Class<?> parcelableClass = Class.forName(name, false /* initialize */,
+ parcelableClass = Class.forName(name, false /* initialize */,
parcelableClassLoader);
if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
throw new BadParcelableException("Parcelable protocol requires subclassing "
@@ -4934,8 +4943,9 @@
+ "CREATOR on class " + name);
}
- synchronized (mCreators) {
- map.put(name, creator);
+ synchronized (sPairedCreators) {
+ sPairedCreators.get(loader).put(name, Pair.create(creator, parcelableClass));
+ mCreators.get(loader).put(name, creator);
}
return (Parcelable.Creator<T>) creator;
@@ -5086,12 +5096,17 @@
}
}
- // Cache of previously looked up CREATOR.createFromParcel() methods for
- // particular classes. Keys are the names of the classes, values are
- // Method objects.
+
+ // Left due to the UnsupportedAppUsage. Do not use anymore - use sPairedCreators instead
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- private static final HashMap<ClassLoader,HashMap<String,Parcelable.Creator<?>>>
- mCreators = new HashMap<>();
+ private static final HashMap<ClassLoader, HashMap<String, Parcelable.Creator<?>>>
+ mCreators = new HashMap<>();
+
+ // Cache of previously looked up CREATOR.createFromParcel() methods for particular classes.
+ // Keys are the names of the classes, values are a pair consisting of a parcelable creator,
+ // and the class of the parcelable type for the object.
+ private static final HashMap<ClassLoader, HashMap<String,
+ Pair<Parcelable.Creator<?>, Class<?>>>> sPairedCreators = new HashMap<>();
/** @hide for internal use only. */
static protected final Parcel obtain(int obj) {
diff --git a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
index cb521c8..4564c30 100644
--- a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
+++ b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
@@ -1,8 +1,7 @@
-ewol@google.com
+ashfall@google.com
hackbod@google.com
jsharkey@google.com
narayan@google.com
patb@google.com
-svetoslavganov@google.com
yamasani@google.com
zhanghai@google.com
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index 49f4bf7..d34b45b 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -2,7 +2,7 @@
evanseverson@google.com
evanxinchen@google.com
-ewol@google.com
+ashfall@google.com
guojing@google.com
jaysullivan@google.com
kvakil@google.com
diff --git a/core/java/android/service/appprediction/OWNERS b/core/java/android/service/appprediction/OWNERS
index fe012da..6efb975 100644
--- a/core/java/android/service/appprediction/OWNERS
+++ b/core/java/android/service/appprediction/OWNERS
@@ -1,2 +1,4 @@
adamcohen@google.com
+hyunyoungs@google.com
+pinyaoting@google.com
sunnygoyal@google.com
diff --git a/core/java/android/service/smartspace/OWNERS b/core/java/android/service/smartspace/OWNERS
index 19ef9d7..d3acd3d3 100644
--- a/core/java/android/service/smartspace/OWNERS
+++ b/core/java/android/service/smartspace/OWNERS
@@ -1,2 +1,4 @@
+hyunyoungs@google.com
+awickham@google.com
srazdan@google.com
-alexmang@google.com
\ No newline at end of file
+sunnygoyal@google.com
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0d530f6..bb4ab39 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -549,10 +549,15 @@
return NULL;
}
- // do not marshall if there are binder objects in the parcel
+ if (parcel->isForRpc()) {
+ jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall an RPC Parcel.");
+ return NULL;
+ }
+
if (parcel->objectsCount())
{
- jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Tried to marshall a Parcel that contains objects (binders or FDs).");
return NULL;
}
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
index 83e2f2b..2279856 100644
--- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -21,17 +21,17 @@
#include "jni.h"
namespace android {
-static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
+static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jclass clazz,
jboolean hasConnectivity) {
setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
}
-static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) {
+static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jclass clazz, jint socket) {
return (jboolean)!protectFromVpn(socket);
}
-static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
- return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFd(env, javaFd));
+static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jclass clazz, jobject javaFd) {
+ return android_net_utils_protectFromVpn(env, clazz, AFileDescriptor_getFd(env, javaFd));
}
static const JNINativeMethod gNetworkUtilMethods[] = {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5a5d7e8..02453a4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1536,7 +1536,7 @@
android:protectionLevel="normal"
android:permissionFlags="removed"/>
- <!-- @hide We need to keep this around for backwards compatibility -->
+ <!-- @SystemApi @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SMS"
android:protectionLevel="normal"
android:permissionFlags="removed"/>
@@ -1614,7 +1614,7 @@
<permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
android:protectionLevel="signature|privileged" />
- <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
+ <!-- @SystemApi Allows an application to monitor incoming Bluetooth MAP messages, to record
or perform processing on them. -->
<!-- @hide -->
<permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
diff --git a/core/res/res/values-mcc440-mnc20/config.xml b/core/res/res/values-mcc440-mnc20/config.xml
index 62001d9..7a48342 100644
--- a/core/res/res/values-mcc440-mnc20/config.xml
+++ b/core/res/res/values-mcc440-mnc20/config.xml
@@ -23,6 +23,6 @@
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
- <integer name="config_mobile_mtu">1422</integer>
+ <integer name="config_mobile_mtu">1358</integer>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cd7f99f..4ece840 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5199,4 +5199,12 @@
<!-- Whether this device should support taking app snapshots on closure -->
<bool name="config_disableTaskSnapshots">false</bool>
+
+ <!-- List of system components which are allowed to receive ServiceState entries in an
+ un-sanitized form, even if the location toggle is off. This is intended ONLY for system
+ components, such as the telephony stack, which require access to the full ServiceState for
+ tasks such as network registration. -->
+ <string-array name="config_serviceStateLocationAllowedPackages">
+ <item>"com.android.phone"</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5c95721..89797e8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4463,5 +4463,6 @@
<java-symbol type="bool" name="config_disableTaskSnapshots" />
+ <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
<java-symbol type="dimen" name="status_bar_height_default" />
</resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index dab4f1b..8519ddf 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -61,7 +61,7 @@
<shortcode country="bg" pattern="\\d{4,5}" premium="18(?:16|423)|19(?:1[56]|35)" free="116\\d{3}|1988|1490" />
<!-- Bahrain: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="bh" pattern="\\d{1,5}" free="81181" />
+ <shortcode country="bh" pattern="\\d{1,5}" free="81181|85999" />
<!-- Brazil: 1-5 digits (standard system default, not country specific) -->
<shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" />
@@ -83,7 +83,7 @@
<shortcode country="cn" premium="1066.*" free="1065.*" />
<!-- Colombia: 1-6 digits (not confirmed) -->
- <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739" />
+ <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739|85517" />
<!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
@@ -190,7 +190,7 @@
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
<!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963" />
+ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index a743d30..ed87990 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -90,11 +90,36 @@
SkRect srcRect = inSrcRect.toSkRect();
- SkRect imageSrcRect =
- SkRect::MakeLTRB(cropRect.left, cropRect.top, cropRect.right, cropRect.bottom);
- if (imageSrcRect.isEmpty()) {
- imageSrcRect = SkRect::MakeIWH(description.width, description.height);
+ SkRect imageSrcRect = SkRect::MakeIWH(description.width, description.height);
+ SkISize imageWH = SkISize::Make(description.width, description.height);
+ if (cropRect.left < cropRect.right && cropRect.top < cropRect.bottom) {
+ imageSrcRect =
+ SkRect::MakeLTRB(cropRect.left, cropRect.top, cropRect.right, cropRect.bottom);
+ imageWH = SkISize::Make(cropRect.right - cropRect.left, cropRect.bottom - cropRect.top);
+
+ // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by
+ // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an
+ // additional 0.5 inset. See GLConsumer::computeTransformMatrix for details.
+ float shrinkAmount = 0.0f;
+ switch (description.format) {
+ // Use HAL formats since some AHB formats are only available in vndk
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ shrinkAmount = 0.5f;
+ break;
+ default:
+ break;
+ }
+
+ // Shrink the crop if it has more than 1-px and differs from the buffer size.
+ if (imageWH.width() > 1 && imageWH.width() < (int32_t)description.width)
+ imageSrcRect = imageSrcRect.makeInset(shrinkAmount, 0);
+
+ if (imageWH.height() > 1 && imageWH.height() < (int32_t)description.height)
+ imageSrcRect = imageSrcRect.makeInset(0, shrinkAmount);
}
+
ALOGV("imageSrcRect = " RECT_STRING, SK_RECT_ARGS(imageSrcRect));
// Represents the "logical" width/height of the texture. That is, the dimensions of the buffer
@@ -153,7 +178,7 @@
*/
SkMatrix m;
- const SkRect imageDstRect = SkRect::MakeIWH(imageSrcRect.width(), imageSrcRect.height());
+ const SkRect imageDstRect = SkRect::Make(imageWH);
const float px = imageDstRect.centerX();
const float py = imageDstRect.centerY();
if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index 132d71e..128be3c 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -55,6 +55,7 @@
export_include_dirs: ["include"],
+ min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
"com.android.os.statsd",
@@ -81,5 +82,5 @@
proto: {
type: "full",
- }
+ },
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index b27a00c..c495535 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1200,6 +1200,8 @@
/**
* Specifying if haptic should be muted or not when playing audio-haptic coupled data.
* By default, haptic channels are disabled.
+ * <p>This will be ignored if the caller doesn't have the
+ * {@link android.Manifest.permission#VIBRATE} permission.
* @param muted true to force muting haptic channels.
* @return the same Builder instance.
*/
diff --git a/media/java/android/media/audiofx/HapticGenerator.java b/media/java/android/media/audiofx/HapticGenerator.java
index fe7f29e..d2523ef 100644
--- a/media/java/android/media/audiofx/HapticGenerator.java
+++ b/media/java/android/media/audiofx/HapticGenerator.java
@@ -91,7 +91,8 @@
}
/**
- * Enable or disable the effect.
+ * Enable or disable the effect. The effect can only be enabled if the caller has the
+ * {@link android.Manifest.permission#VIBRATE} permission.
*
* @param enabled the requested enable state
* @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 89e10c4..fc70ba4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -20,15 +20,19 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
+import android.os.Build;
import android.os.ParcelUuid;
import android.util.Log;
+import androidx.annotation.ChecksSdkIntAtLeast;
+
import com.android.internal.annotations.VisibleForTesting;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
@@ -126,32 +130,84 @@
}
}
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+ private static boolean isAtLeastT() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
+ }
+
// Group devices by groupId
@VisibleForTesting
void onGroupIdChanged(int groupId) {
- int firstMatchedIndex = -1;
- CachedBluetoothDevice mainDevice = null;
+ if (!isValidGroupId(groupId)) {
+ log("onGroupIdChanged: groupId is invalid");
+ return;
+ }
+ log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString());
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
+ final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
+ final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ?
+ leAudioProfile.getConnectedGroupLeadDevice(groupId) : null;
+ CachedBluetoothDevice newMainDevice =
+ mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null;
+ if (newMainDevice != null) {
+ final CachedBluetoothDevice finalNewMainDevice = newMainDevice;
+ final List<CachedBluetoothDevice> memberDevices = mCachedDevices.stream()
+ .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice)
+ && cachedDevice.getGroupId() == groupId)
+ .collect(Collectors.toList());
+ if (memberDevices == null || memberDevices.isEmpty()) {
+ log("onGroupIdChanged: There is no member device in list.");
+ return;
+ }
+ log("onGroupIdChanged: removed from UI device =" + memberDevices
+ + ", with groupId=" + groupId + " mainDevice= " + newMainDevice);
+ for (CachedBluetoothDevice memberDeviceItem : memberDevices) {
+ Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice();
+ if (!memberSet.isEmpty()) {
+ log("onGroupIdChanged: Transfer the member list into new main device.");
+ for (CachedBluetoothDevice memberListItem : memberSet) {
+ if (!memberListItem.equals(newMainDevice)) {
+ newMainDevice.addMemberDevice(memberListItem);
+ }
+ }
+ memberSet.clear();
+ }
- for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
- final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- if (cachedDevice.getGroupId() != groupId) {
- continue;
+ newMainDevice.addMemberDevice(memberDeviceItem);
+ mCachedDevices.remove(memberDeviceItem);
+ mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem);
}
- if (firstMatchedIndex == -1) {
- // Found the first one
- firstMatchedIndex = i;
- mainDevice = cachedDevice;
- continue;
+ if (!mCachedDevices.contains(newMainDevice)) {
+ mCachedDevices.add(newMainDevice);
+ mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice);
}
+ } else {
+ log("onGroupIdChanged: There is no main device from the LE profile.");
+ int firstMatchedIndex = -1;
- log("onGroupIdChanged: removed from UI device =" + cachedDevice
- + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ if (cachedDevice.getGroupId() != groupId) {
+ continue;
+ }
- mainDevice.addMemberDevice(cachedDevice);
- mCachedDevices.remove(i);
- mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
- break;
+ if (firstMatchedIndex == -1) {
+ // Found the first one
+ firstMatchedIndex = i;
+ newMainDevice = cachedDevice;
+ continue;
+ }
+
+ log("onGroupIdChanged: removed from UI device =" + cachedDevice
+ + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
+
+ newMainDevice.addMemberDevice(cachedDevice);
+ mCachedDevices.remove(i);
+ mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ break;
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index c323c4e..b6dcdc3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -21,6 +21,7 @@
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCodecConfig;
@@ -183,6 +184,37 @@
return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
}
+ /**
+ * Get Lead device for the group.
+ *
+ * Lead device is the device that can be used as an active device in the system.
+ * Active devices points to the Audio Device for the Le Audio group.
+ * This method returns the Lead devices for the connected LE Audio
+ * group and this device should be used in the setActiveDevice() method by other parts
+ * of the system, which wants to set to active a particular Le Audio group.
+ *
+ * Note: getActiveDevice() returns the Lead device for the currently active LE Audio group.
+ * Note: When Lead device gets disconnected while Le Audio group is active and has more devices
+ * in the group, then Lead device will not change. If Lead device gets disconnected, for the
+ * Le Audio group which is not active, a new Lead device will be chosen
+ *
+ * @param groupId The group id.
+ * @return group lead device.
+ *
+ * @hide
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public @Nullable BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
+ if (DEBUG) {
+ Log.d(TAG,"getConnectedGroupLeadDevice");
+ }
+ if (mService == null) {
+ Log.e(TAG,"No service.");
+ return null;
+ }
+ return mService.getConnectedGroupLeadDevice(groupId);
+ }
+
@Override
public boolean isEnabled(BluetoothDevice device) {
if (mService == null || device == null) {
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
index 0ec8ed3..acb54f6 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
@@ -67,6 +67,10 @@
}
}
+ //clear sp before enqueue unique work since policy is REPLACE
+ val deContext = context.createDeviceProtectedStorageContext()
+ val editor = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)?.edit()
+ editor?.clear()?.apply()
WorkManager.getInstance(context)
.beginUniqueWork(
"$PACKAGE_WORK_PREFIX_V1$packageName",
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt
index 3a3aea9..36c81722 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt
@@ -41,9 +41,7 @@
Data.Builder()
.putInt(VERIFICATION_ID_KEY, verificationId)
.apply {
- if (DEBUG) {
- putString(PACKAGE_NAME_KEY, packageName)
- }
+ putString(PACKAGE_NAME_KEY, packageName)
}
.build()
)
@@ -52,6 +50,18 @@
override suspend fun doWork() = coroutineScope {
if (!AndroidUtils.isReceiverV1Enabled(appContext)) {
+ //clear sp and commit here
+ val inputData = params.inputData
+ val packageName = inputData.getString(PACKAGE_NAME_KEY)
+ val deContext = appContext.createDeviceProtectedStorageContext()
+ val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)
+ val editor = sp?.edit()
+ editor?.clear()?.commit()
+ //delete sp file
+ val retOfDel = deContext?.deleteSharedPreferences(packageName)
+ if (DEBUG) {
+ Log.d(TAG, "delete sp for $packageName return $retOfDel")
+ }
return@coroutineScope Result.success()
}
@@ -59,7 +69,10 @@
val verificationId = inputData.getInt(VERIFICATION_ID_KEY, -1)
val successfulHosts = mutableListOf<String>()
val failedHosts = mutableListOf<String>()
- inputData.keyValueMap.entries.forEach { (key, _) ->
+ val packageName = inputData.getString(PACKAGE_NAME_KEY)
+ val deContext = appContext.createDeviceProtectedStorageContext()
+ val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)
+ sp?.all?.entries?.forEach { (key, _) ->
when {
key.startsWith(SingleV1RequestWorker.HOST_SUCCESS_PREFIX) ->
successfulHosts += key.removePrefix(SingleV1RequestWorker.HOST_SUCCESS_PREFIX)
@@ -69,7 +82,6 @@
}
if (DEBUG) {
- val packageName = inputData.getString(PACKAGE_NAME_KEY)
Log.d(
TAG, "Domain verification v1 request for $packageName: " +
"success = $successfulHosts, failed = $failedHosts"
@@ -84,6 +96,15 @@
appContext.packageManager.verifyIntentFilter(verificationId, resultCode, failedHosts)
+ //clear sp and commit here
+ val editor = sp?.edit()
+ editor?.clear()?.commit()
+ //delete sp file
+ val retOfDel = deContext?.deleteSharedPreferences(packageName)
+ if (DEBUG) {
+ Log.d(TAG, "delete sp for $packageName return $retOfDel")
+ }
+
Result.success()
}
}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
index cd8a182..7a198cb 100644
--- a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
@@ -71,16 +71,18 @@
// Coerce failure results into success so that final collection task gets a chance to run
when (result) {
- is Result.Success -> Result.success(
- Data.Builder()
- .putInt("$HOST_SUCCESS_PREFIX$host", status.value)
- .build()
- )
- is Result.Failure -> Result.success(
- Data.Builder()
- .putInt("$HOST_FAILURE_PREFIX$host", status.value)
- .build()
- )
+ is Result.Success -> {
+ val deContext = appContext.createDeviceProtectedStorageContext()
+ val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)
+ sp?.edit()?.putInt("$HOST_SUCCESS_PREFIX$host", status.value)?.apply()
+ Result.success()
+ }
+ is Result.Failure -> {
+ val deContext = appContext.createDeviceProtectedStorageContext()
+ val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)
+ sp?.edit()?.putInt("$HOST_FAILURE_PREFIX$host", status.value)?.apply()
+ Result.success()
+ }
else -> result
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index a617850..f8f784f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -112,7 +112,7 @@
if (DEBUG) Log.d(mTag, "requesting AudioFocus");
int focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
if (mCmd.looping) {
- focusGain = AudioManager.AUDIOFOCUS_GAIN;
+ focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT;
}
mNotificationRampTimeMs = audioManager.getFocusRampTimeMs(
focusGain, mCmd.attributes);
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index a31cfae..2b9f179 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,4 +1,4 @@
-svetoslavganov@google.com
pweaver@google.com
-rhedjao@google.com
+sallyyuen@google.com
ryanlwlin@google.com
+fuego@google.com
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7cbe218..16c4880 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -125,6 +125,7 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -354,6 +355,8 @@
private static final float DEFAULT_LOW_BATTERY_LEVEL = 20F;
// Decide whether charging is required to turn on the feature
private static final boolean DEFAULT_CHARGING_REQUIRED = true;
+ // Minimum GC interval sleep time in ms
+ private static final int DEFAULT_MIN_GC_SLEEPTIME = 10000;
private volatile int mLifetimePercentThreshold;
private volatile int mMinSegmentsThreshold;
@@ -361,6 +364,7 @@
private volatile float mSegmentReclaimWeight;
private volatile float mLowBatteryLevel;
private volatile boolean mChargingRequired;
+ private volatile int mMinGCSleepTime;
private volatile boolean mNeedGC;
private volatile boolean mPassedLifetimeThresh;
@@ -2611,6 +2615,8 @@
"low_battery_level", DEFAULT_LOW_BATTERY_LEVEL);
mChargingRequired = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
"charging_required", DEFAULT_CHARGING_REQUIRED);
+ mMinGCSleepTime = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "min_gc_sleeptime", DEFAULT_MIN_GC_SLEEPTIME);
// If we use the smart idle maintenance, we need to turn off GC in the traditional idle
// maintenance to avoid the conflict
@@ -2728,6 +2734,14 @@
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
try {
+ int latestWrite = mVold.getWriteAmount();
+ if (latestWrite == -1) {
+ Slog.w(TAG, "Failed to get storage write record");
+ return;
+ }
+
+ updateStorageWriteRecords(latestWrite);
+
// Block based checkpoint process runs fstrim. So, if checkpoint is in progress
// (first boot after OTA), We skip the smart idle maintenance
if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
@@ -2735,13 +2749,6 @@
return;
}
- int latestWrite = mVold.getWriteAmount();
- if (latestWrite == -1) {
- Slog.w(TAG, "Failed to get storage write record");
- return;
- }
-
- updateStorageWriteRecords(latestWrite);
int avgWriteAmount = getAverageWriteAmount();
Slog.i(TAG, "Set smart idle maintenance: " + "latest write amount: " +
@@ -2749,9 +2756,11 @@
", min segment threshold: " + mMinSegmentsThreshold +
", dirty reclaim rate: " + mDirtyReclaimRate +
", segment reclaim weight: " + mSegmentReclaimWeight +
- ", period: " + sSmartIdleMaintPeriod);
+ ", period(min): " + sSmartIdleMaintPeriod +
+ ", min gc sleep time(ms): " + mMinGCSleepTime);
mVold.setGCUrgentPace(avgWriteAmount, mMinSegmentsThreshold, mDirtyReclaimRate,
- mSegmentReclaimWeight, sSmartIdleMaintPeriod);
+ mSegmentReclaimWeight, sSmartIdleMaintPeriod,
+ mMinGCSleepTime);
} else {
Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
}
@@ -3274,11 +3283,21 @@
mInstaller.tryMountDataMirror(volumeUuid);
}
}
- } catch (RemoteException | Installer.InstallerException e) {
+ } catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "224585613", -1, "");
Slog.wtf(TAG, e);
// Make sure to re-throw this exception; we must not ignore failure
// to prepare the user storage as it could indicate that encryption
// wasn't successfully set up.
+ //
+ // Very unfortunately, these errors need to be ignored for broken
+ // users that already existed on-disk from older Android versions.
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
+ if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
+ Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
+ + "; device may be insecure!");
+ return;
+ }
throw new RuntimeException(e);
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 724d17b..481b53c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -3065,42 +3065,88 @@
Binder.restoreCallingIdentity(ident);
}
+ // Send the broadcast exactly once to all possible disjoint sets of apps.
+ // If the location master switch is on, broadcast the ServiceState 4 times:
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and
+ // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE
+ // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION
+ // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither
+ // READ_PHONE_STATE nor ACCESS_FINE_LOCATION
+ // If the location master switch is off, broadcast the ServiceState multiple times:
+ // - Full ServiceState sent to all apps permitted to bypass the location master switch if
+ // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not
+ // READ_PHONE_STATE
+ if (Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ } else {
+ String[] locationBypassPackages = Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.getLocationBypassPackages(mContext));
+ for (String locationBypassPackage : locationBypassPackages) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ fullIntent.setPackage(locationBypassPackage);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ }
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{/* no excluded permissions */},
+ locationBypassPackages);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ locationBypassPackages);
+ }
+ }
+
+ private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId,
+ boolean sanitizeLocation) {
Intent intent = new Intent(Intent.ACTION_SERVICE_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Bundle data = new Bundle();
- state.fillInNotifierBundle(data);
+ if (sanitizeLocation) {
+ state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
+ } else {
+ state.fillInNotifierBundle(data);
+ }
intent.putExtras(data);
- // Pass the subscription along with the intent.
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
-
- // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again
- // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE.
- // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with
- // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION.
- // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
- // get this broadcast exactly once, and we are not exposing location without permission.
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION},
- new String[] {Manifest.permission.READ_PHONE_STATE});
-
- // Replace bundle with location-sanitized ServiceState
- data = new Bundle();
- state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
- intent.putExtras(data);
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE},
- new String[] {Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
+ return intent;
}
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index d3ef6be..c9a420e 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -45,6 +45,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.ServiceManager;
@@ -131,6 +132,12 @@
return INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
}
+
+ /** Create a VPN. */
+ public Vpn createVpn(Looper looper, Context context, INetworkManagementService nms,
+ INetd netd, int userId) {
+ return new Vpn(looper, context, nms, netd, userId, new VpnProfileStore());
+ }
}
public VpnManagerService(Context context, Dependencies deps) {
@@ -688,6 +695,7 @@
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
@@ -738,6 +746,10 @@
final boolean isReplacing = intent.getBooleanExtra(
Intent.EXTRA_REPLACING, false);
onPackageRemoved(packageName, uid, isReplacing);
+ } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ final boolean isReplacing = intent.getBooleanExtra(
+ Intent.EXTRA_REPLACING, false);
+ onPackageAdded(packageName, uid, isReplacing);
} else {
Log.wtf(TAG, "received unexpected intent: " + action);
}
@@ -764,8 +776,7 @@
loge("Starting user already has a VPN");
return;
}
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId,
- new VpnProfileStore());
+ userVpn = mDeps.createVpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId);
mVpns.put(userId, userVpn);
if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
updateLockdownVpn();
@@ -851,15 +862,33 @@
final int userId = UserHandle.getUserId(uid);
synchronized (mVpns) {
final Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
+ if (vpn == null || isReplacing) {
return;
}
// Legacy always-on VPN won't be affected since the package name is not set.
- if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
+ if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
log("Removing always-on VPN package " + packageName + " for user "
+ userId);
vpn.setAlwaysOnPackage(null, false, null);
}
+
+ vpn.refreshPlatformVpnAppExclusionList();
+ }
+ }
+
+ private void onPackageAdded(String packageName, int uid, boolean isReplacing) {
+ if (TextUtils.isEmpty(packageName) || uid < 0) {
+ Log.wtf(TAG, "Invalid package in onPackageAdded: " + packageName + " | " + uid);
+ return;
+ }
+
+ final int userId = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ final Vpn vpn = mVpns.get(userId);
+
+ if (vpn != null && !isReplacing) {
+ vpn.refreshPlatformVpnAppExclusionList();
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 683b730..09b601c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2574,7 +2574,7 @@
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -4051,7 +4051,7 @@
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.getUserId(uid));
}
@@ -7746,7 +7746,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
@@ -7758,8 +7758,8 @@
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
+ OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
@@ -12577,8 +12577,8 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1, false, null,
+ null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
+ receivers, null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
@@ -12820,12 +12820,14 @@
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
- int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
+ String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered,
+ boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
- realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
+ excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
+ callingUid, realCallingUid, realCallingPid, userId,
+ false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@@ -12834,7 +12836,7 @@
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
- String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
boolean allowBackgroundActivityStarts,
@@ -13411,10 +13413,10 @@
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
- resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken,
- timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
+ registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
+ sticky, false, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -13509,7 +13511,7 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt);
@@ -13638,14 +13640,16 @@
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermissions, null, appOp, bOptions, serialized,
- sticky, userId);
+ resultData, resultExtras, requiredPermissions, null, null, appOp, bOptions,
+ serialized, sticky, userId);
}
+ @Override
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
- String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] requiredPermissions, String[] excludedPermissions,
+ String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
@@ -13660,8 +13664,8 @@
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
- sticky, callingPid, callingUid, callingUid, callingPid, userId);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -13683,7 +13687,7 @@
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
+ null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken,
null /* broadcastAllowList */);
@@ -15951,10 +15955,11 @@
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions, null, AppOpsManager.OP_NONE,
- bOptions /*options*/, serialized, false /*sticky*/, callingPid,
- callingUid, callingUid, callingPid, userId,
- false /*allowBackgroundStarts*/,
+ null /*resultExtras*/, requiredPermissions,
+ null /*excludedPermissions*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
+ false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
+ userId, false /*allowBackgroundStarts*/,
null /*tokenNeededForBackgroundActivityStarts*/, appIdAllowList);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -16076,7 +16081,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ null, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
@@ -16091,8 +16096,8 @@
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
PowerExemptionManager.REASON_LOCALE_CHANGED, "");
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, bOptions.toBundle(), false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ null, null, OP_NONE, bOptions.toBundle(), false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.USER_ALL);
}
@@ -16107,8 +16112,9 @@
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
- permissions, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
+ permissions, null, null, OP_NONE, null, false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.USER_ALL);
}
}
}
@@ -16132,8 +16138,8 @@
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, null, OP_NONE, null, false, false, -1, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index ea28117..827c5c4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -24,6 +24,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
@@ -170,6 +171,7 @@
private String mAgent; // Agent to attach on startup.
private boolean mAttachAgentDuringBind; // Whether agent should be attached late.
private int mDisplayId;
+ private int mTaskDisplayAreaFeatureId;
private int mWindowingMode;
private int mActivityType;
private int mTaskId;
@@ -353,6 +355,7 @@
mStreaming = false;
mUserId = defUser;
mDisplayId = INVALID_DISPLAY;
+ mTaskDisplayAreaFeatureId = FEATURE_UNDEFINED;
mWindowingMode = WINDOWING_MODE_UNDEFINED;
mActivityType = ACTIVITY_TYPE_UNDEFINED;
mTaskId = INVALID_TASK_ID;
@@ -408,6 +411,8 @@
mReceiverPermission = getNextArgRequired();
} else if (opt.equals("--display")) {
mDisplayId = Integer.parseInt(getNextArgRequired());
+ } else if (opt.equals("--task-display-area-feature-id")) {
+ mTaskDisplayAreaFeatureId = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--windowingMode")) {
mWindowingMode = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--activityType")) {
@@ -535,6 +540,12 @@
options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(mDisplayId);
}
+ if (mTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchTaskDisplayAreaFeatureId(mTaskDisplayAreaFeatureId);
+ }
if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
if (options == null) {
options = ActivityOptions.makeBasic();
@@ -773,8 +784,8 @@
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bundle, true, false,
- mUserId);
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, bundle, true,
+ false, mUserId);
if (!mAsync) {
receiver.waitForFinish();
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2da4107..6daf709 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -67,6 +67,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import java.io.FileDescriptor;
@@ -766,6 +767,22 @@
skip = true;
}
}
+
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, filter.packageName)) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " excludes package " + filter.packageName
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
// If the broadcast also requires an app op check that as well.
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(r.appOp,
@@ -1600,6 +1617,19 @@
}
}
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " excludes package " + component.getPackageName()
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8015596..84a9482 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -63,6 +63,7 @@
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
final String[] excludedPermissions; // permissions to exclude
+ final String[] excludedPackages; // packages to exclude
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
@@ -147,6 +148,10 @@
pw.print(prefix); pw.print("excludedPermissions=");
pw.print(Arrays.toString(excludedPermissions));
}
+ if (excludedPackages != null && excludedPackages.length > 0) {
+ pw.print(prefix); pw.print("excludedPackages=");
+ pw.print(Arrays.toString(excludedPackages));
+ }
if (options != null) {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
@@ -245,7 +250,8 @@
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
@Nullable String _callerFeatureId, int _callingPid, int _callingUid,
boolean _callerInstantApp, String _resolvedType,
- String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
+ String[] _requiredPermissions, String[] _excludedPermissions,
+ String[] _excludedPackages, int _appOp,
BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
@@ -265,6 +271,7 @@
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
excludedPermissions = _excludedPermissions;
+ excludedPackages = _excludedPackages;
appOp = _appOp;
options = _options;
receivers = _receivers;
@@ -306,6 +313,7 @@
resolvedType = from.resolvedType;
requiredPermissions = from.requiredPermissions;
excludedPermissions = from.excludedPermissions;
+ excludedPackages = from.excludedPackages;
appOp = from.appOp;
options = from.options;
receivers = from.receivers;
@@ -363,9 +371,10 @@
// build a new BroadcastRecord around that single-target list
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
+ splitReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky,
+ initialSticky, userId, allowBackgroundActivityStarts,
+ mBackgroundActivityStartsToken, timeoutExempt);
split.splitToken = this.splitToken;
return split;
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 7562098..35f91ba 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -124,7 +124,7 @@
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
- null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
+ null, null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c465be1..6f7dab9 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2994,8 +2994,8 @@
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
- realCallingPid, userId);
+ null, appOp, bOptions, ordered, sticky, callingPid, callingUid,
+ realCallingUid, realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 4d025c9..28a9191 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -423,6 +423,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
@@ -441,6 +442,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5b282ce..c3fc8e0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -186,7 +186,7 @@
private static final boolean LOGD = true;
private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
/** Key containing prefix of vpn app excluded list */
- @VisibleForTesting static final String VPN_APP_EXCLUDED = "VPN_APP_EXCLUDED_";
+ @VisibleForTesting static final String VPN_APP_EXCLUDED = "VPNAPPEXCLUDED_";
// Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
// the device idle allowlist during service launch and VPN bootstrap.
@@ -1182,20 +1182,9 @@
cleanupVpnStateLocked();
} else if (mVpnRunner != null) {
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 */);
- }
+ notifyVpnManagerVpnStopped(mPackage, mOwnerUID);
}
+
// cleanupVpnStateLocked() is called from mVpnRunner.exit()
mVpnRunner.exit();
}
@@ -4043,7 +4032,25 @@
// To stop the VPN profile, the caller must be the current prepared package and must be
// running an Ikev2VpnProfile.
if (isCurrentIkev2VpnLocked(packageName)) {
- prepareInternal(VpnConfig.LEGACY_VPN);
+ notifyVpnManagerVpnStopped(packageName, mOwnerUID);
+
+ mVpnRunner.exit();
+ }
+ }
+
+ private synchronized void notifyVpnManagerVpnStopped(String packageName, int ownerUID) {
+ mAppOpsManager.finishOp(
+ AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, ownerUID, packageName, 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*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
}
}
@@ -4085,6 +4092,20 @@
@NonNull List<String> excludedApps) {
enforceNotRestrictedUser();
if (!storeAppExclusionList(packageName, excludedApps)) return false;
+
+ updateAppExclusionList(excludedApps);
+
+ return true;
+ }
+
+ /**
+ * Triggers an update of the VPN network's excluded UIDs if a VPN is running.
+ */
+ public synchronized void refreshPlatformVpnAppExclusionList() {
+ updateAppExclusionList(getAppExclusionList(mPackage));
+ }
+
+ private synchronized void updateAppExclusionList(@NonNull List<String> excludedApps) {
// Re-build and update NetworkCapabilities via NetworkAgent.
if (mNetworkAgent != null) {
// Only update the platform VPN
@@ -4097,8 +4118,6 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
}
-
- return true;
}
/**
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a592192..59fae9e 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -200,7 +200,7 @@
}
private void handleMediaProjectionStoppedLocked(IBinder appToken) {
- VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
+ VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
if (device != null) {
Slog.i(TAG, "Virtual display device released because media projection stopped: "
+ device.mName);
diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS
index 426f002..7302f6e 100644
--- a/services/core/java/com/android/server/dreams/OWNERS
+++ b/services/core/java/com/android/server/dreams/OWNERS
@@ -1,3 +1,4 @@
+brycelee@google.com
dsandler@android.com
michaelwr@google.com
roosa@google.com
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 601a572..4631570 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -116,9 +116,9 @@
// 256-bit synthetic password
private static final byte SYNTHETIC_PASSWORD_LENGTH = 256 / 8;
- private static final int PASSWORD_SCRYPT_N = 11;
- private static final int PASSWORD_SCRYPT_R = 3;
- private static final int PASSWORD_SCRYPT_P = 1;
+ private static final int PASSWORD_SCRYPT_LOG_N = 11;
+ private static final int PASSWORD_SCRYPT_LOG_R = 3;
+ private static final int PASSWORD_SCRYPT_LOG_P = 1;
private static final int PASSWORD_SALT_LENGTH = 16;
private static final int PASSWORD_TOKEN_LENGTH = 32;
private static final String TAG = "SyntheticPasswordManager";
@@ -186,7 +186,11 @@
mVersion = version;
}
- private byte[] derivePassword(byte[] personalization) {
+ /**
+ * Derives a subkey from the synthetic password. For v3 and later synthetic passwords the
+ * subkeys are 256-bit; for v1 and v2 they are 512-bit.
+ */
+ private byte[] deriveSubkey(byte[] personalization) {
if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) {
return (new SP800Derive(mSyntheticPassword))
.withContext(personalization, PERSONALISATION_CONTEXT);
@@ -197,28 +201,28 @@
}
public byte[] deriveKeyStorePassword() {
- return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
+ return bytesToHex(deriveSubkey(PERSONALIZATION_KEY_STORE_PASSWORD));
}
public byte[] deriveGkPassword() {
- return derivePassword(PERSONALIZATION_SP_GK_AUTH);
+ return deriveSubkey(PERSONALIZATION_SP_GK_AUTH);
}
public byte[] deriveDiskEncryptionKey() {
- return derivePassword(PERSONALIZATION_FBE_KEY);
+ return deriveSubkey(PERSONALIZATION_FBE_KEY);
}
public byte[] deriveVendorAuthSecret() {
- return derivePassword(PERSONALIZATION_AUTHSECRET_KEY);
+ return deriveSubkey(PERSONALIZATION_AUTHSECRET_KEY);
}
public byte[] derivePasswordHashFactor() {
- return derivePassword(PERSONALIZATION_PASSWORD_HASH);
+ return deriveSubkey(PERSONALIZATION_PASSWORD_HASH);
}
/** Derives key used to encrypt password metrics */
public byte[] deriveMetricsKey() {
- return derivePassword(PERSONALIZATION_PASSWORD_METRICS);
+ return deriveSubkey(PERSONALIZATION_PASSWORD_METRICS);
}
/**
@@ -268,9 +272,8 @@
* AuthenticationToken.mSyntheticPassword for details on what each block means.
*/
private void recreate(byte[] escrowSplit0, byte[] escrowSplit1) {
- mSyntheticPassword = String.valueOf(HexEncoding.encode(
- SyntheticPasswordCrypto.personalisedHash(
- PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1))).getBytes();
+ mSyntheticPassword = bytesToHex(SyntheticPasswordCrypto.personalisedHash(
+ PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1));
}
/**
@@ -304,9 +307,9 @@
}
static class PasswordData {
- byte scryptN;
- byte scryptR;
- byte scryptP;
+ byte scryptLogN;
+ byte scryptLogR;
+ byte scryptLogP;
public int credentialType;
byte[] salt;
// For GateKeeper-based credential, this is the password handle returned by GK,
@@ -315,9 +318,9 @@
public static PasswordData create(int passwordType) {
PasswordData result = new PasswordData();
- result.scryptN = PASSWORD_SCRYPT_N;
- result.scryptR = PASSWORD_SCRYPT_R;
- result.scryptP = PASSWORD_SCRYPT_P;
+ result.scryptLogN = PASSWORD_SCRYPT_LOG_N;
+ result.scryptLogR = PASSWORD_SCRYPT_LOG_R;
+ result.scryptLogP = PASSWORD_SCRYPT_LOG_P;
result.credentialType = passwordType;
result.salt = secureRandom(PASSWORD_SALT_LENGTH);
return result;
@@ -329,9 +332,9 @@
buffer.put(data, 0, data.length);
buffer.flip();
result.credentialType = buffer.getInt();
- result.scryptN = buffer.get();
- result.scryptR = buffer.get();
- result.scryptP = buffer.get();
+ result.scryptLogN = buffer.get();
+ result.scryptLogR = buffer.get();
+ result.scryptLogP = buffer.get();
int saltLen = buffer.getInt();
result.salt = new byte[saltLen];
buffer.get(result.salt);
@@ -351,9 +354,9 @@
+ Integer.BYTES + salt.length + Integer.BYTES +
(passwordHandle != null ? passwordHandle.length : 0));
buffer.putInt(credentialType);
- buffer.put(scryptN);
- buffer.put(scryptR);
- buffer.put(scryptP);
+ buffer.put(scryptLogN);
+ buffer.put(scryptLogR);
+ buffer.put(scryptLogP);
buffer.putInt(salt.length);
buffer.put(salt);
if (passwordHandle != null && passwordHandle.length > 0) {
@@ -1369,8 +1372,8 @@
private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) {
final byte[] password = credential.isNone() ? DEFAULT_PASSWORD : credential.getCredential();
- return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
- PASSWORD_TOKEN_LENGTH);
+ return scrypt(password, data.salt, 1 << data.scryptLogN, 1 << data.scryptLogR,
+ 1 << data.scryptLogP, PASSWORD_TOKEN_LENGTH);
}
private byte[] passwordTokenToGkInput(byte[] token) {
@@ -1411,18 +1414,9 @@
return result;
}
- protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
- private static byte[] bytesToHex(byte[] bytes) {
- if (bytes == null) {
- return "null".getBytes();
- }
- byte[] hexBytes = new byte[bytes.length * 2];
- for ( int j = 0; j < bytes.length; j++ ) {
- int v = bytes[j] & 0xFF;
- hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
- hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
- }
- return hexBytes;
+ @VisibleForTesting
+ static byte[] bytesToHex(byte[] bytes) {
+ return HexEncoding.encodeToString(bytes).getBytes();
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 39d501b..d162ce2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15962,7 +15962,7 @@
final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
REASON_LOCKED_BOOT_COMPLETED);
am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
// Deliver BOOT_COMPLETED only if user is unlocked
@@ -15973,7 +15973,7 @@
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
}
} catch (RemoteException e) {
@@ -22869,7 +22869,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntentWithFeature(null, null, intent, null, null,
- 0, null, null, null, null, android.app.AppOpsManager.OP_NONE,
+ 0, null, null, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
}
@@ -28766,8 +28766,8 @@
};
try {
am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false,
- false, UserHandle.USER_ALL);
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, null,
+ false, false, UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 1ca7bcd..479701e 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -125,8 +125,11 @@
flags | StorageManager.FLAG_STORAGE_DE, false);
} else {
try {
- Log.e(TAG, "prepareUserData failed", e);
- RecoverySystem.rebootPromptAndWipeUserData(mContext, "prepareUserData failed");
+ Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
+ if (userId == UserHandle.USER_SYSTEM) {
+ RecoverySystem.rebootPromptAndWipeUserData(mContext,
+ "prepareUserData failed for system user");
+ }
} catch (IOException e2) {
throw new RuntimeException("error rebooting into recovery", e2);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index eb2de60..0e6d5e5 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -312,4 +312,12 @@
*/
public abstract void setDefaultCrossProfileIntentFilters(
@UserIdInt int parentUserId, @UserIdInt int profileUserId);
+
+ /**
+ * Returns {@code true} if the system should ignore errors when preparing
+ * the storage directories for the user with ID {@code userId}. This will
+ * return {@code false} for all new users; it will only return {@code true}
+ * for users that already existed on-disk from an older version of Android.
+ */
+ public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 374a5c2..af3dafc 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -204,6 +204,8 @@
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
"lastRequestQuietModeEnabledCall";
+ private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
+ "ignorePrepareStorageErrors";
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -313,6 +315,14 @@
private long mLastRequestQuietModeEnabledMillis;
+ /**
+ * {@code true} if the system should ignore errors when preparing the
+ * storage directories for this user. This is {@code false} for all new
+ * users; it will only be {@code true} for users that already existed
+ * on-disk from an older version of Android.
+ */
+ private boolean mIgnorePrepareStorageErrors;
+
void setLastRequestQuietModeEnabledMillis(long millis) {
mLastRequestQuietModeEnabledMillis = millis;
}
@@ -321,6 +331,14 @@
return mLastRequestQuietModeEnabledMillis;
}
+ boolean getIgnorePrepareStorageErrors() {
+ return mIgnorePrepareStorageErrors;
+ }
+
+ void setIgnorePrepareStorageErrors() {
+ mIgnorePrepareStorageErrors = true;
+ }
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -3180,6 +3198,10 @@
serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
}
+ serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+ serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
+ serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -3289,6 +3311,7 @@
Bundle legacyLocalRestrictions = null;
RestrictionsSet localRestrictions = null;
Bundle globalRestrictions = null;
+ boolean ignorePrepareStorageErrors = true; // default is true for old users
final TypedXmlPullParser parser = Xml.resolvePullParser(is);
int type;
@@ -3367,6 +3390,11 @@
if (type == XmlPullParser.TEXT) {
lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
}
+ } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
+ }
}
}
}
@@ -3394,6 +3422,9 @@
userData.persistSeedData = persistSeedData;
userData.seedAccountOptions = seedAccountOptions;
userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+ if (ignorePrepareStorageErrors) {
+ userData.setIgnorePrepareStorageErrors();
+ }
synchronized (mRestrictionsLock) {
if (baseRestrictions != null) {
@@ -5238,6 +5269,9 @@
pw.println();
}
}
+
+ pw.println(" Ignore errors preparing storage: "
+ + userData.getIgnorePrepareStorageErrors());
}
}
@@ -5727,6 +5761,14 @@
UserManagerService.this.setDefaultCrossProfileIntentFilters(
profileUserId, userTypeDetails, restrictions, parentUserId);
}
+
+ @Override
+ public boolean shouldIgnorePrepareStorageErrors(int userId) {
+ synchronized (mUsersLock) {
+ UserData userData = mUsers.get(userId);
+ return userData != null && userData.getIgnorePrepareStorageErrors();
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 290f4ae..336c27d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -5689,16 +5689,21 @@
appOpsManager.finishProxyOp(AppOpsManager.opToPublicName(op),
resolvedAttributionSource, skipCurrentFinish);
}
-
- if (next == null || next.getNext() == null) {
- return;
- }
-
RegisteredAttribution registered =
sRunningAttributionSources.remove(current.getToken());
if (registered != null) {
registered.unregister();
}
+
+ if (next == null || next.getNext() == null) {
+ if (next != null) {
+ registered = sRunningAttributionSources.remove(next.getToken());
+ if (registered != null) {
+ registered.unregister();
+ }
+ }
+ return;
+ }
current = next;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b184d5c..42c6dd43 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4193,17 +4193,17 @@
*/
@VisibleForTesting
SurfaceControl computeImeParent() {
- if (mImeLayeringTarget != null && mImeInputTarget != null
- && mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
- // Do not change parent if the window hasn't requested IME.
- return null;
- }
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
if (shouldImeAttachedToApp()) {
+ if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
+ // Do not change parent if the window hasn't requested IME.
+ return null;
+ }
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
}
+
// Otherwise, we just attach it to where the display area policy put it.
return mImeWindowsContainer.getParent() != null
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 5124841..10ae152 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -265,12 +265,14 @@
return state;
}
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
- // During switching tasks with gestural navigation, before the next IME input target
- // starts the input, we should adjust and freeze the last IME visibility of the window
- // in case delivering obsoleted IME insets state during transitioning.
+ // During switching tasks with gestural navigation, if the IME is attached to
+ // one app window on that time, even the next app window is behind the IME window,
+ // conceptually the window should not receive the IME insets if the next window is
+ // not eligible IME requester and ready to show IME on top of it.
+ final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
- if (originalImeSource != null) {
+ if (shouldImeAttachedToApp && originalImeSource != null) {
final boolean imeVisibility =
w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
final InsetsState state = copyState ? new InsetsState(originalState)
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index eeac230..027f3ae 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -68,6 +68,7 @@
final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
private final Handler mHandler;
private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
+ private boolean mIsFinishing;
private FinishedCallback mFinishedCallback;
private boolean mCanceled;
@@ -246,6 +247,7 @@
mPendingAnimations.size());
mHandler.removeCallbacks(mTimeoutRunnable);
synchronized (mService.mGlobalLock) {
+ mIsFinishing = true;
unlinkToDeathOfRunner();
releaseFinishedCallback();
mService.openSurfaceTransaction();
@@ -290,6 +292,7 @@
throw e;
} finally {
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
+ mIsFinishing = false;
}
}
setRunningRemoteAnimation(false);
@@ -501,6 +504,9 @@
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
+ if (mIsFinishing) {
+ return;
+ }
if (mRecord.mAdapter == this) {
mRecord.mAdapter = null;
} else {
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 2d4aef6..66d0230 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -25,7 +25,9 @@
import static android.app.WindowConfiguration.activityTypeToString;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -248,8 +250,25 @@
}
// Check if the caller is allowed to launch on the specified display area.
final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
- final TaskDisplayArea taskDisplayArea = daToken != null
+ TaskDisplayArea taskDisplayArea = daToken != null
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
+
+ // If we do not have a task display area token, check if the launch task display area
+ // feature id is specified.
+ if (taskDisplayArea == null) {
+ final int launchTaskDisplayAreaFeatureId = options.getLaunchTaskDisplayAreaFeatureId();
+ if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+ final int launchDisplayId = options.getLaunchDisplayId() == INVALID_DISPLAY
+ ? DEFAULT_DISPLAY : options.getLaunchDisplayId();
+ final DisplayContent dc = supervisor.mRootWindowContainer
+ .getDisplayContent(launchDisplayId);
+ if (dc != null) {
+ taskDisplayArea = dc.getItemFromTaskDisplayAreas(tda ->
+ tda.mFeatureId == launchTaskDisplayAreaFeatureId ? tda : null);
+ }
+ }
+ }
+
if (aInfo != null && taskDisplayArea != null
&& !supervisor.isCallerAllowedToLaunchOnTaskDisplayArea(callingPid, callingUid,
taskDisplayArea, aInfo)) {
diff --git a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
index e815a0e..92a538c 100644
--- a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
+++ b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
@@ -81,7 +81,7 @@
@SuppressWarnings("AndroidFrameworkCompatChange") // Target sdk check
public boolean isException(@NonNull String packageName, int targetSdk,
@Nullable Supplier<ApplicationInfo> infoSupplier) {
- if (targetSdk >= Build.VERSION_CODES.S) {
+ if (targetSdk > Build.VERSION_CODES.S_V2) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index b8ceb4a..24a745b 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -35,6 +35,7 @@
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static com.android.server.wm.ActivityStarter.Request;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -293,7 +294,8 @@
TaskDisplayArea taskDisplayArea = suggestedDisplayArea;
// If launch task display area is set in options we should just use it. We assume the
// suggestedDisplayArea has the right one in this case.
- if (options == null || options.getLaunchTaskDisplayArea() == null) {
+ if (options == null || (options.getLaunchTaskDisplayArea() == null
+ && options.getLaunchTaskDisplayAreaFeatureId() == FEATURE_UNDEFINED)) {
final int activityType =
mSupervisor.mRootWindowContainer.resolveActivityType(root, options, task);
display.forAllTaskDisplayAreas(displayArea -> {
@@ -377,7 +379,22 @@
if (optionLaunchTaskDisplayAreaToken != null) {
taskDisplayArea = (TaskDisplayArea) WindowContainer.fromBinder(
optionLaunchTaskDisplayAreaToken.asBinder());
- if (DEBUG) appendLog("display-area-from-option=" + taskDisplayArea);
+ if (DEBUG) appendLog("display-area-token-from-option=" + taskDisplayArea);
+ }
+
+ if (taskDisplayArea == null && options != null) {
+ final int launchTaskDisplayAreaFeatureId = options.getLaunchTaskDisplayAreaFeatureId();
+ if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
+ final int launchDisplayId = options.getLaunchDisplayId() == INVALID_DISPLAY
+ ? DEFAULT_DISPLAY : options.getLaunchDisplayId();
+ final DisplayContent dc = mSupervisor.mRootWindowContainer
+ .getDisplayContent(launchDisplayId);
+ if (dc != null) {
+ taskDisplayArea = dc.getItemFromTaskDisplayAreas(tda ->
+ tda.mFeatureId == launchTaskDisplayAreaFeatureId ? tda : null);
+ if (DEBUG) appendLog("display-area-feature-from-option=" + taskDisplayArea);
+ }
+ }
}
// If task display area is not specified in options - try display id
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
index c6b15c1..6bf6349 100644
--- a/services/net/java/android/net/ConnectivityModuleConnector.java
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -25,7 +25,6 @@
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.net.util.SharedLog;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
@@ -35,13 +34,13 @@
import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
-import java.io.PrintWriter;
/**
* Class used to communicate to the various networking mainline modules running in the network stack
@@ -73,8 +72,6 @@
private static ConnectivityModuleConnector sInstance;
private Context mContext;
- @GuardedBy("mLog")
- private final SharedLog mLog = new SharedLog(TAG);
@GuardedBy("mHealthListeners")
private final ArraySet<ConnectivityModuleHealthListener> mHealthListeners = new ArraySet<>();
@NonNull
@@ -384,38 +381,19 @@
}
private void log(@NonNull String message) {
- Slog.d(TAG, message);
- synchronized (mLog) {
- mLog.log(message);
- }
+ Log.d(TAG, message);
}
private void logWtf(@NonNull String message, @Nullable Throwable e) {
Slog.wtf(TAG, message, e);
- synchronized (mLog) {
- mLog.e(message);
- }
+ Log.e(TAG, message, e);
}
private void loge(@NonNull String message, @Nullable Throwable e) {
- Slog.e(TAG, message, e);
- synchronized (mLog) {
- mLog.e(message);
- }
+ Log.e(TAG, message, e);
}
private void logi(@NonNull String message) {
- Slog.i(TAG, message);
- synchronized (mLog) {
- mLog.i(message);
- }
- }
-
- /**
- * Dump ConnectivityModuleConnector logs to the specified {@link PrintWriter}.
- */
- public void dump(PrintWriter pw) {
- // dump is thread-safe on SharedLog
- mLog.dump(null, pw, null);
+ Log.i(TAG, message);
}
}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 865e3b8..b7eb5cd 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -25,19 +25,18 @@
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
-import android.net.util.SharedLog;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -61,9 +60,6 @@
@GuardedBy("mPendingNetStackRequests")
private INetworkStackConnector mConnector;
- @GuardedBy("mLog")
- private final SharedLog mLog = new SharedLog(TAG);
-
private volatile boolean mWasSystemServerInitialized = false;
private interface NetworkStackCallback {
@@ -237,34 +233,23 @@
}
/**
- * Log a message in the local log.
+ * Log a debug message.
*/
private void log(@NonNull String message) {
- synchronized (mLog) {
- mLog.log(message);
- }
+ Log.d(TAG, message);
}
private void logWtf(@NonNull String message, @Nullable Throwable e) {
Slog.wtf(TAG, message);
- synchronized (mLog) {
- mLog.e(message, e);
- }
+ Log.e(TAG, message, e);
}
private void loge(@NonNull String message, @Nullable Throwable e) {
- synchronized (mLog) {
- mLog.e(message, e);
- }
+ Log.e(TAG, message, e);
}
- /**
- * Log a message in the local and system logs.
- */
private void logi(@NonNull String message) {
- synchronized (mLog) {
- mLog.i(message);
- }
+ Log.i(TAG, message);
}
/**
@@ -320,22 +305,4 @@
request.onNetworkStackConnected(connector);
}
-
- /**
- * Dump NetworkStackClient logs to the specified {@link PrintWriter}.
- */
- public void dump(PrintWriter pw) {
- // dump is thread-safe on SharedLog
- mLog.dump(null, pw, null);
- // dump connectivity module connector logs.
- ConnectivityModuleConnector.getInstance().dump(pw);
-
- final int requestsQueueLength;
- synchronized (mPendingNetStackRequests) {
- requestsQueueLength = mPendingNetStackRequests.size();
- }
-
- pw.println();
- pw.println("pendingNetStackRequests length: " + requestsQueueLength);
- }
}
diff --git a/services/smartspace/OWNERS b/services/smartspace/OWNERS
index 19ef9d7..4d9a633 100644
--- a/services/smartspace/OWNERS
+++ b/services/smartspace/OWNERS
@@ -1,2 +1 @@
-srazdan@google.com
-alexmang@google.com
\ No newline at end of file
+include /core/java/android/service/smartspace/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index e9b5b62..f44104e 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -185,6 +185,7 @@
null /* resolvedType */,
null /* requiredPermissions */,
null /* excludedPermissions */,
+ null /* excludedPackages */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 1c49e6e..70853b6 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -298,7 +298,7 @@
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mIActivityManager, times(2)).broadcastIntentWithFeature(any(), any(),
intentArgumentCaptor.capture(), any(), any(), anyInt(), any(), any(), any(), any(),
- anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
+ any(), anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
List<Intent> capturedIntents = intentArgumentCaptor.getAllValues();
assertEquals(capturedIntents.get(0).getAction(), Intent.ACTION_LOCKED_BOOT_COMPLETED);
assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index c0a38b8..09d3b48 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -461,18 +461,18 @@
@Test
public void testPasswordData_serializeDeserialize() {
PasswordData data = new PasswordData();
- data.scryptN = 11;
- data.scryptR = 22;
- data.scryptP = 33;
+ data.scryptLogN = 11;
+ data.scryptLogR = 22;
+ data.scryptLogP = 33;
data.credentialType = CREDENTIAL_TYPE_PASSWORD;
data.salt = PAYLOAD;
data.passwordHandle = PAYLOAD2;
PasswordData deserialized = PasswordData.fromBytes(data.toBytes());
- assertEquals(11, deserialized.scryptN);
- assertEquals(22, deserialized.scryptR);
- assertEquals(33, deserialized.scryptP);
+ assertEquals(11, deserialized.scryptLogN);
+ assertEquals(22, deserialized.scryptLogR);
+ assertEquals(33, deserialized.scryptLogP);
assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.credentialType);
assertArrayEquals(PAYLOAD, deserialized.salt);
assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
@@ -484,9 +484,9 @@
// wire format.
byte[] serialized = new byte[] {
0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD_OR_PIN */
- 11, /* scryptN */
- 22, /* scryptR */
- 33, /* scryptP */
+ 11, /* scryptLogN */
+ 22, /* scryptLogR */
+ 33, /* scryptLogP */
0, 0, 0, 5, /* salt.length */
1, 2, -1, -2, 55, /* salt */
0, 0, 0, 6, /* passwordHandle.length */
@@ -494,9 +494,9 @@
};
PasswordData deserialized = PasswordData.fromBytes(serialized);
- assertEquals(11, deserialized.scryptN);
- assertEquals(22, deserialized.scryptR);
- assertEquals(33, deserialized.scryptP);
+ assertEquals(11, deserialized.scryptLogN);
+ assertEquals(22, deserialized.scryptLogR);
+ assertEquals(33, deserialized.scryptLogP);
assertEquals(CREDENTIAL_TYPE_PASSWORD_OR_PIN, deserialized.credentialType);
assertArrayEquals(PAYLOAD, deserialized.salt);
assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
@@ -567,6 +567,13 @@
}
}
+ @Test
+ public void testHexEncodingIsUppercase() {
+ final byte[] raw = new byte[] { (byte)0xAB, (byte)0xCD, (byte)0xEF };
+ final byte[] expected = new byte[] { 'A', 'B', 'C', 'D', 'E', 'F' };
+ assertArrayEquals(expected, SyntheticPasswordManager.bytesToHex(raw));
+ }
+
// b/62213311
//TODO: add non-migration work profile case, and unify/un-unify transition.
//TODO: test token after user resets password
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 32cee44..0d9c923 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2528,7 +2528,9 @@
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
"splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false);
testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
- testLegacySplashScreen(Build.VERSION_CODES.S, 0);
+ testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ testLegacySplashScreen(Build.VERSION_CODES.S_V2, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ testLegacySplashScreen(Build.VERSION_CODES.S_V2 + 1, 0);
} finally {
try {
DeviceConfig.setProperties(properties);
@@ -3065,11 +3067,11 @@
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
// keyguard to back to the app, expect IME insets is not frozen
- mDisplayContent.updateImeInputAndControlTarget(app);
- assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
imeSource.setFrame(new Rect(100, 400, 500, 500));
app.getInsetsState().addSource(imeSource);
app.getInsetsState().setSourceVisible(ITYPE_IME, true);
+ mDisplayContent.updateImeInputAndControlTarget(app);
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
// Verify when IME is visible and the app can receive the right IME insets from policy.
makeWindowVisibleAndDrawn(app, mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 9c0c213c..f3c1ec5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1075,21 +1075,6 @@
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
}
- @UseTestDisplay(addWindows = W_ACTIVITY)
- @Test
- public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
- WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
- WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
- doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
- mDisplayContent.setImeLayeringTarget(app1);
- mDisplayContent.setImeInputTarget(app1);
- assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
- mDisplayContent.setImeLayeringTarget(app2);
- // Expect null means no change IME parent when the IME layering target not yet
- // request IME to be the input target.
- assertNull(mDisplayContent.computeImeParent());
- }
-
@Test
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
final DisplayContent dc = createNewDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index 3714d99..b78675d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -80,13 +80,19 @@
public void packageFromDeviceConfigIgnored() {
setExceptionListAndWaitForCallback("com.test.nosplashscreen1,com.test.nosplashscreen2");
- assertIsException("com.test.nosplashscreen1", null);
- assertIsException("com.test.nosplashscreen2", null);
+ // In list, up to SC-V2 included
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.R);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.S);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.S_V2);
- assertIsNotException("com.test.nosplashscreen1", VERSION_CODES.S, null);
- assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.S, null);
- assertIsNotException("com.test.splashscreen", VERSION_CODES.S, null);
- assertIsNotException("com.test.splashscreen", VERSION_CODES.R, null);
+ // In list, after SC-V2
+ assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.S_V2 + 1);
+ assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.CUR_DEVELOPMENT);
+
+ // Not in list, up to SC-V2 included
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.R);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.S);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.S_V2);
}
private void setExceptionListAndWaitForCallback(String commaSeparatedList) {
@@ -123,16 +129,26 @@
metaData.putBoolean("android.splashscreen.exception_opt_out", true);
assertIsNotException(packageName, VERSION_CODES.R, activityInfo);
assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.S_V2, activityInfo);
- // Exception Pre S
+ // Exception up to T
metaData.putBoolean("android.splashscreen.exception_opt_out", false);
- assertIsException(packageName, activityInfo);
- assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
+ assertIsException(packageName, VERSION_CODES.R, activityInfo);
+ assertIsException(packageName, VERSION_CODES.S, activityInfo);
+ assertIsException(packageName, VERSION_CODES.S_V2, activityInfo);
+
+ // No Exception after T
+ assertIsNotException(packageName, VERSION_CODES.S_V2 + 1, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.CUR_DEVELOPMENT, activityInfo);
// Edge Cases
activityInfo.metaData = null;
- assertIsException(packageName, activityInfo);
- assertIsException(packageName, null);
+ assertIsException(packageName, VERSION_CODES.R, activityInfo);
+ assertIsException(packageName, VERSION_CODES.R);
+ }
+
+ private void assertIsNotException(String packageName, int targetSdk) {
+ assertIsNotException(packageName, targetSdk, null);
}
private void assertIsNotException(String packageName, int targetSdk,
@@ -142,10 +158,14 @@
mList.isException(packageName, targetSdk, () -> activityInfo));
}
- private void assertIsException(String packageName,
+ private void assertIsException(String packageName, int targetSdk) {
+ assertIsException(packageName, targetSdk, null);
+ }
+
+ private void assertIsException(String packageName, int targetSdk,
ApplicationInfo activityInfo) {
assertTrue(String.format("%s (sdk=%d) should have been considered as an exception",
- packageName, VERSION_CODES.R),
- mList.isException(packageName, VERSION_CODES.R, () -> activityInfo));
+ packageName, targetSdk),
+ mList.isException(packageName, targetSdk, () -> activityInfo));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 168c250..159d482 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -196,6 +196,28 @@
}
@Test
+ public void testUsesOptionsDisplayAreaFeatureIdIfSet() {
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FREEFORM);
+ final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+ ActivityRecord source = createSourceActivity(freeformDisplay);
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
+ options.setLaunchTaskDisplayAreaFeatureId(
+ fullscreenDisplay.getDefaultTaskDisplayArea().mFeatureId);
+
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
+
+ assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
+ mResult.mPreferredTaskDisplayArea);
+ }
+
+ @Test
public void testUsesSourcesDisplayAreaIdPriorToTaskIfSet() {
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
@@ -453,7 +475,7 @@
}
@Test
- public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayArea() {
+ public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaToken() {
final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
@@ -475,6 +497,52 @@
}
@Test
+ public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaFeatureId() {
+ final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
+ mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
+ launchRoot.mCreatedByOrganizer = true;
+
+ secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
+ new int[] { ACTIVITY_TYPE_STANDARD });
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskDisplayAreaFeatureId(
+ mDefaultDisplay.getDefaultTaskDisplayArea().mFeatureId);
+
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setOptions(options).calculate());
+
+ assertEquals(
+ mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
+ }
+
+ @Test
+ public void testUsesOptionsDisplayAreaFeatureIdDisplayIdNotSet() {
+ final TestDisplayContent secondaryDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FULLSCREEN);
+ final TaskDisplayArea tdaOnSecondaryDisplay = createTaskDisplayArea(secondaryDisplay,
+ mWm, "TestTaskDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+
+ final TaskDisplayArea tdaOnDefaultDisplay = createTaskDisplayArea(mDefaultDisplay,
+ mWm, "TestTaskDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+
+ mCurrent.mPreferredTaskDisplayArea = tdaOnSecondaryDisplay;
+ ActivityRecord source = createSourceActivity(tdaOnSecondaryDisplay,
+ WINDOWING_MODE_FULLSCREEN);
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskDisplayAreaFeatureId(tdaOnSecondaryDisplay.mFeatureId);
+
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
+ // Display id wasn't specified in ActivityOptions - the activity should be placed on the
+ // default display, into the TaskDisplayArea with the same feature id.
+ assertEquals(tdaOnDefaultDisplay, mResult.mPreferredTaskDisplayArea);
+ }
+
+ @Test
public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea() {
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
@@ -1822,6 +1890,13 @@
return new ActivityBuilder(mAtm).setTask(rootTask).build();
}
+ private ActivityRecord createSourceActivity(TaskDisplayArea taskDisplayArea,
+ int windowingMode) {
+ final Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
+ true);
+ return new ActivityBuilder(mAtm).setTask(rootTask).build();
+ }
+
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
final Task rootTask = display.getDefaultTaskDisplayArea()
.createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 03b8188..7d50135 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -931,47 +931,6 @@
@UseTestDisplay(addWindows = { W_ACTIVITY })
@Test
- public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
- final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
- ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
- final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
- spyOn(imeWindow);
- doReturn(true).when(imeWindow).isVisible();
- mDisplayContent.mInputMethodWindow = imeWindow;
-
- final InsetsStateController controller = mDisplayContent.getInsetsStateController();
- controller.getImeSourceProvider().setWindow(imeWindow, null, null);
-
- // Simulate app2 in multi-window mode is going to background to switch to the fullscreen
- // app which requests IME with updating all windows Insets State when IME is above app.
- app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
- mDisplayContent.setImeLayeringTarget(app);
- mDisplayContent.setImeInputTarget(app);
- assertTrue(mDisplayContent.shouldImeAttachedToApp());
- controller.getImeSourceProvider().scheduleShowImePostLayout(app);
- controller.getImeSourceProvider().getSource().setVisible(true);
- controller.updateAboveInsetsState(imeWindow, false);
-
- // Expect app windows behind IME can receive IME insets visible,
- // but not for app2 in background.
- assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
- assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
-
- // Simulate app plays closing transition to app2.
- // And app2 is now IME layering target but not yet to be the IME input target.
- mDisplayContent.setImeLayeringTarget(app2);
- app.mActivityRecord.commitVisibility(false, false);
- assertTrue(app.mActivityRecord.mLastImeShown);
- assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
-
- // Verify the IME insets is still visible on app, but not for app2 during task switching.
- assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
- assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
- }
-
- @UseTestDisplay(addWindows = {W_ACTIVITY})
- @Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
mAppWindow.mToken, "app");
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index af1d56a..610190e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -175,7 +175,11 @@
// Delay for debouncing USB disconnects.
// We often get rapid connect/disconnect events when enabling USB functions,
// which need debouncing.
- private static final int UPDATE_DELAY = 1000;
+ private static final int DEVICE_STATE_UPDATE_DELAY_EXT = 3000;
+ private static final int DEVICE_STATE_UPDATE_DELAY = 1000;
+
+ // Delay for debouncing USB disconnects on Type-C ports in host mode
+ private static final int HOST_STATE_UPDATE_DELAY = 1000;
// Timeout for entering USB request mode.
// Request is cancelled if host does not configure device within 10 seconds.
@@ -637,7 +641,9 @@
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
- sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
+ sendMessageDelayed(msg,
+ (connected == 0) ? (mScreenLocked ? DEVICE_STATE_UPDATE_DELAY
+ : DEVICE_STATE_UPDATE_DELAY_EXT) : 0);
}
public void updateHostState(UsbPort port, UsbPortStatus status) {
@@ -652,7 +658,7 @@
removeMessages(MSG_UPDATE_PORT_STATE);
Message msg = obtainMessage(MSG_UPDATE_PORT_STATE, args);
// debounce rapid transitions of connect/disconnect on type-c ports
- sendMessageDelayed(msg, UPDATE_DELAY);
+ sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
}
private void setAdbEnabled(boolean enable) {
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 85d59a2..9dfb0cc 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -361,7 +361,10 @@
return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid);
}
- private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+ /**
+ * @return Whether location is enabled for the given user.
+ */
+ public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
LocationManager locationManager = context.getSystemService(LocationManager.class);
if (locationManager == null) {
Log.w(TAG, "Couldn't get location manager, denying location access");
@@ -370,6 +373,14 @@
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
}
+ /**
+ * @return An array of packages that are always allowed to access location.
+ */
+ public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) {
+ return context.getResources().getStringArray(
+ com.android.internal.R.array.config_serviceStateLocationAllowedPackages);
+ }
+
private static boolean checkInteractAcrossUsersFull(
@NonNull Context context, int pid, int uid) {
return checkManifestPermission(context, pid, uid,
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index b5d97ab..c2a9864 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -4,8 +4,8 @@
import static android.telephony.ServiceState.DUPLEX_MODE_TDD;
import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
-import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency;
import android.telephony.AccessNetworkConstants.EutranBand;
+import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency;
import android.telephony.AccessNetworkConstants.GeranBand;
import android.telephony.AccessNetworkConstants.GeranBandArfcnFrequency;
import android.telephony.AccessNetworkConstants.NgranArfcnFrequency;
@@ -13,7 +13,6 @@
import android.telephony.AccessNetworkConstants.UtranBand;
import android.telephony.AccessNetworkConstants.UtranBandArfcnFrequency;
import android.telephony.ServiceState.DuplexMode;
-import android.util.Log;
import java.util.Arrays;
import java.util.HashSet;
@@ -232,6 +231,108 @@
}
/**
+ * Gets the NR Operating band for a given downlink NRARFCN.
+ *
+ * <p>See 3GPP TS 38.104 Table 5.2-1 NR operating bands in FR1 and
+ * Table 5.2-2 NR operating bands in FR2
+ *
+ * @param nrarfcn The downlink NRARFCN
+ * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+ */
+ public static int getOperatingBandForNrarfcn(int nrarfcn) {
+ if (nrarfcn >= 422000 && nrarfcn <= 434000) {
+ return NgranBands.BAND_1;
+ } else if (nrarfcn >= 386000 && nrarfcn <= 398000) {
+ return NgranBands.BAND_2;
+ } else if (nrarfcn >= 361000 && nrarfcn <= 376000) {
+ return NgranBands.BAND_3;
+ } else if (nrarfcn >= 173800 && nrarfcn <= 178800) {
+ return NgranBands.BAND_5;
+ } else if (nrarfcn >= 524000 && nrarfcn <= 538000) {
+ return NgranBands.BAND_7;
+ } else if (nrarfcn >= 185000 && nrarfcn <= 192000) {
+ return NgranBands.BAND_8;
+ } else if (nrarfcn >= 145800 && nrarfcn <= 149200) {
+ return NgranBands.BAND_12;
+ } else if (nrarfcn >= 151600 && nrarfcn <= 153600) {
+ return NgranBands.BAND_14;
+ } else if (nrarfcn >= 172000 && nrarfcn <= 175000) {
+ return NgranBands.BAND_18;
+ } else if (nrarfcn >= 158200 && nrarfcn <= 164200) {
+ return NgranBands.BAND_20;
+ } else if (nrarfcn >= 386000 && nrarfcn <= 399000) {
+ return NgranBands.BAND_25;
+ } else if (nrarfcn >= 171800 && nrarfcn <= 178800) {
+ return NgranBands.BAND_26;
+ } else if (nrarfcn >= 151600 && nrarfcn <= 160600) {
+ return NgranBands.BAND_28;
+ } else if (nrarfcn >= 143400 && nrarfcn <= 145600) {
+ return NgranBands.BAND_29;
+ } else if (nrarfcn >= 470000 && nrarfcn <= 472000) {
+ return NgranBands.BAND_30;
+ } else if (nrarfcn >= 402000 && nrarfcn <= 405000) {
+ return NgranBands.BAND_34;
+ } else if (nrarfcn >= 514000 && nrarfcn <= 524000) {
+ return NgranBands.BAND_38;
+ } else if (nrarfcn >= 376000 && nrarfcn <= 384000) {
+ return NgranBands.BAND_39;
+ } else if (nrarfcn >= 460000 && nrarfcn <= 480000) {
+ return NgranBands.BAND_40;
+ } else if (nrarfcn >= 499200 && nrarfcn <= 537999) {
+ return NgranBands.BAND_41;
+ } else if (nrarfcn >= 743334 && nrarfcn <= 795000) {
+ return NgranBands.BAND_46;
+ } else if (nrarfcn >= 636667 && nrarfcn <= 646666) {
+ return NgranBands.BAND_48;
+ } else if (nrarfcn >= 286400 && nrarfcn <= 303400) {
+ return NgranBands.BAND_50;
+ } else if (nrarfcn >= 285400 && nrarfcn <= 286400) {
+ return NgranBands.BAND_51;
+ } else if (nrarfcn >= 496700 && nrarfcn <= 499000) {
+ return NgranBands.BAND_53;
+ } else if (nrarfcn >= 422000 && nrarfcn <= 440000) {
+ return NgranBands.BAND_65; // BAND_66 has the same channels
+ } else if (nrarfcn >= 399000 && nrarfcn <= 404000) {
+ return NgranBands.BAND_70;
+ } else if (nrarfcn >= 123400 && nrarfcn <= 130400) {
+ return NgranBands.BAND_71;
+ } else if (nrarfcn >= 295000 && nrarfcn <= 303600) {
+ return NgranBands.BAND_74;
+ } else if (nrarfcn >= 286400 && nrarfcn <= 303400) {
+ return NgranBands.BAND_75;
+ } else if (nrarfcn >= 285400 && nrarfcn <= 286400) {
+ return NgranBands.BAND_76;
+ } else if (nrarfcn >= 620000 && nrarfcn <= 680000) {
+ return NgranBands.BAND_77;
+ } else if (nrarfcn >= 620000 && nrarfcn <= 653333) {
+ return NgranBands.BAND_78;
+ } else if (nrarfcn >= 693334 && nrarfcn <= 733333) {
+ return NgranBands.BAND_79;
+ } else if (nrarfcn >= 499200 && nrarfcn <= 538000) {
+ return NgranBands.BAND_90;
+ } else if (nrarfcn >= 285400 && nrarfcn <= 286400) {
+ return NgranBands.BAND_91;
+ } else if (nrarfcn >= 286400 && nrarfcn <= 303400) {
+ return NgranBands.BAND_92;
+ } else if (nrarfcn >= 285400 && nrarfcn <= 286400) {
+ return NgranBands.BAND_93;
+ } else if (nrarfcn >= 286400 && nrarfcn <= 303400) {
+ return NgranBands.BAND_94;
+ } else if (nrarfcn >= 795000 && nrarfcn <= 875000) {
+ return NgranBands.BAND_96;
+ } else if (nrarfcn >= 2054166 && nrarfcn <= 2104165) {
+ return NgranBands.BAND_257;
+ } else if (nrarfcn >= 2016667 && nrarfcn <= 2070832) {
+ return NgranBands.BAND_258;
+ } else if (nrarfcn >= 2229166 && nrarfcn <= 2279165) {
+ return NgranBands.BAND_260;
+ } else if (nrarfcn >= 2070833 && nrarfcn <= 2084999) {
+ return NgranBands.BAND_261;
+ }
+ return INVALID_BAND;
+ }
+
+ /**
* Gets the GERAN Operating band for a given ARFCN.
*
* <p>See 3GPP TS 45.005 clause 2 for calculation.