Merge "Add UpsideDownCake to aapt2 codenames and android.os.Build"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c5c6012..3a6b347 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,6 +17,14 @@
],
"presubmit": [
{
+ "name": "ManagedProvisioningTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
"name": "FrameworksUiServicesTests",
"options": [
{
diff --git a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
new file mode 100644
index 0000000..e0c12dd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+
+/**
+ * Tries to measure important BigInteger operations across a variety of BigInteger sizes. Note that
+ * BigInteger implementations commonly need to use wildly different algorithms for different sizes,
+ * so relative performance may change substantially depending on the size of the integer. This is
+ * not structured as a proper benchmark; just run main(), e.g. with vogar
+ * libcore/benchmarks/src/benchmarks/BigIntegerBenchmark.java.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BigIntegerPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ // A simple sum of products computation, mostly so we can check timing in the
+ // absence of any division. Computes the sum from 1 to n of ((10^prec) << 30) + 1)^2,
+ // repeating the multiplication, but not addition of 1, each time through the loop.
+ // Check the last few bits of the result as we go. Assumes n < 2^30.
+ // Note that we're actually squaring values in computing the product.
+ // That affects the algorithm used by some implementations.
+ private static void inner(int n, int prec) {
+ BigInteger big = BigInteger.TEN.pow(prec).shiftLeft(30).add(BigInteger.ONE);
+ BigInteger sum = BigInteger.ZERO;
+ for (int i = 0; i < n; ++i) {
+ sum = sum.add(big.multiply(big));
+ }
+ if (sum.and(BigInteger.valueOf(0x3fffffff)).intValue() != n) {
+ throw new AssertionError(
+ "inner() got " + sum.and(BigInteger.valueOf(0x3fffffff)) + " instead of " + n);
+ }
+ }
+
+ // Execute the above rep times, optionally timing it.
+ @Test
+ public void repeatInner() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 10; i <= 10_000; i *= 10) {
+ inner(100, i);
+ }
+ }
+ }
+
+ // Approximate the sum of the first 1000 terms of the harmonic series (sum of 1/m as m
+ // goes from 1 to n) to about prec digits. The result has an implicit decimal point
+ // prec digits from the right.
+ private static BigInteger harmonic1000(int prec) {
+ BigInteger scaledOne = BigInteger.TEN.pow(prec);
+ BigInteger sum = BigInteger.ZERO;
+ for (int i = 1; i <= 1000; ++i) {
+ sum = sum.add(scaledOne.divide(BigInteger.valueOf(i)));
+ }
+ return sum;
+ }
+
+ // Execute the above rep times, optionally timing it.
+ // Check results for equality, and print one, to compaare against reference.
+ @Test
+ public void repeatHarmonic1000() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 5; i <= 5_000; i *= 10) {
+ BigInteger refRes = harmonic1000(i);
+ BigInteger newRes = harmonic1000(i);
+ if (!newRes.equals(refRes)) {
+ throw new AssertionError(newRes + " != " + refRes);
+ }
+ if (i >= 50
+ && !refRes.toString()
+ .startsWith("748547086055034491265651820433390017652167916970")) {
+ throw new AssertionError("harmanic(" + i + ") incorrectly produced " + refRes);
+ }
+ }
+ }
+ }
+
+ // Repeatedly execute just the base conversion from the last test, allowing
+ // us to time and check it for consistency as well.
+ @Test
+ public void repeatToString() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 5; i <= 5_000; i *= 10) {
+ BigInteger refRes = harmonic1000(i);
+ String refString = refRes.toString();
+ // Disguise refRes to avoid compiler optimization issues.
+ BigInteger newRes = refRes.shiftLeft(30).add(BigInteger.valueOf(i)).shiftRight(30);
+ // The time-consuming part:
+ String newString = newRes.toString();
+ }
+ }
+ }
+
+ // Compute base^exp, where base and result are scaled/multiplied by scaleBy to make them
+ // integers. exp >= 0 .
+ private static BigInteger myPow(BigInteger base, int exp, BigInteger scaleBy) {
+ if (exp == 0) {
+ return scaleBy; // Return one.
+ } else if ((exp & 1) != 0) {
+ BigInteger tmp = myPow(base, exp - 1, scaleBy);
+ return tmp.multiply(base).divide(scaleBy);
+ } else {
+ BigInteger tmp = myPow(base, exp / 2, scaleBy);
+ return tmp.multiply(tmp).divide(scaleBy);
+ }
+ }
+
+ // Approximate e by computing (1 + 1/n)^n to prec decimal digits.
+ // This isn't necessarily a very good approximation to e.
+ // Return the result, scaled by 10^prec.
+ private static BigInteger eApprox(int n, int prec) {
+ BigInteger scaledOne = BigInteger.TEN.pow(prec);
+ BigInteger base = scaledOne.add(scaledOne.divide(BigInteger.valueOf(n)));
+ return myPow(base, n, scaledOne);
+ }
+
+ // Repeatedly execute and check the above, printing one of the results
+ // to compare to reference.
+ @Test
+ public void repeatEApprox() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 10; i <= 10_000; i *= 10) {
+ BigInteger refRes = eApprox(100_000, i);
+ BigInteger newRes = eApprox(100_000, i);
+ if (!newRes.equals(refRes)) {
+ throw new AssertionError(newRes + " != " + refRes);
+ }
+ if (i >= 10 && !refRes.toString().startsWith("271826")) {
+ throw new AssertionError(
+ "eApprox(" + 100_000 + "," + i + ") incorrectly produced " + refRes);
+ }
+ }
+ }
+ }
+
+ // Test / time modPow()
+ @Test
+ public void repeatModPow() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 5; i <= 500; i *= 10) {
+ BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
+ BigInteger odd2 = BigInteger.TEN.pow(i / 2).add(BigInteger.valueOf(17));
+ BigInteger product = odd1.multiply(odd2);
+ BigInteger exponent = BigInteger.TEN.pow(i / 2 - 1);
+ BigInteger base = BigInteger.TEN.pow(i / 4);
+ BigInteger newRes = base.modPow(exponent, product);
+ if (!newRes.mod(odd1).equals(base.modPow(exponent, odd1))) {
+ throw new AssertionError(
+ "ModPow() result incorrect mod odd1:"
+ + odd1
+ + "; lastRes.mod(odd1)="
+ + newRes.mod(odd1)
+ + " vs. "
+ + "base.modPow(exponent, odd1)="
+ + base.modPow(exponent, odd1)
+ + " base="
+ + base
+ + " exponent="
+ + exponent);
+ }
+ if (!newRes.mod(odd2).equals(base.modPow(exponent, odd2))) {
+ throw new AssertionError("ModPow() result incorrect mod odd2");
+ }
+ }
+ }
+ }
+
+ // Test / time modInverse()
+ @Test
+ public void repeatModInverse() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 10; i <= 10_000; i *= 10) {
+ BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
+ BigInteger odd2 = BigInteger.TEN.pow(i / 2).add(BigInteger.valueOf(17));
+ BigInteger product = odd1.multiply(odd2);
+ BigInteger arg = BigInteger.ONE.shiftLeft(i / 4);
+ BigInteger lastRes = null;
+ BigInteger newRes = arg.modInverse(product);
+ lastRes = newRes;
+ if (!lastRes.mod(odd1).equals(arg.modInverse(odd1))) {
+ throw new AssertionError("ModInverse() result incorrect mod odd1");
+ }
+ if (!lastRes.mod(odd2).equals(arg.modInverse(odd2))) {
+ throw new AssertionError("ModInverse() result incorrect mod odd2");
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
new file mode 100644
index 0000000..04ef09e4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.Random;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public final class BufferedZipFilePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ int[] mReadSize = new int[] {4, 32, 128};
+ int[] mCompressedSize = new int[] {128, 1024, 8192, 65536};
+ private File mFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mFile = File.createTempFile("BufferedZipFilePerfTest", ".zip");
+ mFile.deleteOnExit();
+ Random random = new Random(0);
+ ZipOutputStream out = new ZipOutputStream(new FileOutputStream(mFile));
+ for (int i = 0; i < mCompressedSize.length; i++) {
+ byte[] data = new byte[8192];
+ out.putNextEntry(new ZipEntry("entry.data" + mCompressedSize[i]));
+ int written = 0;
+ while (written < mCompressedSize[i]) {
+ random.nextBytes(data);
+ int toWrite = Math.min(mCompressedSize[i] - written, data.length);
+ out.write(data, 0, toWrite);
+ written += toWrite;
+ }
+ }
+ out.close();
+ }
+
+ @Test
+ public void timeUnbufferedRead() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mCompressedSize.length; i++) {
+ for (int j = 0; j < mReadSize.length; j++) {
+ ZipFile zipFile = new ZipFile(mFile);
+ ZipEntry entry = zipFile.getEntry("entry.data" + mCompressedSize[i]);
+ InputStream in = zipFile.getInputStream(entry);
+ byte[] buffer = new byte[mReadSize[j]];
+ while (in.read(buffer) != -1) {
+ // Keep reading
+ }
+ in.close();
+ zipFile.close();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void timeBufferedRead() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ for (int i = 0; i < mCompressedSize.length; i++) {
+ for (int j = 0; j < mReadSize.length; j++) {
+ ZipFile zipFile = new ZipFile(mFile);
+ ZipEntry entry = zipFile.getEntry("entry.data" + mCompressedSize[i]);
+ InputStream in = new BufferedInputStream(zipFile.getInputStream(entry));
+ byte[] buffer = new byte[mReadSize[j]];
+ while (in.read(buffer) != -1) {
+ // Keep reading
+ }
+ in.close();
+ zipFile.close();
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
new file mode 100644
index 0000000..4ae88b8
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ClassLoaderResourcePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final String EXISTENT_RESOURCE = "java/util/logging/logging.properties";
+ private static final String MISSING_RESOURCE = "missing_entry";
+
+ @Test
+ public void timeGetBootResource_hit() {
+ ClassLoader currentClassLoader = getClass().getClassLoader();
+ Assert.assertNotNull(currentClassLoader.getResource(EXISTENT_RESOURCE));
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ currentClassLoader.getResource(EXISTENT_RESOURCE);
+ }
+ }
+
+ @Test
+ public void timeGetBootResource_miss() {
+ ClassLoader currentClassLoader = getClass().getClassLoader();
+ Assert.assertNull(currentClassLoader.getResource(MISSING_RESOURCE));
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ currentClassLoader.getResource(MISSING_RESOURCE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
new file mode 100644
index 0000000..5e73916
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
@@ -0,0 +1,1197 @@
+/*
+ * 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;
+
+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 ClonePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ static class CloneableObject implements Cloneable {
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static class CloneableManyFieldObject implements Cloneable {
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ Object mO1 = new Object();
+ Object mO2 = new Object();
+ Object mO3 = new Object();
+ Object mO4 = new Object();
+ Object mO5 = new Object();
+ Object mO6 = new Object();
+ Object mO7 = new Object();
+ Object mO8 = new Object();
+ Object mO9 = new Object();
+ Object mO10 = new Object();
+ Object mO11 = new Object();
+ Object mO12 = new Object();
+ Object mO13 = new Object();
+ Object mO14 = new Object();
+ Object mO15 = new Object();
+ Object mO16 = new Object();
+ Object mO17 = new Object();
+ Object mO18 = new Object();
+ Object mO19 = new Object();
+ Object mO20 = new Object();
+ Object mO21 = new Object();
+ Object mO22 = new Object();
+ Object mO23 = new Object();
+ Object mO24 = new Object();
+ Object mO25 = new Object();
+ Object mO26 = new Object();
+ Object mO27 = new Object();
+ Object mO28 = new Object();
+ Object mO29 = new Object();
+ Object mO30 = new Object();
+ Object mO31 = new Object();
+ Object mO32 = new Object();
+ Object mO33 = new Object();
+ Object mO34 = new Object();
+ Object mO35 = new Object();
+ Object mO36 = new Object();
+ Object mO37 = new Object();
+ Object mO38 = new Object();
+ Object mO39 = new Object();
+ Object mO40 = new Object();
+ Object mO41 = new Object();
+ Object mO42 = new Object();
+ Object mO43 = new Object();
+ Object mO44 = new Object();
+ Object mO45 = new Object();
+ Object mO46 = new Object();
+ Object mO47 = new Object();
+ Object mO48 = new Object();
+ Object mO49 = new Object();
+ Object mO50 = new Object();
+ Object mO51 = new Object();
+ Object mO52 = new Object();
+ Object mO53 = new Object();
+ Object mO54 = new Object();
+ Object mO55 = new Object();
+ Object mO56 = new Object();
+ Object mO57 = new Object();
+ Object mO58 = new Object();
+ Object mO59 = new Object();
+ Object mO60 = new Object();
+ Object mO61 = new Object();
+ Object mO62 = new Object();
+ Object mO63 = new Object();
+ Object mO64 = new Object();
+ Object mO65 = new Object();
+ Object mO66 = new Object();
+ Object mO67 = new Object();
+ Object mO68 = new Object();
+ Object mO69 = new Object();
+ Object mO70 = new Object();
+ Object mO71 = new Object();
+ Object mO72 = new Object();
+ Object mO73 = new Object();
+ Object mO74 = new Object();
+ Object mO75 = new Object();
+ Object mO76 = new Object();
+ Object mO77 = new Object();
+ Object mO78 = new Object();
+ Object mO79 = new Object();
+ Object mO80 = new Object();
+ Object mO81 = new Object();
+ Object mO82 = new Object();
+ Object mO83 = new Object();
+ Object mO84 = new Object();
+ Object mO85 = new Object();
+ Object mO86 = new Object();
+ Object mO87 = new Object();
+ Object mO88 = new Object();
+ Object mO89 = new Object();
+ Object mO90 = new Object();
+ Object mO91 = new Object();
+ Object mO92 = new Object();
+ Object mO93 = new Object();
+ Object mO94 = new Object();
+ Object mO95 = new Object();
+ Object mO96 = new Object();
+ Object mO97 = new Object();
+ Object mO98 = new Object();
+ Object mO99 = new Object();
+ Object mO100 = new Object();
+ Object mO101 = new Object();
+ Object mO102 = new Object();
+ Object mO103 = new Object();
+ Object mO104 = new Object();
+ Object mO105 = new Object();
+ Object mO106 = new Object();
+ Object mO107 = new Object();
+ Object mO108 = new Object();
+ Object mO109 = new Object();
+ Object mO110 = new Object();
+ Object mO111 = new Object();
+ Object mO112 = new Object();
+ Object mO113 = new Object();
+ Object mO114 = new Object();
+ Object mO115 = new Object();
+ Object mO116 = new Object();
+ Object mO117 = new Object();
+ Object mO118 = new Object();
+ Object mO119 = new Object();
+ Object mO120 = new Object();
+ Object mO121 = new Object();
+ Object mO122 = new Object();
+ Object mO123 = new Object();
+ Object mO124 = new Object();
+ Object mO125 = new Object();
+ Object mO126 = new Object();
+ Object mO127 = new Object();
+ Object mO128 = new Object();
+ Object mO129 = new Object();
+ Object mO130 = new Object();
+ Object mO131 = new Object();
+ Object mO132 = new Object();
+ Object mO133 = new Object();
+ Object mO134 = new Object();
+ Object mO135 = new Object();
+ Object mO136 = new Object();
+ Object mO137 = new Object();
+ Object mO138 = new Object();
+ Object mO139 = new Object();
+ Object mO140 = new Object();
+ Object mO141 = new Object();
+ Object mO142 = new Object();
+ Object mO143 = new Object();
+ Object mO144 = new Object();
+ Object mO145 = new Object();
+ Object mO146 = new Object();
+ Object mO147 = new Object();
+ Object mO148 = new Object();
+ Object mO149 = new Object();
+ Object mO150 = new Object();
+ Object mO151 = new Object();
+ Object mO152 = new Object();
+ Object mO153 = new Object();
+ Object mO154 = new Object();
+ Object mO155 = new Object();
+ Object mO156 = new Object();
+ Object mO157 = new Object();
+ Object mO158 = new Object();
+ Object mO159 = new Object();
+ Object mO160 = new Object();
+ Object mO161 = new Object();
+ Object mO162 = new Object();
+ Object mO163 = new Object();
+ Object mO164 = new Object();
+ Object mO165 = new Object();
+ Object mO166 = new Object();
+ Object mO167 = new Object();
+ Object mO168 = new Object();
+ Object mO169 = new Object();
+ Object mO170 = new Object();
+ Object mO171 = new Object();
+ Object mO172 = new Object();
+ Object mO173 = new Object();
+ Object mO174 = new Object();
+ Object mO175 = new Object();
+ Object mO176 = new Object();
+ Object mO177 = new Object();
+ Object mO178 = new Object();
+ Object mO179 = new Object();
+ Object mO180 = new Object();
+ Object mO181 = new Object();
+ Object mO182 = new Object();
+ Object mO183 = new Object();
+ Object mO184 = new Object();
+ Object mO185 = new Object();
+ Object mO186 = new Object();
+ Object mO187 = new Object();
+ Object mO188 = new Object();
+ Object mO189 = new Object();
+ Object mO190 = new Object();
+ Object mO191 = new Object();
+ Object mO192 = new Object();
+ Object mO193 = new Object();
+ Object mO194 = new Object();
+ Object mO195 = new Object();
+ Object mO196 = new Object();
+ Object mO197 = new Object();
+ Object mO198 = new Object();
+ Object mO199 = new Object();
+ Object mO200 = new Object();
+ Object mO201 = new Object();
+ Object mO202 = new Object();
+ Object mO203 = new Object();
+ Object mO204 = new Object();
+ Object mO205 = new Object();
+ Object mO206 = new Object();
+ Object mO207 = new Object();
+ Object mO208 = new Object();
+ Object mO209 = new Object();
+ Object mO210 = new Object();
+ Object mO211 = new Object();
+ Object mO212 = new Object();
+ Object mO213 = new Object();
+ Object mO214 = new Object();
+ Object mO215 = new Object();
+ Object mO216 = new Object();
+ Object mO217 = new Object();
+ Object mO218 = new Object();
+ Object mO219 = new Object();
+ Object mO220 = new Object();
+ Object mO221 = new Object();
+ Object mO222 = new Object();
+ Object mO223 = new Object();
+ Object mO224 = new Object();
+ Object mO225 = new Object();
+ Object mO226 = new Object();
+ Object mO227 = new Object();
+ Object mO228 = new Object();
+ Object mO229 = new Object();
+ Object mO230 = new Object();
+ Object mO231 = new Object();
+ Object mO232 = new Object();
+ Object mO233 = new Object();
+ Object mO234 = new Object();
+ Object mO235 = new Object();
+ Object mO236 = new Object();
+ Object mO237 = new Object();
+ Object mO238 = new Object();
+ Object mO239 = new Object();
+ Object mO240 = new Object();
+ Object mO241 = new Object();
+ Object mO242 = new Object();
+ Object mO243 = new Object();
+ Object mO244 = new Object();
+ Object mO245 = new Object();
+ Object mO246 = new Object();
+ Object mO247 = new Object();
+ Object mO248 = new Object();
+ Object mO249 = new Object();
+ Object mO250 = new Object();
+ Object mO251 = new Object();
+ Object mO252 = new Object();
+ Object mO253 = new Object();
+ Object mO254 = new Object();
+ Object mO255 = new Object();
+ Object mO256 = new Object();
+ Object mO257 = new Object();
+ Object mO258 = new Object();
+ Object mO259 = new Object();
+ Object mO260 = new Object();
+ Object mO261 = new Object();
+ Object mO262 = new Object();
+ Object mO263 = new Object();
+ Object mO264 = new Object();
+ Object mO265 = new Object();
+ Object mO266 = new Object();
+ Object mO267 = new Object();
+ Object mO268 = new Object();
+ Object mO269 = new Object();
+ Object mO270 = new Object();
+ Object mO271 = new Object();
+ Object mO272 = new Object();
+ Object mO273 = new Object();
+ Object mO274 = new Object();
+ Object mO275 = new Object();
+ Object mO276 = new Object();
+ Object mO277 = new Object();
+ Object mO278 = new Object();
+ Object mO279 = new Object();
+ Object mO280 = new Object();
+ Object mO281 = new Object();
+ Object mO282 = new Object();
+ Object mO283 = new Object();
+ Object mO284 = new Object();
+ Object mO285 = new Object();
+ Object mO286 = new Object();
+ Object mO287 = new Object();
+ Object mO288 = new Object();
+ Object mO289 = new Object();
+ Object mO290 = new Object();
+ Object mO291 = new Object();
+ Object mO292 = new Object();
+ Object mO293 = new Object();
+ Object mO294 = new Object();
+ Object mO295 = new Object();
+ Object mO296 = new Object();
+ Object mO297 = new Object();
+ Object mO298 = new Object();
+ Object mO299 = new Object();
+ Object mO300 = new Object();
+ Object mO301 = new Object();
+ Object mO302 = new Object();
+ Object mO303 = new Object();
+ Object mO304 = new Object();
+ Object mO305 = new Object();
+ Object mO306 = new Object();
+ Object mO307 = new Object();
+ Object mO308 = new Object();
+ Object mO309 = new Object();
+ Object mO310 = new Object();
+ Object mO311 = new Object();
+ Object mO312 = new Object();
+ Object mO313 = new Object();
+ Object mO314 = new Object();
+ Object mO315 = new Object();
+ Object mO316 = new Object();
+ Object mO317 = new Object();
+ Object mO318 = new Object();
+ Object mO319 = new Object();
+ Object mO320 = new Object();
+ Object mO321 = new Object();
+ Object mO322 = new Object();
+ Object mO323 = new Object();
+ Object mO324 = new Object();
+ Object mO325 = new Object();
+ Object mO326 = new Object();
+ Object mO327 = new Object();
+ Object mO328 = new Object();
+ Object mO329 = new Object();
+ Object mO330 = new Object();
+ Object mO331 = new Object();
+ Object mO332 = new Object();
+ Object mO333 = new Object();
+ Object mO334 = new Object();
+ Object mO335 = new Object();
+ Object mO336 = new Object();
+ Object mO337 = new Object();
+ Object mO338 = new Object();
+ Object mO339 = new Object();
+ Object mO340 = new Object();
+ Object mO341 = new Object();
+ Object mO342 = new Object();
+ Object mO343 = new Object();
+ Object mO344 = new Object();
+ Object mO345 = new Object();
+ Object mO346 = new Object();
+ Object mO347 = new Object();
+ Object mO348 = new Object();
+ Object mO349 = new Object();
+ Object mO350 = new Object();
+ Object mO351 = new Object();
+ Object mO352 = new Object();
+ Object mO353 = new Object();
+ Object mO354 = new Object();
+ Object mO355 = new Object();
+ Object mO356 = new Object();
+ Object mO357 = new Object();
+ Object mO358 = new Object();
+ Object mO359 = new Object();
+ Object mO360 = new Object();
+ Object mO361 = new Object();
+ Object mO362 = new Object();
+ Object mO363 = new Object();
+ Object mO364 = new Object();
+ Object mO365 = new Object();
+ Object mO366 = new Object();
+ Object mO367 = new Object();
+ Object mO368 = new Object();
+ Object mO369 = new Object();
+ Object mO370 = new Object();
+ Object mO371 = new Object();
+ Object mO372 = new Object();
+ Object mO373 = new Object();
+ Object mO374 = new Object();
+ Object mO375 = new Object();
+ Object mO376 = new Object();
+ Object mO377 = new Object();
+ Object mO378 = new Object();
+ Object mO379 = new Object();
+ Object mO380 = new Object();
+ Object mO381 = new Object();
+ Object mO382 = new Object();
+ Object mO383 = new Object();
+ Object mO384 = new Object();
+ Object mO385 = new Object();
+ Object mO386 = new Object();
+ Object mO387 = new Object();
+ Object mO388 = new Object();
+ Object mO389 = new Object();
+ Object mO390 = new Object();
+ Object mO391 = new Object();
+ Object mO392 = new Object();
+ Object mO393 = new Object();
+ Object mO394 = new Object();
+ Object mO395 = new Object();
+ Object mO396 = new Object();
+ Object mO397 = new Object();
+ Object mO398 = new Object();
+ Object mO399 = new Object();
+ Object mO400 = new Object();
+ Object mO401 = new Object();
+ Object mO402 = new Object();
+ Object mO403 = new Object();
+ Object mO404 = new Object();
+ Object mO405 = new Object();
+ Object mO406 = new Object();
+ Object mO407 = new Object();
+ Object mO408 = new Object();
+ Object mO409 = new Object();
+ Object mO410 = new Object();
+ Object mO411 = new Object();
+ Object mO412 = new Object();
+ Object mO413 = new Object();
+ Object mO414 = new Object();
+ Object mO415 = new Object();
+ Object mO416 = new Object();
+ Object mO417 = new Object();
+ Object mO418 = new Object();
+ Object mO419 = new Object();
+ Object mO420 = new Object();
+ Object mO421 = new Object();
+ Object mO422 = new Object();
+ Object mO423 = new Object();
+ Object mO424 = new Object();
+ Object mO425 = new Object();
+ Object mO426 = new Object();
+ Object mO427 = new Object();
+ Object mO428 = new Object();
+ Object mO429 = new Object();
+ Object mO430 = new Object();
+ Object mO431 = new Object();
+ Object mO432 = new Object();
+ Object mO433 = new Object();
+ Object mO434 = new Object();
+ Object mO435 = new Object();
+ Object mO436 = new Object();
+ Object mO437 = new Object();
+ Object mO438 = new Object();
+ Object mO439 = new Object();
+ Object mO440 = new Object();
+ Object mO441 = new Object();
+ Object mO442 = new Object();
+ Object mO460 = new Object();
+ Object mO461 = new Object();
+ Object mO462 = new Object();
+ Object mO463 = new Object();
+ Object mO464 = new Object();
+ Object mO465 = new Object();
+ Object mO466 = new Object();
+ Object mO467 = new Object();
+ Object mO468 = new Object();
+ Object mO469 = new Object();
+ Object mO470 = new Object();
+ Object mO471 = new Object();
+ Object mO472 = new Object();
+ Object mO473 = new Object();
+ Object mO474 = new Object();
+ Object mO475 = new Object();
+ Object mO476 = new Object();
+ Object mO477 = new Object();
+ Object mO478 = new Object();
+ Object mO479 = new Object();
+ Object mO480 = new Object();
+ Object mO481 = new Object();
+ Object mO482 = new Object();
+ Object mO483 = new Object();
+ Object mO484 = new Object();
+ Object mO485 = new Object();
+ Object mO486 = new Object();
+ Object mO487 = new Object();
+ Object mO488 = new Object();
+ Object mO489 = new Object();
+ Object mO490 = new Object();
+ Object mO491 = new Object();
+ Object mO492 = new Object();
+ Object mO493 = new Object();
+ Object mO494 = new Object();
+ Object mO495 = new Object();
+ Object mO496 = new Object();
+ Object mO497 = new Object();
+ Object mO498 = new Object();
+ Object mO499 = new Object();
+ Object mO500 = new Object();
+ Object mO501 = new Object();
+ Object mO502 = new Object();
+ Object mO503 = new Object();
+ Object mO504 = new Object();
+ Object mO505 = new Object();
+ Object mO506 = new Object();
+ Object mO507 = new Object();
+ Object mO508 = new Object();
+ Object mO509 = new Object();
+ Object mO510 = new Object();
+ Object mO511 = new Object();
+ Object mO512 = new Object();
+ Object mO513 = new Object();
+ Object mO514 = new Object();
+ Object mO515 = new Object();
+ Object mO516 = new Object();
+ Object mO517 = new Object();
+ Object mO518 = new Object();
+ Object mO519 = new Object();
+ Object mO520 = new Object();
+ Object mO521 = new Object();
+ Object mO522 = new Object();
+ Object mO523 = new Object();
+ Object mO556 = new Object();
+ Object mO557 = new Object();
+ Object mO558 = new Object();
+ Object mO559 = new Object();
+ Object mO560 = new Object();
+ Object mO561 = new Object();
+ Object mO562 = new Object();
+ Object mO563 = new Object();
+ Object mO564 = new Object();
+ Object mO565 = new Object();
+ Object mO566 = new Object();
+ Object mO567 = new Object();
+ Object mO568 = new Object();
+ Object mO569 = new Object();
+ Object mO570 = new Object();
+ Object mO571 = new Object();
+ Object mO572 = new Object();
+ Object mO573 = new Object();
+ Object mO574 = new Object();
+ Object mO575 = new Object();
+ Object mO576 = new Object();
+ Object mO577 = new Object();
+ Object mO578 = new Object();
+ Object mO579 = new Object();
+ Object mO580 = new Object();
+ Object mO581 = new Object();
+ Object mO582 = new Object();
+ Object mO583 = new Object();
+ Object mO584 = new Object();
+ Object mO585 = new Object();
+ Object mO586 = new Object();
+ Object mO587 = new Object();
+ Object mO588 = new Object();
+ Object mO589 = new Object();
+ Object mO590 = new Object();
+ Object mO591 = new Object();
+ Object mO592 = new Object();
+ Object mO593 = new Object();
+ Object mO594 = new Object();
+ Object mO595 = new Object();
+ Object mO596 = new Object();
+ Object mO597 = new Object();
+ Object mO598 = new Object();
+ Object mO599 = new Object();
+ Object mO600 = new Object();
+ Object mO601 = new Object();
+ Object mO602 = new Object();
+ Object mO603 = new Object();
+ Object mO604 = new Object();
+ Object mO605 = new Object();
+ Object mO606 = new Object();
+ Object mO607 = new Object();
+ Object mO608 = new Object();
+ Object mO609 = new Object();
+ Object mO610 = new Object();
+ Object mO611 = new Object();
+ Object mO612 = new Object();
+ Object mO613 = new Object();
+ Object mO614 = new Object();
+ Object mO615 = new Object();
+ Object mO616 = new Object();
+ Object mO617 = new Object();
+ Object mO618 = new Object();
+ Object mO619 = new Object();
+ Object mO620 = new Object();
+ Object mO621 = new Object();
+ Object mO622 = new Object();
+ Object mO623 = new Object();
+ Object mO624 = new Object();
+ Object mO625 = new Object();
+ Object mO626 = new Object();
+ Object mO627 = new Object();
+ Object mO628 = new Object();
+ Object mO629 = new Object();
+ Object mO630 = new Object();
+ Object mO631 = new Object();
+ Object mO632 = new Object();
+ Object mO633 = new Object();
+ Object mO634 = new Object();
+ Object mO635 = new Object();
+ Object mO636 = new Object();
+ Object mO637 = new Object();
+ Object mO638 = new Object();
+ Object mO639 = new Object();
+ Object mO640 = new Object();
+ Object mO641 = new Object();
+ Object mO642 = new Object();
+ Object mO643 = new Object();
+ Object mO644 = new Object();
+ Object mO645 = new Object();
+ Object mO646 = new Object();
+ Object mO647 = new Object();
+ Object mO648 = new Object();
+ Object mO649 = new Object();
+ Object mO650 = new Object();
+ Object mO651 = new Object();
+ Object mO652 = new Object();
+ Object mO653 = new Object();
+ Object mO654 = new Object();
+ Object mO655 = new Object();
+ Object mO656 = new Object();
+ Object mO657 = new Object();
+ Object mO658 = new Object();
+ Object mO659 = new Object();
+ Object mO660 = new Object();
+ Object mO661 = new Object();
+ Object mO662 = new Object();
+ Object mO663 = new Object();
+ Object mO664 = new Object();
+ Object mO665 = new Object();
+ Object mO666 = new Object();
+ Object mO667 = new Object();
+ Object mO668 = new Object();
+ Object mO669 = new Object();
+ Object mO670 = new Object();
+ Object mO671 = new Object();
+ Object mO672 = new Object();
+ Object mO673 = new Object();
+ Object mO674 = new Object();
+ Object mO675 = new Object();
+ Object mO676 = new Object();
+ Object mO677 = new Object();
+ Object mO678 = new Object();
+ Object mO679 = new Object();
+ Object mO680 = new Object();
+ Object mO681 = new Object();
+ Object mO682 = new Object();
+ Object mO683 = new Object();
+ Object mO684 = new Object();
+ Object mO685 = new Object();
+ Object mO686 = new Object();
+ Object mO687 = new Object();
+ Object mO688 = new Object();
+ Object mO734 = new Object();
+ Object mO735 = new Object();
+ Object mO736 = new Object();
+ Object mO737 = new Object();
+ Object mO738 = new Object();
+ Object mO739 = new Object();
+ Object mO740 = new Object();
+ Object mO741 = new Object();
+ Object mO742 = new Object();
+ Object mO743 = new Object();
+ Object mO744 = new Object();
+ Object mO745 = new Object();
+ Object mO746 = new Object();
+ Object mO747 = new Object();
+ Object mO748 = new Object();
+ Object mO749 = new Object();
+ Object mO750 = new Object();
+ Object mO751 = new Object();
+ Object mO752 = new Object();
+ Object mO753 = new Object();
+ Object mO754 = new Object();
+ Object mO755 = new Object();
+ Object mO756 = new Object();
+ Object mO757 = new Object();
+ Object mO758 = new Object();
+ Object mO759 = new Object();
+ Object mO760 = new Object();
+ Object mO761 = new Object();
+ Object mO762 = new Object();
+ Object mO763 = new Object();
+ Object mO764 = new Object();
+ Object mO765 = new Object();
+ Object mO766 = new Object();
+ Object mO767 = new Object();
+ Object mO768 = new Object();
+ Object mO769 = new Object();
+ Object mO770 = new Object();
+ Object mO771 = new Object();
+ Object mO772 = new Object();
+ Object mO773 = new Object();
+ Object mO774 = new Object();
+ Object mO775 = new Object();
+ Object mO776 = new Object();
+ Object mO777 = new Object();
+ Object mO778 = new Object();
+ Object mO779 = new Object();
+ Object mO780 = new Object();
+ Object mO781 = new Object();
+ Object mO782 = new Object();
+ Object mO783 = new Object();
+ Object mO784 = new Object();
+ Object mO785 = new Object();
+ Object mO786 = new Object();
+ Object mO787 = new Object();
+ Object mO788 = new Object();
+ Object mO789 = new Object();
+ Object mO790 = new Object();
+ Object mO791 = new Object();
+ Object mO792 = new Object();
+ Object mO793 = new Object();
+ Object mO794 = new Object();
+ Object mO795 = new Object();
+ Object mO796 = new Object();
+ Object mO797 = new Object();
+ Object mO798 = new Object();
+ Object mO799 = new Object();
+ Object mO800 = new Object();
+ Object mO801 = new Object();
+ Object mO802 = new Object();
+ Object mO803 = new Object();
+ Object mO804 = new Object();
+ Object mO805 = new Object();
+ Object mO806 = new Object();
+ Object mO807 = new Object();
+ Object mO808 = new Object();
+ Object mO809 = new Object();
+ Object mO810 = new Object();
+ Object mO811 = new Object();
+ Object mO812 = new Object();
+ Object mO813 = new Object();
+ Object mO848 = new Object();
+ Object mO849 = new Object();
+ Object mO850 = new Object();
+ Object mO851 = new Object();
+ Object mO852 = new Object();
+ Object mO853 = new Object();
+ Object mO854 = new Object();
+ Object mO855 = new Object();
+ Object mO856 = new Object();
+ Object mO857 = new Object();
+ Object mO858 = new Object();
+ Object mO859 = new Object();
+ Object mO860 = new Object();
+ Object mO861 = new Object();
+ Object mO862 = new Object();
+ Object mO863 = new Object();
+ Object mO864 = new Object();
+ Object mO865 = new Object();
+ Object mO866 = new Object();
+ Object mO867 = new Object();
+ Object mO868 = new Object();
+ Object mO869 = new Object();
+ Object mO870 = new Object();
+ Object mO871 = new Object();
+ Object mO872 = new Object();
+ Object mO873 = new Object();
+ Object mO874 = new Object();
+ Object mO875 = new Object();
+ Object mO876 = new Object();
+ Object mO877 = new Object();
+ Object mO878 = new Object();
+ Object mO879 = new Object();
+ Object mO880 = new Object();
+ Object mO881 = new Object();
+ Object mO882 = new Object();
+ Object mO883 = new Object();
+ Object mO884 = new Object();
+ Object mO885 = new Object();
+ Object mO886 = new Object();
+ Object mO887 = new Object();
+ Object mO888 = new Object();
+ Object mO889 = new Object();
+ Object mO890 = new Object();
+ Object mO891 = new Object();
+ Object mO892 = new Object();
+ Object mO893 = new Object();
+ Object mO894 = new Object();
+ Object mO895 = new Object();
+ Object mO896 = new Object();
+ Object mO897 = new Object();
+ Object mO898 = new Object();
+ Object mO899 = new Object();
+ Object mO900 = new Object();
+ Object mO901 = new Object();
+ Object mO902 = new Object();
+ Object mO903 = new Object();
+ Object mO904 = new Object();
+ Object mO905 = new Object();
+ Object mO906 = new Object();
+ Object mO907 = new Object();
+ Object mO908 = new Object();
+ Object mO909 = new Object();
+ Object mO910 = new Object();
+ Object mO911 = new Object();
+ Object mO912 = new Object();
+ Object mO913 = new Object();
+ Object mO914 = new Object();
+ Object mO915 = new Object();
+ Object mO916 = new Object();
+ Object mO917 = new Object();
+ Object mO918 = new Object();
+ Object mO919 = new Object();
+ Object mO920 = new Object();
+ Object mO921 = new Object();
+ Object mO922 = new Object();
+ Object mO923 = new Object();
+ Object mO924 = new Object();
+ Object mO925 = new Object();
+ Object mO926 = new Object();
+ Object mO927 = new Object();
+ Object mO928 = new Object();
+ Object mO929 = new Object();
+ Object mO930 = new Object();
+ Object mO931 = new Object();
+ Object mO932 = new Object();
+ Object mO933 = new Object();
+ Object mO934 = new Object();
+ Object mO935 = new Object();
+ Object mO936 = new Object();
+ Object mO937 = new Object();
+ Object mO938 = new Object();
+ Object mO939 = new Object();
+ Object mO940 = new Object();
+ Object mO941 = new Object();
+ Object mO942 = new Object();
+ Object mO943 = new Object();
+ Object mO944 = new Object();
+ Object mO945 = new Object();
+ Object mO946 = new Object();
+ Object mO947 = new Object();
+ Object mO948 = new Object();
+ Object mO949 = new Object();
+ Object mO950 = new Object();
+ Object mO951 = new Object();
+ Object mO952 = new Object();
+ Object mO953 = new Object();
+ Object mO954 = new Object();
+ Object mO955 = new Object();
+ Object mO956 = new Object();
+ Object mO957 = new Object();
+ Object mO958 = new Object();
+ Object mO959 = new Object();
+ Object mO960 = new Object();
+ Object mO961 = new Object();
+ Object mO962 = new Object();
+ Object mO963 = new Object();
+ Object mO964 = new Object();
+ Object mO965 = new Object();
+ Object mO966 = new Object();
+ Object mO967 = new Object();
+ Object mO968 = new Object();
+ Object mO969 = new Object();
+ Object mO970 = new Object();
+ Object mO971 = new Object();
+ Object mO972 = new Object();
+ Object mO973 = new Object();
+ Object mO974 = new Object();
+ Object mO975 = new Object();
+ Object mO976 = new Object();
+ Object mO977 = new Object();
+ Object mO978 = new Object();
+ Object mO979 = new Object();
+ Object mO980 = new Object();
+ Object mO981 = new Object();
+ Object mO982 = new Object();
+ Object mO983 = new Object();
+ Object mO984 = new Object();
+ Object mO985 = new Object();
+ Object mO986 = new Object();
+ Object mO987 = new Object();
+ Object mO988 = new Object();
+ Object mO989 = new Object();
+ Object mO990 = new Object();
+ Object mO991 = new Object();
+ Object mO992 = new Object();
+ Object mO993 = new Object();
+ Object mO994 = new Object();
+ Object mO995 = new Object();
+ Object mO996 = new Object();
+ Object mO997 = new Object();
+ Object mO998 = new Object();
+ Object mO999 = new Object();
+ }
+
+ static class Deep0 {}
+
+ static class Deep1 extends Deep0 {}
+
+ static class Deep2 extends Deep1 {}
+
+ static class Deep3 extends Deep2 {}
+
+ static class Deep4 extends Deep3 {}
+
+ static class Deep5 extends Deep4 {}
+
+ static class Deep6 extends Deep5 {}
+
+ static class Deep7 extends Deep6 {}
+
+ static class Deep8 extends Deep7 {}
+
+ static class Deep9 extends Deep8 {}
+
+ static class Deep10 extends Deep9 {}
+
+ static class Deep11 extends Deep10 {}
+
+ static class Deep12 extends Deep11 {}
+
+ static class Deep13 extends Deep12 {}
+
+ static class Deep14 extends Deep13 {}
+
+ static class Deep15 extends Deep14 {}
+
+ static class Deep16 extends Deep15 {}
+
+ static class Deep17 extends Deep16 {}
+
+ static class Deep18 extends Deep17 {}
+
+ static class Deep19 extends Deep18 {}
+
+ static class Deep20 extends Deep19 {}
+
+ static class Deep21 extends Deep20 {}
+
+ static class Deep22 extends Deep21 {}
+
+ static class Deep23 extends Deep22 {}
+
+ static class Deep24 extends Deep23 {}
+
+ static class Deep25 extends Deep24 {}
+
+ static class Deep26 extends Deep25 {}
+
+ static class Deep27 extends Deep26 {}
+
+ static class Deep28 extends Deep27 {}
+
+ static class Deep29 extends Deep28 {}
+
+ static class Deep30 extends Deep29 {}
+
+ static class Deep31 extends Deep30 {}
+
+ static class Deep32 extends Deep31 {}
+
+ static class Deep33 extends Deep32 {}
+
+ static class Deep34 extends Deep33 {}
+
+ static class Deep35 extends Deep34 {}
+
+ static class Deep36 extends Deep35 {}
+
+ static class Deep37 extends Deep36 {}
+
+ static class Deep38 extends Deep37 {}
+
+ static class Deep39 extends Deep38 {}
+
+ static class Deep40 extends Deep39 {}
+
+ static class Deep41 extends Deep40 {}
+
+ static class Deep42 extends Deep41 {}
+
+ static class Deep43 extends Deep42 {}
+
+ static class Deep44 extends Deep43 {}
+
+ static class Deep45 extends Deep44 {}
+
+ static class Deep46 extends Deep45 {}
+
+ static class Deep47 extends Deep46 {}
+
+ static class Deep48 extends Deep47 {}
+
+ static class Deep49 extends Deep48 {}
+
+ static class Deep50 extends Deep49 {}
+
+ static class Deep51 extends Deep50 {}
+
+ static class Deep52 extends Deep51 {}
+
+ static class Deep53 extends Deep52 {}
+
+ static class Deep54 extends Deep53 {}
+
+ static class Deep55 extends Deep54 {}
+
+ static class Deep56 extends Deep55 {}
+
+ static class Deep57 extends Deep56 {}
+
+ static class Deep58 extends Deep57 {}
+
+ static class Deep59 extends Deep58 {}
+
+ static class Deep60 extends Deep59 {}
+
+ static class Deep61 extends Deep60 {}
+
+ static class Deep62 extends Deep61 {}
+
+ static class Deep63 extends Deep62 {}
+
+ static class Deep64 extends Deep63 {}
+
+ static class Deep65 extends Deep64 {}
+
+ static class Deep66 extends Deep65 {}
+
+ static class Deep67 extends Deep66 {}
+
+ static class Deep68 extends Deep67 {}
+
+ static class Deep69 extends Deep68 {}
+
+ static class Deep70 extends Deep69 {}
+
+ static class Deep71 extends Deep70 {}
+
+ static class Deep72 extends Deep71 {}
+
+ static class Deep73 extends Deep72 {}
+
+ static class Deep74 extends Deep73 {}
+
+ static class Deep75 extends Deep74 {}
+
+ static class Deep76 extends Deep75 {}
+
+ static class Deep77 extends Deep76 {}
+
+ static class Deep78 extends Deep77 {}
+
+ static class Deep79 extends Deep78 {}
+
+ static class Deep80 extends Deep79 {}
+
+ static class Deep81 extends Deep80 {}
+
+ static class Deep82 extends Deep81 {}
+
+ static class Deep83 extends Deep82 {}
+
+ static class Deep84 extends Deep83 {}
+
+ static class Deep85 extends Deep84 {}
+
+ static class Deep86 extends Deep85 {}
+
+ static class Deep87 extends Deep86 {}
+
+ static class Deep88 extends Deep87 {}
+
+ static class Deep89 extends Deep88 {}
+
+ static class Deep90 extends Deep89 {}
+
+ static class Deep91 extends Deep90 {}
+
+ static class Deep92 extends Deep91 {}
+
+ static class Deep93 extends Deep92 {}
+
+ static class Deep94 extends Deep93 {}
+
+ static class Deep95 extends Deep94 {}
+
+ static class Deep96 extends Deep95 {}
+
+ static class Deep97 extends Deep96 {}
+
+ static class Deep98 extends Deep97 {}
+
+ static class Deep99 extends Deep98 {}
+
+ static class Deep100 extends Deep99 {}
+
+ static class DeepCloneable extends Deep100 implements Cloneable {
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ @Test
+ public void time_Object_clone() {
+ try {
+ CloneableObject o = new CloneableObject();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ } catch (Exception e) {
+ throw new AssertionError(e.getMessage());
+ }
+ }
+
+ @Test
+ public void time_Object_manyFieldClone() {
+ try {
+ CloneableManyFieldObject o = new CloneableManyFieldObject();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ } catch (Exception e) {
+ throw new AssertionError(e.getMessage());
+ }
+ }
+
+ @Test
+ public void time_Object_deepClone() {
+ try {
+ DeepCloneable o = new DeepCloneable();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ } catch (Exception e) {
+ throw new AssertionError(e.getMessage());
+ }
+ }
+
+ @Test
+ public void time_Array_clone() {
+ int[] o = new int[32];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ }
+
+ @Test
+ public void time_ObjectArray_smallClone() {
+ Object[] o = new Object[32];
+ for (int i = 0; i < o.length / 2; ++i) {
+ o[i] = new Object();
+ }
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ }
+
+ @Test
+ public void time_ObjectArray_largeClone() {
+ Object[] o = new Object[2048];
+ for (int i = 0; i < o.length / 2; ++i) {
+ o[i] = new Object();
+ }
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ o.clone();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
new file mode 100644
index 0000000..3f4f6af
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class DeepArrayOpsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Object[] mArray;
+ private Object[] mArray2;
+
+ @Parameterized.Parameter(0)
+ public int mArrayLength;
+
+ @Parameterized.Parameters(name = "mArrayLength({0})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{1}, {4}, {16}, {32}, {2048}});
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mArray = new Object[mArrayLength * 14];
+ mArray2 = new Object[mArrayLength * 14];
+ for (int i = 0; i < mArrayLength; i += 14) {
+ mArray[i] = new IntWrapper(i);
+ mArray2[i] = new IntWrapper(i);
+
+ mArray[i + 1] = new16ElementObjectmArray();
+ mArray2[i + 1] = new16ElementObjectmArray();
+
+ mArray[i + 2] = new boolean[16];
+ mArray2[i + 2] = new boolean[16];
+
+ mArray[i + 3] = new byte[16];
+ mArray2[i + 3] = new byte[16];
+
+ mArray[i + 4] = new char[16];
+ mArray2[i + 4] = new char[16];
+
+ mArray[i + 5] = new short[16];
+ mArray2[i + 5] = new short[16];
+
+ mArray[i + 6] = new float[16];
+ mArray2[i + 6] = new float[16];
+
+ mArray[i + 7] = new long[16];
+ mArray2[i + 7] = new long[16];
+
+ mArray[i + 8] = new int[16];
+ mArray2[i + 8] = new int[16];
+
+ mArray[i + 9] = new double[16];
+ mArray2[i + 9] = new double[16];
+
+ // SubmArray types are concrete objects.
+ mArray[i + 10] = new16ElementArray(String.class, String.class);
+ mArray2[i + 10] = new16ElementArray(String.class, String.class);
+
+ mArray[i + 11] = new16ElementArray(Integer.class, Integer.class);
+ mArray2[i + 11] = new16ElementArray(Integer.class, Integer.class);
+
+ // SubmArray types is an interface.
+ mArray[i + 12] = new16ElementArray(CharSequence.class, String.class);
+ mArray2[i + 12] = new16ElementArray(CharSequence.class, String.class);
+
+ mArray[i + 13] = null;
+ mArray2[i + 13] = null;
+ }
+ }
+
+ @Test
+ public void deepHashCode() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Arrays.deepHashCode(mArray);
+ }
+ }
+
+ @Test
+ public void deepEquals() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Arrays.deepEquals(mArray, mArray2);
+ }
+ }
+
+ private static Object[] new16ElementObjectmArray() {
+ Object[] array = new Object[16];
+ for (int i = 0; i < 16; ++i) {
+ array[i] = new IntWrapper(i);
+ }
+
+ return array;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T, V> T[] new16ElementArray(Class<T> mArrayType, Class<V> type)
+ throws Exception {
+ T[] array = (T[]) Array.newInstance(type, 16);
+ if (!mArrayType.isAssignableFrom(type)) {
+ throw new IllegalArgumentException(mArrayType + " is not assignable from " + type);
+ }
+
+ Constructor<V> constructor = type.getDeclaredConstructor(String.class);
+ for (int i = 0; i < 16; ++i) {
+ array[i] = (T) constructor.newInstance(String.valueOf(i + 1000));
+ }
+
+ return array;
+ }
+
+ /**
+ * A class that provides very basic equals() and hashCode() operations and doesn't resort to
+ * memoization tricks like {@link java.lang.Integer}.
+ *
+ * <p>Useful for providing equal objects that aren't the same (a.equals(b) but a != b).
+ */
+ public static final class IntWrapper {
+ private final int mWrapped;
+
+ public IntWrapper(int wrap) {
+ mWrapped = wrap;
+ }
+
+ @Override
+ public int hashCode() {
+ return mWrapped;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof IntWrapper)) {
+ return false;
+ }
+
+ return ((IntWrapper) o).mWrapped == this.mWrapped;
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
new file mode 100644
index 0000000..da94ae1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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;
+
+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;
+
+/** What does field access cost? */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class FieldAccessPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static class Inner {
+ public int mPublicInnerIntVal;
+ protected int mProtectedInnerIntVal;
+ private int mPrivateInnerIntVal;
+ int mPackageInnerIntVal;
+ }
+
+ int mIntVal = 42;
+ final int mFinalIntVal = 42;
+ static int sStaticIntVal = 42;
+ static final int FINAL_INT_VAL = 42;
+
+ @Test
+ public void timeField() {
+ int result = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = mIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldFinal() {
+ int result = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = mFinalIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldStatic() {
+ int result = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = sStaticIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldStaticFinal() {
+ int result = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = FINAL_INT_VAL;
+ }
+ }
+
+ @Test
+ public void timeFieldCached() {
+ int result = 0;
+ int cachedIntVal = this.mIntVal;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = cachedIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldPrivateInnerClassPublicField() {
+ int result = 0;
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = inner.mPublicInnerIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldPrivateInnerClassProtectedField() {
+ int result = 0;
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = inner.mProtectedInnerIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldPrivateInnerClassPrivateField() {
+ int result = 0;
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = inner.mPrivateInnerIntVal;
+ }
+ }
+
+ @Test
+ public void timeFieldPrivateInnerClassPackageField() {
+ int result = 0;
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = inner.mPackageInnerIntVal;
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
new file mode 100644
index 0000000..9446d99c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+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.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** How do the various hash maps compare? */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class HashedCollectionsPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeHashMapGet() {
+ HashMap<String, String> map = new HashMap<String, String>();
+ map.put("hello", "world");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.get("hello");
+ }
+ }
+
+ @Test
+ public void timeHashMapGet_Synchronized() {
+ HashMap<String, String> map = new HashMap<String, String>();
+ synchronized (map) {
+ map.put("hello", "world");
+ }
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ synchronized (map) {
+ map.get("hello");
+ }
+ }
+ }
+
+ @Test
+ public void timeHashtableGet() {
+ Hashtable<String, String> map = new Hashtable<String, String>();
+ map.put("hello", "world");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.get("hello");
+ }
+ }
+
+ @Test
+ public void timeLinkedHashMapGet() {
+ LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
+ map.put("hello", "world");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.get("hello");
+ }
+ }
+
+ @Test
+ public void timeConcurrentHashMapGet() {
+ ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
+ map.put("hello", "world");
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.get("hello");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
new file mode 100644
index 0000000..be2a7e9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
@@ -0,0 +1,1818 @@
+/*
+ * Copyright 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This file is script-generated by ImtConflictPerfTestGen.py. It measures the performance impact of
+ * conflicts in interface method tables. Run `python ImtConflictPerfTestGen.py >
+ * ImtConflictPerfTest.java` to regenerate.
+ *
+ * <p>Each interface has 64 methods, which is the current size of an IMT. C0 implements one
+ * interface, C1 implements two, C2 implements three, and so on. The intent is that C0 has no
+ * conflicts in its IMT, C1 has depth-2 conflicts in its IMT, C2 has depth-3 conflicts, etc. This is
+ * currently guaranteed by the fact that we hash interface methods by taking their method index
+ * modulo 64. (Note that a "conflict depth" of 1 means no conflict at all.)
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ImtConflictPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Before
+ public void setup() {
+ C0 c0 = new C0();
+ callF0(c0);
+ C1 c1 = new C1();
+ callF0(c1);
+ callF19(c1);
+ C2 c2 = new C2();
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ C3 c3 = new C3();
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ C4 c4 = new C4();
+ callF0(c4);
+ callF19(c4);
+ callF38(c4);
+ callF57(c4);
+ callF76(c4);
+ C5 c5 = new C5();
+ callF0(c5);
+ callF19(c5);
+ callF38(c5);
+ callF57(c5);
+ callF76(c5);
+ callF95(c5);
+ C6 c6 = new C6();
+ callF0(c6);
+ callF19(c6);
+ callF38(c6);
+ callF57(c6);
+ callF76(c6);
+ callF95(c6);
+ callF114(c6);
+ C7 c7 = new C7();
+ callF0(c7);
+ callF19(c7);
+ callF38(c7);
+ callF57(c7);
+ callF76(c7);
+ callF95(c7);
+ callF114(c7);
+ callF133(c7);
+ C8 c8 = new C8();
+ callF0(c8);
+ callF19(c8);
+ callF38(c8);
+ callF57(c8);
+ callF76(c8);
+ callF95(c8);
+ callF114(c8);
+ callF133(c8);
+ callF152(c8);
+ C9 c9 = new C9();
+ callF0(c9);
+ callF19(c9);
+ callF38(c9);
+ callF57(c9);
+ callF76(c9);
+ callF95(c9);
+ callF114(c9);
+ callF133(c9);
+ callF152(c9);
+ callF171(c9);
+ C10 c10 = new C10();
+ callF0(c10);
+ callF19(c10);
+ callF38(c10);
+ callF57(c10);
+ callF76(c10);
+ callF95(c10);
+ callF114(c10);
+ callF133(c10);
+ callF152(c10);
+ callF171(c10);
+ callF190(c10);
+ C11 c11 = new C11();
+ callF0(c11);
+ callF19(c11);
+ callF38(c11);
+ callF57(c11);
+ callF76(c11);
+ callF95(c11);
+ callF114(c11);
+ callF133(c11);
+ callF152(c11);
+ callF171(c11);
+ callF190(c11);
+ callF209(c11);
+ C12 c12 = new C12();
+ callF0(c12);
+ callF19(c12);
+ callF38(c12);
+ callF57(c12);
+ callF76(c12);
+ callF95(c12);
+ callF114(c12);
+ callF133(c12);
+ callF152(c12);
+ callF171(c12);
+ callF190(c12);
+ callF209(c12);
+ callF228(c12);
+ C13 c13 = new C13();
+ callF0(c13);
+ callF19(c13);
+ callF38(c13);
+ callF57(c13);
+ callF76(c13);
+ callF95(c13);
+ callF114(c13);
+ callF133(c13);
+ callF152(c13);
+ callF171(c13);
+ callF190(c13);
+ callF209(c13);
+ callF228(c13);
+ callF247(c13);
+ C14 c14 = new C14();
+ callF0(c14);
+ callF19(c14);
+ callF38(c14);
+ callF57(c14);
+ callF76(c14);
+ callF95(c14);
+ callF114(c14);
+ callF133(c14);
+ callF152(c14);
+ callF171(c14);
+ callF190(c14);
+ callF209(c14);
+ callF228(c14);
+ callF247(c14);
+ callF266(c14);
+ C15 c15 = new C15();
+ callF0(c15);
+ callF19(c15);
+ callF38(c15);
+ callF57(c15);
+ callF76(c15);
+ callF95(c15);
+ callF114(c15);
+ callF133(c15);
+ callF152(c15);
+ callF171(c15);
+ callF190(c15);
+ callF209(c15);
+ callF228(c15);
+ callF247(c15);
+ callF266(c15);
+ callF285(c15);
+ C16 c16 = new C16();
+ callF0(c16);
+ callF19(c16);
+ callF38(c16);
+ callF57(c16);
+ callF76(c16);
+ callF95(c16);
+ callF114(c16);
+ callF133(c16);
+ callF152(c16);
+ callF171(c16);
+ callF190(c16);
+ callF209(c16);
+ callF228(c16);
+ callF247(c16);
+ callF266(c16);
+ callF285(c16);
+ callF304(c16);
+ C17 c17 = new C17();
+ callF0(c17);
+ callF19(c17);
+ callF38(c17);
+ callF57(c17);
+ callF76(c17);
+ callF95(c17);
+ callF114(c17);
+ callF133(c17);
+ callF152(c17);
+ callF171(c17);
+ callF190(c17);
+ callF209(c17);
+ callF228(c17);
+ callF247(c17);
+ callF266(c17);
+ callF285(c17);
+ callF304(c17);
+ callF323(c17);
+ C18 c18 = new C18();
+ callF0(c18);
+ callF19(c18);
+ callF38(c18);
+ callF57(c18);
+ callF76(c18);
+ callF95(c18);
+ callF114(c18);
+ callF133(c18);
+ callF152(c18);
+ callF171(c18);
+ callF190(c18);
+ callF209(c18);
+ callF228(c18);
+ callF247(c18);
+ callF266(c18);
+ callF285(c18);
+ callF304(c18);
+ callF323(c18);
+ callF342(c18);
+ C19 c19 = new C19();
+ callF0(c19);
+ callF19(c19);
+ callF38(c19);
+ callF57(c19);
+ callF76(c19);
+ callF95(c19);
+ callF114(c19);
+ callF133(c19);
+ callF152(c19);
+ callF171(c19);
+ callF190(c19);
+ callF209(c19);
+ callF228(c19);
+ callF247(c19);
+ callF266(c19);
+ callF285(c19);
+ callF304(c19);
+ callF323(c19);
+ callF342(c19);
+ callF361(c19);
+ }
+
+ @Test
+ public void timeConflictDepth01() {
+ C0 c0 = new C0();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ callF0(c0);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth02() {
+ C1 c1 = new C1();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ callF0(c1);
+ callF19(c1);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth03() {
+ C2 c2 = new C2();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ callF38(c2);
+ callF0(c2);
+ callF19(c2);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth04() {
+ C3 c3 = new C3();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ callF0(c3);
+ callF19(c3);
+ callF38(c3);
+ callF57(c3);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth05() {
+ C4 c4 = new C4();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c4);
+ callF19(c4);
+ callF38(c4);
+ callF57(c4);
+ callF76(c4);
+ callF0(c4);
+ callF19(c4);
+ callF38(c4);
+ callF57(c4);
+ callF76(c4);
+ callF0(c4);
+ callF19(c4);
+ callF38(c4);
+ callF57(c4);
+ callF76(c4);
+ callF0(c4);
+ callF19(c4);
+ callF38(c4);
+ callF57(c4);
+ callF76(c4);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth06() {
+ C5 c5 = new C5();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c5);
+ callF19(c5);
+ callF38(c5);
+ callF57(c5);
+ callF76(c5);
+ callF95(c5);
+ callF0(c5);
+ callF19(c5);
+ callF38(c5);
+ callF57(c5);
+ callF76(c5);
+ callF95(c5);
+ callF0(c5);
+ callF19(c5);
+ callF38(c5);
+ callF57(c5);
+ callF76(c5);
+ callF95(c5);
+ callF0(c5);
+ callF19(c5);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth07() {
+ C6 c6 = new C6();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c6);
+ callF19(c6);
+ callF38(c6);
+ callF57(c6);
+ callF76(c6);
+ callF95(c6);
+ callF114(c6);
+ callF0(c6);
+ callF19(c6);
+ callF38(c6);
+ callF57(c6);
+ callF76(c6);
+ callF95(c6);
+ callF114(c6);
+ callF0(c6);
+ callF19(c6);
+ callF38(c6);
+ callF57(c6);
+ callF76(c6);
+ callF95(c6);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth08() {
+ C7 c7 = new C7();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c7);
+ callF19(c7);
+ callF38(c7);
+ callF57(c7);
+ callF76(c7);
+ callF95(c7);
+ callF114(c7);
+ callF133(c7);
+ callF0(c7);
+ callF19(c7);
+ callF38(c7);
+ callF57(c7);
+ callF76(c7);
+ callF95(c7);
+ callF114(c7);
+ callF133(c7);
+ callF0(c7);
+ callF19(c7);
+ callF38(c7);
+ callF57(c7);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth09() {
+ C8 c8 = new C8();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c8);
+ callF19(c8);
+ callF38(c8);
+ callF57(c8);
+ callF76(c8);
+ callF95(c8);
+ callF114(c8);
+ callF133(c8);
+ callF152(c8);
+ callF0(c8);
+ callF19(c8);
+ callF38(c8);
+ callF57(c8);
+ callF76(c8);
+ callF95(c8);
+ callF114(c8);
+ callF133(c8);
+ callF152(c8);
+ callF0(c8);
+ callF19(c8);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth10() {
+ C9 c9 = new C9();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c9);
+ callF19(c9);
+ callF38(c9);
+ callF57(c9);
+ callF76(c9);
+ callF95(c9);
+ callF114(c9);
+ callF133(c9);
+ callF152(c9);
+ callF171(c9);
+ callF0(c9);
+ callF19(c9);
+ callF38(c9);
+ callF57(c9);
+ callF76(c9);
+ callF95(c9);
+ callF114(c9);
+ callF133(c9);
+ callF152(c9);
+ callF171(c9);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth11() {
+ C10 c10 = new C10();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c10);
+ callF19(c10);
+ callF38(c10);
+ callF57(c10);
+ callF76(c10);
+ callF95(c10);
+ callF114(c10);
+ callF133(c10);
+ callF152(c10);
+ callF171(c10);
+ callF190(c10);
+ callF0(c10);
+ callF19(c10);
+ callF38(c10);
+ callF57(c10);
+ callF76(c10);
+ callF95(c10);
+ callF114(c10);
+ callF133(c10);
+ callF152(c10);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth12() {
+ C11 c11 = new C11();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c11);
+ callF19(c11);
+ callF38(c11);
+ callF57(c11);
+ callF76(c11);
+ callF95(c11);
+ callF114(c11);
+ callF133(c11);
+ callF152(c11);
+ callF171(c11);
+ callF190(c11);
+ callF209(c11);
+ callF0(c11);
+ callF19(c11);
+ callF38(c11);
+ callF57(c11);
+ callF76(c11);
+ callF95(c11);
+ callF114(c11);
+ callF133(c11);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth13() {
+ C12 c12 = new C12();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c12);
+ callF19(c12);
+ callF38(c12);
+ callF57(c12);
+ callF76(c12);
+ callF95(c12);
+ callF114(c12);
+ callF133(c12);
+ callF152(c12);
+ callF171(c12);
+ callF190(c12);
+ callF209(c12);
+ callF228(c12);
+ callF0(c12);
+ callF19(c12);
+ callF38(c12);
+ callF57(c12);
+ callF76(c12);
+ callF95(c12);
+ callF114(c12);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth14() {
+ C13 c13 = new C13();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c13);
+ callF19(c13);
+ callF38(c13);
+ callF57(c13);
+ callF76(c13);
+ callF95(c13);
+ callF114(c13);
+ callF133(c13);
+ callF152(c13);
+ callF171(c13);
+ callF190(c13);
+ callF209(c13);
+ callF228(c13);
+ callF247(c13);
+ callF0(c13);
+ callF19(c13);
+ callF38(c13);
+ callF57(c13);
+ callF76(c13);
+ callF95(c13);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth15() {
+ C14 c14 = new C14();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c14);
+ callF19(c14);
+ callF38(c14);
+ callF57(c14);
+ callF76(c14);
+ callF95(c14);
+ callF114(c14);
+ callF133(c14);
+ callF152(c14);
+ callF171(c14);
+ callF190(c14);
+ callF209(c14);
+ callF228(c14);
+ callF247(c14);
+ callF266(c14);
+ callF0(c14);
+ callF19(c14);
+ callF38(c14);
+ callF57(c14);
+ callF76(c14);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth16() {
+ C15 c15 = new C15();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c15);
+ callF19(c15);
+ callF38(c15);
+ callF57(c15);
+ callF76(c15);
+ callF95(c15);
+ callF114(c15);
+ callF133(c15);
+ callF152(c15);
+ callF171(c15);
+ callF190(c15);
+ callF209(c15);
+ callF228(c15);
+ callF247(c15);
+ callF266(c15);
+ callF285(c15);
+ callF0(c15);
+ callF19(c15);
+ callF38(c15);
+ callF57(c15);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth17() {
+ C16 c16 = new C16();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c16);
+ callF19(c16);
+ callF38(c16);
+ callF57(c16);
+ callF76(c16);
+ callF95(c16);
+ callF114(c16);
+ callF133(c16);
+ callF152(c16);
+ callF171(c16);
+ callF190(c16);
+ callF209(c16);
+ callF228(c16);
+ callF247(c16);
+ callF266(c16);
+ callF285(c16);
+ callF304(c16);
+ callF0(c16);
+ callF19(c16);
+ callF38(c16);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth18() {
+ C17 c17 = new C17();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c17);
+ callF19(c17);
+ callF38(c17);
+ callF57(c17);
+ callF76(c17);
+ callF95(c17);
+ callF114(c17);
+ callF133(c17);
+ callF152(c17);
+ callF171(c17);
+ callF190(c17);
+ callF209(c17);
+ callF228(c17);
+ callF247(c17);
+ callF266(c17);
+ callF285(c17);
+ callF304(c17);
+ callF323(c17);
+ callF0(c17);
+ callF19(c17);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth19() {
+ C18 c18 = new C18();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c18);
+ callF19(c18);
+ callF38(c18);
+ callF57(c18);
+ callF76(c18);
+ callF95(c18);
+ callF114(c18);
+ callF133(c18);
+ callF152(c18);
+ callF171(c18);
+ callF190(c18);
+ callF209(c18);
+ callF228(c18);
+ callF247(c18);
+ callF266(c18);
+ callF285(c18);
+ callF304(c18);
+ callF323(c18);
+ callF342(c18);
+ callF0(c18);
+ }
+ }
+
+ @Test
+ public void timeConflictDepth20() {
+ C19 c19 = new C19();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ callF0(c19);
+ callF19(c19);
+ callF38(c19);
+ callF57(c19);
+ callF76(c19);
+ callF95(c19);
+ callF114(c19);
+ callF133(c19);
+ callF152(c19);
+ callF171(c19);
+ callF190(c19);
+ callF209(c19);
+ callF228(c19);
+ callF247(c19);
+ callF266(c19);
+ callF285(c19);
+ callF304(c19);
+ callF323(c19);
+ callF342(c19);
+ callF361(c19);
+ }
+ }
+
+ public void callF0(I0 i) {
+ i.f0();
+ }
+
+ public void callF19(I1 i) {
+ i.f19();
+ }
+
+ public void callF38(I2 i) {
+ i.f38();
+ }
+
+ public void callF57(I3 i) {
+ i.f57();
+ }
+
+ public void callF76(I4 i) {
+ i.f76();
+ }
+
+ public void callF95(I5 i) {
+ i.f95();
+ }
+
+ public void callF114(I6 i) {
+ i.f114();
+ }
+
+ public void callF133(I7 i) {
+ i.f133();
+ }
+
+ public void callF152(I8 i) {
+ i.f152();
+ }
+
+ public void callF171(I9 i) {
+ i.f171();
+ }
+
+ public void callF190(I10 i) {
+ i.f190();
+ }
+
+ public void callF209(I11 i) {
+ i.f209();
+ }
+
+ public void callF228(I12 i) {
+ i.f228();
+ }
+
+ public void callF247(I13 i) {
+ i.f247();
+ }
+
+ public void callF266(I14 i) {
+ i.f266();
+ }
+
+ public void callF285(I15 i) {
+ i.f285();
+ }
+
+ public void callF304(I16 i) {
+ i.f304();
+ }
+
+ public void callF323(I17 i) {
+ i.f323();
+ }
+
+ public void callF342(I18 i) {
+ i.f342();
+ }
+
+ public void callF361(I19 i) {
+ i.f361();
+ }
+
+ static class C0 implements I0 {}
+
+ static class C1 implements I0, I1 {}
+
+ static class C2 implements I0, I1, I2 {}
+
+ static class C3 implements I0, I1, I2, I3 {}
+
+ static class C4 implements I0, I1, I2, I3, I4 {}
+
+ static class C5 implements I0, I1, I2, I3, I4, I5 {}
+
+ static class C6 implements I0, I1, I2, I3, I4, I5, I6 {}
+
+ static class C7 implements I0, I1, I2, I3, I4, I5, I6, I7 {}
+
+ static class C8 implements I0, I1, I2, I3, I4, I5, I6, I7, I8 {}
+
+ static class C9 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9 {}
+
+ static class C10 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10 {}
+
+ static class C11 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11 {}
+
+ static class C12 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12 {}
+
+ static class C13 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13 {}
+
+ static class C14 implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14 {}
+
+ static class C15
+ implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15 {}
+
+ static class C16
+ implements I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16 {}
+
+ static class C17
+ implements I0,
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8,
+ I9,
+ I10,
+ I11,
+ I12,
+ I13,
+ I14,
+ I15,
+ I16,
+ I17 {}
+
+ static class C18
+ implements I0,
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8,
+ I9,
+ I10,
+ I11,
+ I12,
+ I13,
+ I14,
+ I15,
+ I16,
+ I17,
+ I18 {}
+
+ static class C19
+ implements I0,
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8,
+ I9,
+ I10,
+ I11,
+ I12,
+ I13,
+ I14,
+ I15,
+ I16,
+ I17,
+ I18,
+ I19 {}
+
+ interface I0 {
+ default void f0() {}
+
+ default void f1() {}
+
+ default void f2() {}
+
+ default void f3() {}
+
+ default void f4() {}
+
+ default void f5() {}
+
+ default void f6() {}
+
+ default void f7() {}
+
+ default void f8() {}
+
+ default void f9() {}
+
+ default void f10() {}
+
+ default void f11() {}
+
+ default void f12() {}
+
+ default void f13() {}
+
+ default void f14() {}
+
+ default void f15() {}
+
+ default void f16() {}
+
+ default void f17() {}
+
+ default void f18() {}
+ }
+
+ interface I1 {
+ default void f19() {}
+
+ default void f20() {}
+
+ default void f21() {}
+
+ default void f22() {}
+
+ default void f23() {}
+
+ default void f24() {}
+
+ default void f25() {}
+
+ default void f26() {}
+
+ default void f27() {}
+
+ default void f28() {}
+
+ default void f29() {}
+
+ default void f30() {}
+
+ default void f31() {}
+
+ default void f32() {}
+
+ default void f33() {}
+
+ default void f34() {}
+
+ default void f35() {}
+
+ default void f36() {}
+
+ default void f37() {}
+ }
+
+ interface I2 {
+ default void f38() {}
+
+ default void f39() {}
+
+ default void f40() {}
+
+ default void f41() {}
+
+ default void f42() {}
+
+ default void f43() {}
+
+ default void f44() {}
+
+ default void f45() {}
+
+ default void f46() {}
+
+ default void f47() {}
+
+ default void f48() {}
+
+ default void f49() {}
+
+ default void f50() {}
+
+ default void f51() {}
+
+ default void f52() {}
+
+ default void f53() {}
+
+ default void f54() {}
+
+ default void f55() {}
+
+ default void f56() {}
+ }
+
+ interface I3 {
+ default void f57() {}
+
+ default void f58() {}
+
+ default void f59() {}
+
+ default void f60() {}
+
+ default void f61() {}
+
+ default void f62() {}
+
+ default void f63() {}
+
+ default void f64() {}
+
+ default void f65() {}
+
+ default void f66() {}
+
+ default void f67() {}
+
+ default void f68() {}
+
+ default void f69() {}
+
+ default void f70() {}
+
+ default void f71() {}
+
+ default void f72() {}
+
+ default void f73() {}
+
+ default void f74() {}
+
+ default void f75() {}
+ }
+
+ interface I4 {
+ default void f76() {}
+
+ default void f77() {}
+
+ default void f78() {}
+
+ default void f79() {}
+
+ default void f80() {}
+
+ default void f81() {}
+
+ default void f82() {}
+
+ default void f83() {}
+
+ default void f84() {}
+
+ default void f85() {}
+
+ default void f86() {}
+
+ default void f87() {}
+
+ default void f88() {}
+
+ default void f89() {}
+
+ default void f90() {}
+
+ default void f91() {}
+
+ default void f92() {}
+
+ default void f93() {}
+
+ default void f94() {}
+ }
+
+ interface I5 {
+ default void f95() {}
+
+ default void f96() {}
+
+ default void f97() {}
+
+ default void f98() {}
+
+ default void f99() {}
+
+ default void f100() {}
+
+ default void f101() {}
+
+ default void f102() {}
+
+ default void f103() {}
+
+ default void f104() {}
+
+ default void f105() {}
+
+ default void f106() {}
+
+ default void f107() {}
+
+ default void f108() {}
+
+ default void f109() {}
+
+ default void f110() {}
+
+ default void f111() {}
+
+ default void f112() {}
+
+ default void f113() {}
+ }
+
+ interface I6 {
+ default void f114() {}
+
+ default void f115() {}
+
+ default void f116() {}
+
+ default void f117() {}
+
+ default void f118() {}
+
+ default void f119() {}
+
+ default void f120() {}
+
+ default void f121() {}
+
+ default void f122() {}
+
+ default void f123() {}
+
+ default void f124() {}
+
+ default void f125() {}
+
+ default void f126() {}
+
+ default void f127() {}
+
+ default void f128() {}
+
+ default void f129() {}
+
+ default void f130() {}
+
+ default void f131() {}
+
+ default void f132() {}
+ }
+
+ interface I7 {
+ default void f133() {}
+
+ default void f134() {}
+
+ default void f135() {}
+
+ default void f136() {}
+
+ default void f137() {}
+
+ default void f138() {}
+
+ default void f139() {}
+
+ default void f140() {}
+
+ default void f141() {}
+
+ default void f142() {}
+
+ default void f143() {}
+
+ default void f144() {}
+
+ default void f145() {}
+
+ default void f146() {}
+
+ default void f147() {}
+
+ default void f148() {}
+
+ default void f149() {}
+
+ default void f150() {}
+
+ default void f151() {}
+ }
+
+ interface I8 {
+ default void f152() {}
+
+ default void f153() {}
+
+ default void f154() {}
+
+ default void f155() {}
+
+ default void f156() {}
+
+ default void f157() {}
+
+ default void f158() {}
+
+ default void f159() {}
+
+ default void f160() {}
+
+ default void f161() {}
+
+ default void f162() {}
+
+ default void f163() {}
+
+ default void f164() {}
+
+ default void f165() {}
+
+ default void f166() {}
+
+ default void f167() {}
+
+ default void f168() {}
+
+ default void f169() {}
+
+ default void f170() {}
+ }
+
+ interface I9 {
+ default void f171() {}
+
+ default void f172() {}
+
+ default void f173() {}
+
+ default void f174() {}
+
+ default void f175() {}
+
+ default void f176() {}
+
+ default void f177() {}
+
+ default void f178() {}
+
+ default void f179() {}
+
+ default void f180() {}
+
+ default void f181() {}
+
+ default void f182() {}
+
+ default void f183() {}
+
+ default void f184() {}
+
+ default void f185() {}
+
+ default void f186() {}
+
+ default void f187() {}
+
+ default void f188() {}
+
+ default void f189() {}
+ }
+
+ interface I10 {
+ default void f190() {}
+
+ default void f191() {}
+
+ default void f192() {}
+
+ default void f193() {}
+
+ default void f194() {}
+
+ default void f195() {}
+
+ default void f196() {}
+
+ default void f197() {}
+
+ default void f198() {}
+
+ default void f199() {}
+
+ default void f200() {}
+
+ default void f201() {}
+
+ default void f202() {}
+
+ default void f203() {}
+
+ default void f204() {}
+
+ default void f205() {}
+
+ default void f206() {}
+
+ default void f207() {}
+
+ default void f208() {}
+ }
+
+ interface I11 {
+ default void f209() {}
+
+ default void f210() {}
+
+ default void f211() {}
+
+ default void f212() {}
+
+ default void f213() {}
+
+ default void f214() {}
+
+ default void f215() {}
+
+ default void f216() {}
+
+ default void f217() {}
+
+ default void f218() {}
+
+ default void f219() {}
+
+ default void f220() {}
+
+ default void f221() {}
+
+ default void f222() {}
+
+ default void f223() {}
+
+ default void f224() {}
+
+ default void f225() {}
+
+ default void f226() {}
+
+ default void f227() {}
+ }
+
+ interface I12 {
+ default void f228() {}
+
+ default void f229() {}
+
+ default void f230() {}
+
+ default void f231() {}
+
+ default void f232() {}
+
+ default void f233() {}
+
+ default void f234() {}
+
+ default void f235() {}
+
+ default void f236() {}
+
+ default void f237() {}
+
+ default void f238() {}
+
+ default void f239() {}
+
+ default void f240() {}
+
+ default void f241() {}
+
+ default void f242() {}
+
+ default void f243() {}
+
+ default void f244() {}
+
+ default void f245() {}
+
+ default void f246() {}
+ }
+
+ interface I13 {
+ default void f247() {}
+
+ default void f248() {}
+
+ default void f249() {}
+
+ default void f250() {}
+
+ default void f251() {}
+
+ default void f252() {}
+
+ default void f253() {}
+
+ default void f254() {}
+
+ default void f255() {}
+
+ default void f256() {}
+
+ default void f257() {}
+
+ default void f258() {}
+
+ default void f259() {}
+
+ default void f260() {}
+
+ default void f261() {}
+
+ default void f262() {}
+
+ default void f263() {}
+
+ default void f264() {}
+
+ default void f265() {}
+ }
+
+ interface I14 {
+ default void f266() {}
+
+ default void f267() {}
+
+ default void f268() {}
+
+ default void f269() {}
+
+ default void f270() {}
+
+ default void f271() {}
+
+ default void f272() {}
+
+ default void f273() {}
+
+ default void f274() {}
+
+ default void f275() {}
+
+ default void f276() {}
+
+ default void f277() {}
+
+ default void f278() {}
+
+ default void f279() {}
+
+ default void f280() {}
+
+ default void f281() {}
+
+ default void f282() {}
+
+ default void f283() {}
+
+ default void f284() {}
+ }
+
+ interface I15 {
+ default void f285() {}
+
+ default void f286() {}
+
+ default void f287() {}
+
+ default void f288() {}
+
+ default void f289() {}
+
+ default void f290() {}
+
+ default void f291() {}
+
+ default void f292() {}
+
+ default void f293() {}
+
+ default void f294() {}
+
+ default void f295() {}
+
+ default void f296() {}
+
+ default void f297() {}
+
+ default void f298() {}
+
+ default void f299() {}
+
+ default void f300() {}
+
+ default void f301() {}
+
+ default void f302() {}
+
+ default void f303() {}
+ }
+
+ interface I16 {
+ default void f304() {}
+
+ default void f305() {}
+
+ default void f306() {}
+
+ default void f307() {}
+
+ default void f308() {}
+
+ default void f309() {}
+
+ default void f310() {}
+
+ default void f311() {}
+
+ default void f312() {}
+
+ default void f313() {}
+
+ default void f314() {}
+
+ default void f315() {}
+
+ default void f316() {}
+
+ default void f317() {}
+
+ default void f318() {}
+
+ default void f319() {}
+
+ default void f320() {}
+
+ default void f321() {}
+
+ default void f322() {}
+ }
+
+ interface I17 {
+ default void f323() {}
+
+ default void f324() {}
+
+ default void f325() {}
+
+ default void f326() {}
+
+ default void f327() {}
+
+ default void f328() {}
+
+ default void f329() {}
+
+ default void f330() {}
+
+ default void f331() {}
+
+ default void f332() {}
+
+ default void f333() {}
+
+ default void f334() {}
+
+ default void f335() {}
+
+ default void f336() {}
+
+ default void f337() {}
+
+ default void f338() {}
+
+ default void f339() {}
+
+ default void f340() {}
+
+ default void f341() {}
+ }
+
+ interface I18 {
+ default void f342() {}
+
+ default void f343() {}
+
+ default void f344() {}
+
+ default void f345() {}
+
+ default void f346() {}
+
+ default void f347() {}
+
+ default void f348() {}
+
+ default void f349() {}
+
+ default void f350() {}
+
+ default void f351() {}
+
+ default void f352() {}
+
+ default void f353() {}
+
+ default void f354() {}
+
+ default void f355() {}
+
+ default void f356() {}
+
+ default void f357() {}
+
+ default void f358() {}
+
+ default void f359() {}
+
+ default void f360() {}
+ }
+
+ interface I19 {
+ default void f361() {}
+
+ default void f362() {}
+
+ default void f363() {}
+
+ default void f364() {}
+
+ default void f365() {}
+
+ default void f366() {}
+
+ default void f367() {}
+
+ default void f368() {}
+
+ default void f369() {}
+
+ default void f370() {}
+
+ default void f371() {}
+
+ default void f372() {}
+
+ default void f373() {}
+
+ default void f374() {}
+
+ default void f375() {}
+
+ default void f376() {}
+
+ default void f377() {}
+
+ default void f378() {}
+
+ default void f379() {}
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTestGen.py b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTestGen.py
new file mode 100755
index 0000000..eea3b84
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTestGen.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+#
+
+import sys
+
+max_conflict_depth = 20 # In practice does not go above 20 for reasonable IMT sizes
+try:
+ imt_size = int(sys.argv[1])
+except (IndexError, ValueError):
+ print("Usage: python ImtConflictPerfTestGen.py <IMT_SIZE>")
+ sys.exit(1)
+
+license = """\
+/*
+ * Copyright 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.
+ */
+"""
+description = """
+/**
+ * This file is script-generated by ImtConflictPerfTestGen.py.
+ * It measures the performance impact of conflicts in interface method tables.
+ * Run `python ImtConflictPerfTestGen.py > ImtConflictPerfTest.java` to regenerate.
+ *
+ * Each interface has 64 methods, which is the current size of an IMT. C0 implements
+ * one interface, C1 implements two, C2 implements three, and so on. The intent
+ * is that C0 has no conflicts in its IMT, C1 has depth-2 conflicts in
+ * its IMT, C2 has depth-3 conflicts, etc. This is currently guaranteed by
+ * the fact that we hash interface methods by taking their method index modulo 64.
+ * (Note that a "conflict depth" of 1 means no conflict at all.)
+ */\
+"""
+
+print(license)
+print("package android.libcore;")
+imports = """
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+"""
+print(imports)
+print(description)
+
+print("@RunWith(AndroidJUnit4.class)")
+print("@LargeTest")
+print("public class ImtConflictPerfTest {")
+print(" @Rule")
+print(" public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();")
+print("")
+# Warm up interface method tables
+print(" @Before")
+print(" public void setup() {")
+for i in range(max_conflict_depth):
+ print(" C{0} c{0} = new C{0}();".format(i))
+ for j in range(i+1):
+ print(" callF{}(c{});".format(imt_size * j, i))
+print(" }")
+
+# Print test cases--one for each conflict depth
+for i in range(max_conflict_depth):
+ print(" @Test")
+ print(" public void timeConflictDepth{:02d}() {{".format(i+1))
+ print(" C{0} c{0} = new C{0}();".format(i))
+ print(" BenchmarkState state = mPerfStatusReporter.getBenchmarkState();")
+ print(" while (state.keepRunning()) {")
+ # Cycle through each interface method in an IMT entry in order
+ # to test all conflict resolution possibilities
+ for j in range(max_conflict_depth):
+ print(" callF{}(c{});".format(imt_size * (j % (i + 1)), i))
+ print(" }")
+ print(" }")
+
+# Make calls through the IMTs
+for i in range(max_conflict_depth):
+ print(" public void callF{0}(I{1} i) {{ i.f{0}(); }}".format(imt_size*i, i))
+
+# Class definitions, implementing varying amounts of interfaces
+for i in range(max_conflict_depth):
+ interfaces = ", ".join(["I{}".format(j) for j in range(i+1)])
+ print(" static class C{} implements {} {{}}".format(i, interfaces))
+
+# Interface definitions, each with enough methods to fill an entire IMT
+for i in range(max_conflict_depth):
+ print(" interface I{} {{".format(i))
+ for j in range(imt_size):
+ print(" default void f{}() {{}}".format(i*imt_size + j))
+ print(" }")
+
+print("}")
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
new file mode 100644
index 0000000..ca99779
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 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;
+
+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;
+
+/** Compares various kinds of method invocation. */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MethodInvocationPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ interface I {
+ void emptyInterface();
+ }
+
+ static class C implements I {
+ private int mField;
+
+ private int getField() {
+ return mField;
+ }
+
+ public void timeInternalGetter(BenchmarkState state) {
+ int result = 0;
+ while (state.keepRunning()) {
+ result = getField();
+ }
+ }
+
+ public void timeInternalFieldAccess(BenchmarkState state) {
+ int result = 0;
+ while (state.keepRunning()) {
+ result = mField;
+ }
+ }
+
+ public static void emptyStatic() {}
+
+ public void emptyVirtual() {}
+
+ public void emptyInterface() {}
+ }
+
+ public void timeInternalGetter() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ new C().timeInternalGetter(state);
+ }
+
+ public void timeInternalFieldAccess() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ new C().timeInternalFieldAccess(state);
+ }
+
+ // Test an intrinsic.
+ @Test
+ public void timeStringLength() {
+ int result = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result = "hello, world!".length();
+ }
+ }
+
+ @Test
+ public void timeEmptyStatic() {
+ C c = new C();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ c.emptyStatic();
+ }
+ }
+
+ @Test
+ public void timeEmptyVirtual() {
+ C c = new C();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ c.emptyVirtual();
+ }
+ }
+
+ @Test
+ public void timeEmptyInterface() {
+ I c = new C();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ c.emptyInterface();
+ }
+ }
+
+ public static class Inner {
+ private int mI;
+
+ private void privateMethod() {
+ ++mI;
+ }
+
+ protected void protectedMethod() {
+ ++mI;
+ }
+
+ public void publicMethod() {
+ ++mI;
+ }
+
+ void packageMethod() {
+ ++mI;
+ }
+
+ final void finalPackageMethod() {
+ ++mI;
+ }
+ }
+
+ @Test
+ public void timePrivateInnerPublicMethod() {
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ inner.publicMethod();
+ }
+ }
+
+ @Test
+ public void timePrivateInnerProtectedMethod() {
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ inner.protectedMethod();
+ }
+ }
+
+ @Test
+ public void timePrivateInnerPrivateMethod() {
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ inner.privateMethod();
+ }
+ }
+
+ @Test
+ public void timePrivateInnerPackageMethod() {
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ inner.packageMethod();
+ }
+ }
+
+ @Test
+ public void timePrivateInnerFinalPackageMethod() {
+ Inner inner = new Inner();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ inner.finalPackageMethod();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
new file mode 100644
index 0000000..8496fbe
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+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;
+
+/** How much do various kinds of multiplication cost? */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MultiplicationPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeMultiplyIntByConstant10() {
+ int result = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result *= 10;
+ }
+ }
+
+ @Test
+ public void timeMultiplyIntByConstant8() {
+ int result = 1;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result *= 8;
+ }
+ }
+
+ @Test
+ public void timeMultiplyIntByVariable10() {
+ int result = 1;
+ int factor = 10;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result *= factor;
+ }
+ }
+
+ @Test
+ public void timeMultiplyIntByVariable8() {
+ int result = 1;
+ int factor = 8;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ result *= factor;
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
new file mode 100644
index 0000000..bb79424
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.libcore;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReferenceGetPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ boolean mIntrinsicDisabled;
+
+ private Object mObj = "str";
+
+ @Before
+ public void setUp() throws Exception {
+ Field intrinsicDisabledField = Reference.class.getDeclaredField("disableIntrinsic");
+ intrinsicDisabledField.setAccessible(true);
+ intrinsicDisabledField.setBoolean(null, mIntrinsicDisabled);
+ }
+
+ @Test
+ public void timeSoftReferenceGet() throws Exception {
+ Reference soft = new SoftReference(mObj);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Object o = soft.get();
+ }
+ }
+
+ @Test
+ public void timeWeakReferenceGet() throws Exception {
+ Reference weak = new WeakReference(mObj);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Object o = weak.get();
+ }
+ }
+
+ @Test
+ public void timeNonPreservedWeakReferenceGet() throws Exception {
+ Reference weak = new WeakReference(mObj);
+ mObj = null;
+ Runtime.getRuntime().gc();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Object o = weak.get();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
new file mode 100644
index 0000000..2ef68ca
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.libcore;
+
+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.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** Benchmark to evaluate the performance of References. */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ReferencePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private Object mObject;
+
+ // How fast can references can be allocated?
+ @Test
+ public void timeAlloc() {
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ new PhantomReference(mObject, queue);
+ }
+ }
+
+ // How fast can references can be allocated and manually enqueued?
+ @Test
+ public void timeAllocAndEnqueue() {
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ (new PhantomReference<Object>(mObject, queue)).enqueue();
+ }
+ }
+
+ // How fast can references can be allocated, enqueued, and polled?
+ @Test
+ public void timeAllocEnqueueAndPoll() {
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ (new PhantomReference<Object>(mObject, queue)).enqueue();
+ queue.poll();
+ }
+ }
+
+ // How fast can references can be allocated, enqueued, and removed?
+ @Test
+ public void timeAllocEnqueueAndRemove() {
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ (new PhantomReference<Object>(mObject, queue)).enqueue();
+ try {
+ queue.remove();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ private static class FinalizableObject {
+ AtomicInteger mCount;
+
+ FinalizableObject(AtomicInteger count) {
+ this.mCount = count;
+ }
+
+ @Override
+ protected void finalize() {
+ mCount.incrementAndGet();
+ }
+ }
+
+ // How fast does finalization run?
+ @Test
+ public void timeFinalization() {
+ // Allocate a bunch of finalizable objects.
+ int n = 0;
+ AtomicInteger count = new AtomicInteger(0);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ n++;
+ new FinalizableObject(count);
+ }
+
+ // Run GC so the objects will be collected for finalization.
+ Runtime.getRuntime().gc();
+
+ // Wait for finalization.
+ Runtime.getRuntime().runFinalization();
+
+ // Double check all the objects were finalized.
+ int got = count.get();
+ if (n != got) {
+ throw new IllegalStateException(
+ String.format("Only %i of %i objects finalized?", got, n));
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
new file mode 100644
index 0000000..65a2fdb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * This measures performance of operations on small BigIntegers. We manually determine the number of
+ * iterations so that it should cause total memory allocation on the order of a few hundred
+ * megabytes. Due to BigInteger's reliance on finalization, these may unfortunately all be kept
+ * around at once.
+ *
+ * <p>This is not structured as a proper benchmark; just run main(), e.g. with vogar
+ * libcore/benchmarks/src/benchmarks/SmallBigIntegerBenchmark.java
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SmallBigIntegerPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ // We allocate about 2 1/3 BigIntegers per iteration.
+ // Assuming 100 bytes/BigInteger, this gives us around 500MB total.
+ static final BigInteger BIG_THREE = BigInteger.valueOf(3);
+ static final BigInteger BIG_FOUR = BigInteger.valueOf(4);
+
+ @Test
+ public void testSmallBigInteger() {
+ final Random r = new Random();
+ BigInteger x = new BigInteger(20, r);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ // We know this converges, but the compiler doesn't.
+ if (x.and(BigInteger.ONE).equals(BigInteger.ONE)) {
+ x = x.multiply(BIG_THREE).add(BigInteger.ONE);
+ } else {
+ x = x.shiftRight(1);
+ }
+ }
+ if (x.signum() < 0 || x.compareTo(BIG_FOUR) > 0) {
+ throw new AssertionError("Something went horribly wrong.");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
new file mode 100644
index 0000000..4f5c54d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+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;
+
+/** How long does it take to access a string in the dex cache? */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringDexCachePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeStringDexCacheAccess() {
+ int v = 0;
+ int count = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ // Deliberately obscured to make optimizations less likely.
+ String s = (count >= 0) ? "hello, world!" : null;
+ v += s.length();
+ ++count;
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
new file mode 100644
index 0000000..08ad926
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+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;
+
+/** How do the various schemes for iterating through a string compare? */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class StringIterationPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeStringIteration0() {
+ String s = "hello, world!";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ char ch;
+ for (int i = 0; i < s.length(); ++i) {
+ ch = s.charAt(i);
+ }
+ }
+ }
+
+ @Test
+ public void timeStringIteration1() {
+ String s = "hello, world!";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ char ch;
+ for (int i = 0, length = s.length(); i < length; ++i) {
+ ch = s.charAt(i);
+ }
+ }
+ }
+
+ @Test
+ public void timeStringIteration2() {
+ String s = "hello, world!";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ char ch;
+ char[] chars = s.toCharArray();
+ for (int i = 0, length = chars.length; i < length; ++i) {
+ ch = chars[i];
+ }
+ }
+ }
+
+ @Test
+ public void timeStringToCharArray() {
+ String s = "hello, world!";
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ char[] chars = s.toCharArray();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java
new file mode 100644
index 0000000..5aacfc2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+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 SystemArrayCopyPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "arrayLength={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {2}, {4}, {8}, {16}, {32}, {64}, {128}, {256}, {512}, {1024}, {2048}, {4096},
+ {8192}, {16384}, {32768}, {65536}, {131072}, {262144}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public int arrayLength;
+
+ // Provides benchmarking for different types of arrays using the arraycopy function.
+ @Test
+ public void timeSystemCharArrayCopy() {
+ final int len = arrayLength;
+ char[] src = new char[len];
+ char[] dst = new char[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemByteArrayCopy() {
+ final int len = arrayLength;
+ byte[] src = new byte[len];
+ byte[] dst = new byte[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemShortArrayCopy() {
+ final int len = arrayLength;
+ short[] src = new short[len];
+ short[] dst = new short[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemIntArrayCopy() {
+ final int len = arrayLength;
+ int[] src = new int[len];
+ int[] dst = new int[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemLongArrayCopy() {
+ final int len = arrayLength;
+ long[] src = new long[len];
+ long[] dst = new long[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemFloatArrayCopy() {
+ final int len = arrayLength;
+ float[] src = new float[len];
+ float[] dst = new float[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemDoubleArrayCopy() {
+ final int len = arrayLength;
+ double[] src = new double[len];
+ double[] dst = new double[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+
+ @Test
+ public void timeSystemBooleanArrayCopy() {
+ final int len = arrayLength;
+ boolean[] src = new boolean[len];
+ boolean[] dst = new boolean[len];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ System.arraycopy(src, 0, dst, 0, len);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
new file mode 100644
index 0000000..7e71976
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+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.HashMap;
+import java.util.Map;
+
+/**
+ * Is there a performance reason to "Prefer virtual over interface", as the Android documentation
+ * once claimed?
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VirtualVersusInterfacePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeMapPut() {
+ Map<String, String> map = new HashMap<String, String>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.put("hello", "world");
+ }
+ }
+
+ @Test
+ public void timeHashMapPut() {
+ HashMap<String, String> map = new HashMap<String, String>();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ map.put("hello", "world");
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
new file mode 100644
index 0000000..eec0734
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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;
+
+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.xmlpull.v1.XmlSerializer;
+
+import java.io.CharArrayWriter;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Random;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class XmlSerializePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "mDatasetAsString({0}), mSeed({1})")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(
+ new Object[][] {
+ {"0.99 0.7 0.7 0.7 0.7 0.7", 854328},
+ {"0.999 0.3 0.3 0.95 0.9 0.9", 854328},
+ {"0.99 0.7 0.7 0.7 0.7 0.7", 312547},
+ {"0.999 0.3 0.3 0.95 0.9 0.9", 312547}
+ });
+ }
+
+ @Parameterized.Parameter(0)
+ public String mDatasetAsString;
+
+ @Parameterized.Parameter(1)
+ public int mSeed;
+
+ double[] mDataset;
+ private Constructor<? extends XmlSerializer> mKxmlConstructor;
+ private Constructor<? extends XmlSerializer> mFastConstructor;
+
+ private void serializeRandomXml(Constructor<? extends XmlSerializer> ctor, long mSeed)
+ throws Exception {
+ double contChance = mDataset[0];
+ double levelUpChance = mDataset[1];
+ double levelDownChance = mDataset[2];
+ double attributeChance = mDataset[3];
+ double writeChance1 = mDataset[4];
+ double writeChance2 = mDataset[5];
+
+ XmlSerializer serializer = (XmlSerializer) ctor.newInstance();
+
+ CharArrayWriter w = new CharArrayWriter();
+ serializer.setOutput(w);
+ int level = 0;
+ Random r = new Random(mSeed);
+ char[] toWrite = {'a', 'b', 'c', 'd', 's', 'z'};
+ serializer.startDocument("UTF-8", true);
+ while (r.nextDouble() < contChance) {
+ while (level > 0 && r.nextDouble() < levelUpChance) {
+ serializer.endTag("aaaaaa", "bbbbbb");
+ level--;
+ }
+ while (r.nextDouble() < levelDownChance) {
+ serializer.startTag("aaaaaa", "bbbbbb");
+ level++;
+ }
+ serializer.startTag("aaaaaa", "bbbbbb");
+ level++;
+ while (r.nextDouble() < attributeChance) {
+ serializer.attribute("aaaaaa", "cccccc", "dddddd");
+ }
+ serializer.endTag("aaaaaa", "bbbbbb");
+ level--;
+ while (r.nextDouble() < writeChance1) serializer.text(toWrite, 0, 5);
+ while (r.nextDouble() < writeChance2) serializer.text("Textxtsxtxtxt ");
+ }
+ serializer.endDocument();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setUp() throws Exception {
+ mKxmlConstructor =
+ (Constructor)
+ Class.forName("com.android.org.kxml2.io.KXmlSerializer").getConstructor();
+ mFastConstructor =
+ (Constructor)
+ Class.forName("com.android.internal.util.FastXmlSerializer")
+ .getConstructor();
+ String[] splitStrings = mDatasetAsString.split(" ");
+ mDataset = new double[splitStrings.length];
+ for (int i = 0; i < splitStrings.length; i++) {
+ mDataset[i] = Double.parseDouble(splitStrings[i]);
+ }
+ }
+
+ private void internalTimeSerializer(Constructor<? extends XmlSerializer> ctor)
+ throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ serializeRandomXml(ctor, mSeed);
+ }
+ }
+
+ @Test
+ public void timeKxml() throws Exception {
+ internalTimeSerializer(mKxmlConstructor);
+ }
+
+ @Test
+ public void timeFast() throws Exception {
+ internalTimeSerializer(mFastConstructor);
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
new file mode 100644
index 0000000..517e3ce
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+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.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Random;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ZipFilePerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private File mFile;
+
+ @Parameters(name = "numEntries={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{128}, {1024}, {8192}});
+ }
+
+ @Parameterized.Parameter(0)
+ public int numEntries;
+
+ @Before
+ public void setUp() throws Exception {
+ mFile = File.createTempFile(getClass().getName(), ".zip");
+ mFile.deleteOnExit();
+ writeEntries(new ZipOutputStream(new FileOutputStream(mFile)), numEntries, 0);
+ ZipFile zipFile = new ZipFile(mFile);
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ }
+ zipFile.close();
+ }
+
+ @Test
+ public void timeZipFileOpen() throws Exception {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ZipFile zf = new ZipFile(mFile);
+ }
+ }
+
+ /** Compresses the given number of files, each of the given size, into a .zip archive. */
+ protected void writeEntries(ZipOutputStream out, int entryCount, long entrySize)
+ throws IOException {
+ byte[] writeBuffer = new byte[8192];
+ Random random = new Random();
+ try {
+ for (int entry = 0; entry < entryCount; ++entry) {
+ ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
+ ze.setSize(entrySize);
+ out.putNextEntry(ze);
+
+ for (long i = 0; i < entrySize; i += writeBuffer.length) {
+ random.nextBytes(writeBuffer);
+ int byteCount = (int) Math.min(writeBuffer.length, entrySize - i);
+ out.write(writeBuffer, 0, byteCount);
+ }
+
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
new file mode 100644
index 0000000..faa9628
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+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.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Random;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class ZipFileReadPerfTest {
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameters(name = "readBufferSize={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {{1024}, {16384}, {65536}});
+ }
+
+ private File mFile;
+
+ @Parameterized.Parameter(0)
+ public int readBufferSize;
+
+ @Before
+ public void setUp() throws Exception {
+ mFile = File.createTempFile(getClass().getName(), ".zip");
+ writeEntries(new ZipOutputStream(new FileOutputStream(mFile)), 2, 1024 * 1024);
+ ZipFile zipFile = new ZipFile(mFile);
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ }
+ zipFile.close();
+ }
+
+ /** Compresses the given number of files, each of the given size, into a .zip archive. */
+ protected void writeEntries(ZipOutputStream out, int entryCount, long entrySize)
+ throws IOException {
+ byte[] writeBuffer = new byte[8192];
+ Random random = new Random();
+ try {
+ for (int entry = 0; entry < entryCount; ++entry) {
+ ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
+ ze.setSize(entrySize);
+ out.putNextEntry(ze);
+
+ for (long i = 0; i < entrySize; i += writeBuffer.length) {
+ random.nextBytes(writeBuffer);
+ int byteCount = (int) Math.min(writeBuffer.length, entrySize - i);
+ out.write(writeBuffer, 0, byteCount);
+ }
+
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+ }
+
+ @Test
+ public void timeZipFileRead() throws Exception {
+ byte[] readBuffer = new byte[readBufferSize];
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ ZipFile zipFile = new ZipFile(mFile);
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ InputStream is = zipFile.getInputStream(zipEntry);
+ while (true) {
+ if (is.read(readBuffer, 0, readBuffer.length) < 0) {
+ break;
+ }
+ }
+ }
+ zipFile.close();
+ }
+ }
+}
diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS
index c77ea33..58434f1 100644
--- a/apex/jobscheduler/OWNERS
+++ b/apex/jobscheduler/OWNERS
@@ -1,7 +1,9 @@
ctate@android.com
ctate@google.com
dplotnikov@google.com
+jji@google.com
kwekua@google.com
omakoto@google.com
suprabh@google.com
+varunshah@google.com
yamasani@google.com
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db45466..6a877f9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4658,6 +4658,11 @@
}
/** @hide */
+ public static boolean isProcStateConsideredInteraction(@ProcessState int procState) {
+ return (procState <= PROCESS_STATE_TOP || procState == PROCESS_STATE_BOUND_TOP);
+ }
+
+ /** @hide */
public static String procStateToString(int procState) {
final String procStateStr;
switch (procState) {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4c30f56..7ec3619 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -209,6 +209,12 @@
public abstract void notifyNetworkPolicyRulesUpdated(int uid, long procStateSeq);
/**
+ * Inform ActivityManagerService about the latest {@code blockedReasons} for an uid, which
+ * can be used to understand whether the {@code uid} is allowed to access network or not.
+ */
+ public abstract void onUidBlockedReasonsChanged(int uid, int blockedReasons);
+
+ /**
* @return true if runtime was restarted, false if it's normal boot
*/
public abstract boolean isRuntimeRestarted();
@@ -581,7 +587,7 @@
* @param uid uid
* @param pid pid of the ProcessRecord that is pending top.
*/
- public abstract void addPendingTopUid(int uid, int pid);
+ public abstract void addPendingTopUid(int uid, int pid, @Nullable IApplicationThread thread);
/**
* Delete uid from the ActivityManagerService PendingStartActivityUids list.
@@ -680,4 +686,15 @@
*/
void notifyActivityEventChanged();
}
+
+ /**
+ * Register the UidObserver for NetworkPolicyManager service.
+ *
+ * This is equivalent to calling
+ * {@link IActivityManager#registerUidObserver(IUidObserver, int, int, String)} but having a
+ * separate method for NetworkPolicyManager service so that it's UidObserver can be called
+ * separately outside the usual UidObserver flow.
+ */
+ public abstract void registerNetworkPolicyUidObserver(@NonNull IUidObserver observer,
+ int which, int cutpoint, @NonNull String callingPackage);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 48edb2e..8bbfd8d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7026,7 +7026,13 @@
// local, we'll need to wait for the publishing of the provider.
if (holder != null && holder.provider == null && !holder.mLocal) {
synchronized (key.mLock) {
- key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ if (key.mHolder != null) {
+ if (DEBUG_PROVIDER) {
+ Slog.i(TAG, "already received provider: " + auth);
+ }
+ } else {
+ key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ }
holder = key.mHolder;
}
if (holder != null && holder.provider == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bde612e..402007d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -463,7 +463,7 @@
/**
* @hide Flag for {@link #bindService}: For only the case where the binding
- * is coming from the system, set the process state to FOREGROUND_SERVICE
+ * is coming from the system, set the process state to BOUND_FOREGROUND_SERVICE
* instead of the normal maximum of IMPORTANT_FOREGROUND. That is, this is
* saying that the process shouldn't participate in the normal power reduction
* modes (removing network access etc).
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 660368a..1c9713d 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -1,7 +1,8 @@
# Remain no owner because multiple modules may touch this file.
per-file Context.java = *
per-file ContextWrapper.java = *
-per-file Content* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *Content* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *Sync* = file:/services/core/java/com/android/server/am/OWNERS
per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS
per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS
per-file Intent.java = file:/PACKAGE_MANAGER_OWNERS
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 4b35b0d..16ad0b8 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -396,7 +396,8 @@
return true;
case MATCH_CARRIER:
case MATCH_MOBILE:
- return !template.getSubscriberIds().isEmpty();
+ return !template.getSubscriberIds().isEmpty()
+ && template.getMeteredness() == METERED_YES;
case MATCH_WIFI:
if (template.getWifiNetworkKeys().isEmpty()
&& template.getSubscriberIds().isEmpty()) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2c2a703..9341105 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -817,11 +817,13 @@
public static final class UidState {
public int uid;
public int procState;
+ public long procStateSeq;
public int capability;
- public UidState(int uid, int procState, int capability) {
+ public UidState(int uid, int procState, long procStateSeq, int capability) {
this.uid = uid;
this.procState = procState;
+ this.procStateSeq = procStateSeq;
this.capability = capability;
}
@@ -830,6 +832,8 @@
final StringBuilder sb = new StringBuilder();
sb.append("{procState=");
sb.append(procStateToString(procState));
+ sb.append(",seq=");
+ sb.append(procStateSeq);
sb.append(",cap=");
ActivityManager.printCapabilitiesSummary(sb, capability);
sb.append("}");
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index ae7d91f..37eb74a 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -187,14 +187,24 @@
/**
* The network that was underlying the VPN when the event occurred, as a {@link Network}.
*
- * This extra will be null if there was no underlying network at the time of the event.
+ * <p>This extra will be null if there was no underlying network at the time of the event, or
+ * the underlying network has no bearing on the event, as in the case of:
+ * <ul>
+ * <li>CATEGORY_EVENT_DEACTIVATED_BY_USER
+ * <li>CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED
+ * </ul>
*/
public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
/**
* The {@link NetworkCapabilities} of the underlying network when the event occurred.
*
- * This extra will be null if there was no underlying network at the time of the event.
+ * <p>This extra will be null if there was no underlying network at the time of the event, or
+ * the underlying network has no bearing on the event, as in the case of:
+ * <ul>
+ * <li>CATEGORY_EVENT_DEACTIVATED_BY_USER
+ * <li>CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED
+ * </ul>
*/
public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES =
"android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
@@ -202,7 +212,12 @@
/**
* The {@link LinkProperties} of the underlying network when the event occurred.
*
- * This extra will be null if there was no underlying network at the time of the event.
+ * <p>This extra will be null if there was no underlying network at the time of the event, or
+ * the underlying network has no bearing on the event, as in the case of:
+ * <ul>
+ * <li>CATEGORY_EVENT_DEACTIVATED_BY_USER
+ * <li>CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED
+ * </ul>
*/
public static final String EXTRA_UNDERLYING_LINK_PROPERTIES =
"android.net.extra.UNDERLYING_LINK_PROPERTIES";
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java
index c69ea1a..0f21a9d 100644
--- a/core/java/android/net/VpnProfileState.java
+++ b/core/java/android/net/VpnProfileState.java
@@ -24,6 +24,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.StringJoiner;
/**
* Describe the state of VPN.
@@ -150,4 +151,29 @@
mAlwaysOn = in.readBoolean();
mLockdown = in.readBoolean();
}
+
+ private String convertStateToString(@State int state) {
+ switch (state) {
+ case STATE_CONNECTED:
+ return "CONNECTED";
+ case STATE_CONNECTING:
+ return "CONNECTING";
+ case STATE_DISCONNECTED:
+ return "DISCONNECTED";
+ case STATE_FAILED:
+ return "FAILED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringJoiner resultJoiner = new StringJoiner(", ", "{", "}");
+ resultJoiner.add("State: " + convertStateToString(getState()));
+ resultJoiner.add("SessionId: " + getSessionId());
+ resultJoiner.add("Always-on: " + isAlwaysOn());
+ resultJoiner.add("Lockdown: " + isLockdownEnabled());
+ return resultJoiner.toString();
+ }
}
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index f1b110a..40e4083 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -104,6 +104,14 @@
// TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz
+ /** List of Carrier Config options to extract from Carrier Config bundles. @hide */
+ @NonNull
+ public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS =
+ new String[] {
+ VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
+ VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY
+ };
+
private static final Map<
VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 80ffd40..c33c2ab 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2263,8 +2263,11 @@
}
/**
- * {@link #getX(int)} for the first pointer index (may be an
- * arbitrary pointer identifier).
+ * Equivalent to {@link #getX(int)} for pointer index 0 (regardless of the
+ * pointer identifier).
+ *
+ * @return The X coordinate of the first pointer index in the coordinate
+ * space of the view that received this motion event.
*
* @see #AXIS_X
*/
@@ -2273,8 +2276,11 @@
}
/**
- * {@link #getY(int)} for the first pointer index (may be an
- * arbitrary pointer identifier).
+ * Equivalent to {@link #getY(int)} for pointer index 0 (regardless of the
+ * pointer identifier).
+ *
+ * @return The Y coordinate of the first pointer index in the coordinate
+ * space of the view that received this motion event.
*
* @see #AXIS_Y
*/
@@ -2416,13 +2422,20 @@
}
/**
- * Returns the X coordinate of this event for the given pointer
- * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
- * identifier for this index).
- * Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
- * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
- * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ * Returns the X coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The coordinate is in the
+ * coordinate space of the view that received this motion event.
+ *
+ * <p>Use {@link #getPointerId(int)} to get the pointer identifier for the
+ * pointer referenced by {@code pointerIndex}.
+ *
+ * @param pointerIndex Index of the pointer for which the X coordinate is
+ * returned. May be a value in the range of 0 (the first pointer that
+ * is down) to {@link #getPointerCount()} - 1.
+ * @return The X coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The unit is pixels. The
+ * value may contain a fractional portion for devices that are subpixel
+ * precise.
*
* @see #AXIS_X
*/
@@ -2431,13 +2444,20 @@
}
/**
- * Returns the Y coordinate of this event for the given pointer
- * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
- * identifier for this index).
- * Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
- * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
- * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ * Returns the Y coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The coordinate is in the
+ * coordinate space of the view that received this motion event.
+ *
+ * <p>Use {@link #getPointerId(int)} to get the pointer identifier for the
+ * pointer referenced by {@code pointerIndex}.
+ *
+ * @param pointerIndex Index of the pointer for which the Y coordinate is
+ * returned. May be a value in the range of 0 (the first pointer that
+ * is down) to {@link #getPointerCount()} - 1.
+ * @return The Y coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The unit is pixels. The
+ * value may contain a fractional portion for devices that are subpixel
+ * precise.
*
* @see #AXIS_Y
*/
@@ -2683,12 +2703,13 @@
}
/**
- * Returns the original raw X coordinate of this event. For touch
- * events on the screen, this is the original location of the event
- * on the screen, before it had been adjusted for the containing window
- * and views.
+ * Equivalent to {@link #getRawX(int)} for pointer index 0 (regardless of
+ * the pointer identifier).
*
- * @see #getX(int)
+ * @return The X coordinate of the first pointer index in the coordinate
+ * space of the device display.
+ *
+ * @see #getX()
* @see #AXIS_X
*/
public final float getRawX() {
@@ -2696,12 +2717,13 @@
}
/**
- * Returns the original raw Y coordinate of this event. For touch
- * events on the screen, this is the original location of the event
- * on the screen, before it had been adjusted for the containing window
- * and views.
+ * Equivalent to {@link #getRawY(int)} for pointer index 0 (regardless of
+ * the pointer identifier).
*
- * @see #getY(int)
+ * @return The Y coordinate of the first pointer index in the coordinate
+ * space of the device display.
+ *
+ * @see #getY()
* @see #AXIS_Y
*/
public final float getRawY() {
@@ -2709,13 +2731,38 @@
}
/**
- * Returns the original raw X coordinate of this event. For touch
- * events on the screen, this is the original location of the event
- * on the screen, before it had been adjusted for the containing window
- * and views.
+ * Returns the X coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The coordinate is in the
+ * coordinate space of the device display, irrespective of system
+ * decorations and whether or not the system is in multi-window mode. If the
+ * app spans multiple screens in a multiple-screen environment, the
+ * coordinate space includes all of the spanned screens.
*
- * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
- * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ * <p>In multi-window mode, the coordinate space extends beyond the bounds
+ * of the app window to encompass the entire display area. For example, if
+ * the motion event occurs in the right-hand window of split-screen mode in
+ * landscape orientation, the left edge of the screen—not the left
+ * edge of the window—is the origin from which the X coordinate is
+ * calculated.
+ *
+ * <p>In multiple-screen scenarios, the coordinate space can span screens.
+ * For example, if the app is spanning both screens of a dual-screen device,
+ * and the motion event occurs on the right-hand screen, the X coordinate is
+ * calculated from the left edge of the left-hand screen to the point of the
+ * motion event on the right-hand screen. When the app is restricted to a
+ * single screen in a multiple-screen environment, the coordinate space
+ * includes only the screen on which the app is running.
+ *
+ * <p>Use {@link #getPointerId(int)} to get the pointer identifier for the
+ * pointer referenced by {@code pointerIndex}.
+ *
+ * @param pointerIndex Index of the pointer for which the X coordinate is
+ * returned. May be a value in the range of 0 (the first pointer that
+ * is down) to {@link #getPointerCount()} - 1.
+ * @return The X coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The unit is pixels. The
+ * value may contain a fractional portion for devices that are subpixel
+ * precise.
*
* @see #getX(int)
* @see #AXIS_X
@@ -2725,13 +2772,38 @@
}
/**
- * Returns the original raw Y coordinate of this event. For touch
- * events on the screen, this is the original location of the event
- * on the screen, before it had been adjusted for the containing window
- * and views.
+ * Returns the Y coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The coordinate is in the
+ * coordinate space of the device display, irrespective of system
+ * decorations and whether or not the system is in multi-window mode. If the
+ * app spans multiple screens in a multiple-screen environment, the
+ * coordinate space includes all of the spanned screens.
*
- * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
- * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ * <p>In multi-window mode, the coordinate space extends beyond the bounds
+ * of the app window to encompass the entire device screen. For example, if
+ * the motion event occurs in the lower window of split-screen mode in
+ * portrait orientation, the top edge of the screen—not the top edge
+ * of the window—is the origin from which the Y coordinate is
+ * determined.
+ *
+ * <p>In multiple-screen scenarios, the coordinate space can span screens.
+ * For example, if the app is spanning both screens of a dual-screen device
+ * that's rotated 90 degrees, and the motion event occurs on the lower
+ * screen, the Y coordinate is calculated from the top edge of the upper
+ * screen to the point of the motion event on the lower screen. When the app
+ * is restricted to a single screen in a multiple-screen environment, the
+ * coordinate space includes only the screen on which the app is running.
+ *
+ * <p>Use {@link #getPointerId(int)} to get the pointer identifier for the
+ * pointer referenced by {@code pointerIndex}.
+ *
+ * @param pointerIndex Index of the pointer for which the Y coordinate is
+ * returned. May be a value in the range of 0 (the first pointer that
+ * is down) to {@link #getPointerCount()} - 1.
+ * @return The Y coordinate of the pointer referenced by
+ * {@code pointerIndex} for this motion event. The unit is pixels. The
+ * value may contain a fractional portion for devices that are subpixel
+ * precise.
*
* @see #getY(int)
* @see #AXIS_Y
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f2ddf52..ffa577a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28283,7 +28283,7 @@
* {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be
* available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li>
*
- * <li>Events from a touchpad will be delivered with the source
+ * <li>Events from a touchpad or trackpad will be delivered with the source
* {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers
* on the touchpad will be available through {@link MotionEvent#getX(int)} and
* {@link MotionEvent#getY(int)}, and their relative movements are stored in
@@ -28292,6 +28292,12 @@
* <li>Events from other types of devices, such as touchscreens, will not be affected.</li>
* </ul>
* <p>
+ * When pointer capture changes, connected mouse and trackpad devices may be reconfigured,
+ * and their properties (such as their sources or motion ranges) may change. Use an
+ * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device
+ * changes (which may happen after enabling or disabling pointer capture), and use
+ * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}.
+ * <p>
* Events captured through pointer capture will be dispatched to
* {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an
* {@link OnCapturedPointerListener} is set, and otherwise to
diff --git a/core/java/com/android/internal/usb/OWNERS b/core/java/com/android/internal/usb/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/core/java/com/android/internal/usb/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 9098d46..d73db62 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -24,8 +24,18 @@
namespace android {
-// Converstion to/from Java IBinder Object and C++ IBinder instance.
+/**
+ * Conversion to Java IBinder Object from C++ IBinder instance.
+ *
+ * WARNING: this function returns global and local references. This can be
+ * figured out using GetObjectRefType. Though, when this function is called
+ * from within a Java context, the local ref will automatically be cleaned
+ * up. If this is called outside of a Java frame,
+ * PushObjectFrame/PopObjectFrame can simulate this automatic cleanup. The
+ * platform provides ScopedLocalFrame as an RAII object for this.
+ */
extern jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+/** Conversion from Java IBinder Object to C++ IBinder instance. */
extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5023927..86e97d5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -110,6 +110,8 @@
using android::zygote::ZygoteFailure;
+using Action = android_mallopt_gwp_asan_options_t::Action;
+
// This type is duplicated in fd_utils.h
typedef const std::function<void(std::string)>& fail_fn_t;
@@ -1597,10 +1599,11 @@
// since the directory is owned by root.
if (!is_system_server && getuid() == 0) {
const int rc = createProcessGroup(uid, getpid());
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else if (rc != 0) {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ if (rc != 0) {
+ fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
+ "CONFIG_CGROUP_CPUACCT?")
+ : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
+ /* pid= */ 0, strerror(-rc)));
}
}
@@ -1717,16 +1720,24 @@
// runtime.
runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
- bool forceEnableGwpAsan = false;
+ const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+ android_mallopt_gwp_asan_options_t gwp_asan_options;
+ // The system server doesn't have its nice name set by the time SpecializeCommon is called.
+ gwp_asan_options.program_name = nice_name_ptr ?: process_name;
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
default:
case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
+ gwp_asan_options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
break;
case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
- forceEnableGwpAsan = true;
- [[fallthrough]];
+ gwp_asan_options.desire = Action::TURN_ON_FOR_APP;
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+ break;
case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
- android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
+ gwp_asan_options.desire = Action::TURN_ON_WITH_SAMPLING;
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+ break;
}
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
// runtime.
@@ -1739,7 +1750,6 @@
AStatsSocket_close();
const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
- const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 679a4f0..add645de 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -296,7 +296,7 @@
++buffersAllocd;
// MMap explicitly to get it page aligned.
void *bufferMem = mmap(NULL, sizeof(NativeCommandBuffer), PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0);
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
// Currently we mmap and unmap one for every request handled by the Java code.
// That could be improved, but unclear it matters.
if (bufferMem == MAP_FAILED) {
diff --git a/graphics/TEST_MAPPING b/graphics/TEST_MAPPING
index 10bd0ee..abeaf19 100644
--- a/graphics/TEST_MAPPING
+++ b/graphics/TEST_MAPPING
@@ -1,7 +1,12 @@
{
"presubmit": [
{
- "name": "CtsGraphicsTestCases"
+ "name": "CtsGraphicsTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
index 2e54e63..6981332 100644
--- a/keystore/java/android/security/GenerateRkpKey.java
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -16,6 +16,8 @@
package android.security;
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -24,6 +26,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -57,6 +61,21 @@
private Context mContext;
private CountDownLatch mCountDownLatch;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ IGenerateRkpKeyService.Status.OK,
+ IGenerateRkpKeyService.Status.NO_NETWORK_CONNECTIVITY,
+ IGenerateRkpKeyService.Status.NETWORK_COMMUNICATION_ERROR,
+ IGenerateRkpKeyService.Status.DEVICE_NOT_REGISTERED,
+ IGenerateRkpKeyService.Status.HTTP_CLIENT_ERROR,
+ IGenerateRkpKeyService.Status.HTTP_SERVER_ERROR,
+ IGenerateRkpKeyService.Status.HTTP_UNKNOWN_ERROR,
+ IGenerateRkpKeyService.Status.INTERNAL_ERROR,
+ })
+ public @interface Status {
+ }
+
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
@@ -81,12 +100,14 @@
mContext = context;
}
- private void bindAndSendCommand(int command, int securityLevel) throws RemoteException {
+ @Status
+ private int bindAndSendCommand(int command, int securityLevel) throws RemoteException {
Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ int returnCode = IGenerateRkpKeyService.Status.OK;
if (comp == null) {
// On a system that does not use RKP, the RemoteProvisioner app won't be installed.
- return;
+ return returnCode;
}
intent.setComponent(comp);
mCountDownLatch = new CountDownLatch(1);
@@ -102,7 +123,7 @@
if (mBinder != null) {
switch (command) {
case NOTIFY_EMPTY:
- mBinder.generateKey(securityLevel);
+ returnCode = mBinder.generateKey(securityLevel);
break;
case NOTIFY_KEY_GENERATED:
mBinder.notifyKeyGenerated(securityLevel);
@@ -112,16 +133,21 @@
}
} else {
Log.e(TAG, "Binder object is null; failed to bind to GenerateRkpKeyService.");
+ returnCode = IGenerateRkpKeyService.Status.INTERNAL_ERROR;
}
mContext.unbindService(mConnection);
+ return returnCode;
}
/**
* Fulfills the use case of (2) described in the class documentation. Blocks until the
* RemoteProvisioner application can get new attestation keys signed by the server.
+ * @return the status of the key generation
*/
- public void notifyEmpty(int securityLevel) throws RemoteException {
- bindAndSendCommand(NOTIFY_EMPTY, securityLevel);
+ @CheckResult
+ @Status
+ public int notifyEmpty(int securityLevel) throws RemoteException {
+ return bindAndSendCommand(NOTIFY_EMPTY, securityLevel);
}
/**
diff --git a/keystore/java/android/security/IGenerateRkpKeyService.aidl b/keystore/java/android/security/IGenerateRkpKeyService.aidl
index 5f1d669..eeaeb27 100644
--- a/keystore/java/android/security/IGenerateRkpKeyService.aidl
+++ b/keystore/java/android/security/IGenerateRkpKeyService.aidl
@@ -26,11 +26,35 @@
* @hide
*/
interface IGenerateRkpKeyService {
+ @JavaDerive(toString=true)
+ @Backing(type="int")
+ enum Status {
+ /** No error(s) occurred */
+ OK = 0,
+ /** Unable to provision keys due to a lack of internet connectivity. */
+ NO_NETWORK_CONNECTIVITY = 1,
+ /** An error occurred while communicating with the RKP server. */
+ NETWORK_COMMUNICATION_ERROR = 2,
+ /** The given device was not registered with the RKP backend. */
+ DEVICE_NOT_REGISTERED = 4,
+ /** The RKP server returned an HTTP client error, indicating a misbehaving client. */
+ HTTP_CLIENT_ERROR = 5,
+ /** The RKP server returned an HTTP server error, indicating something went wrong on the server. */
+ HTTP_SERVER_ERROR = 6,
+ /** The RKP server returned an HTTP status that is unknown. This should never happen. */
+ HTTP_UNKNOWN_ERROR = 7,
+ /** An unexpected internal error occurred. This should never happen. */
+ INTERNAL_ERROR = 8,
+ }
+
/**
* Ping the provisioner service to let it know an app generated a key. This may or may not have
* consumed a remotely provisioned attestation key, so the RemoteProvisioner app should check.
*/
oneway void notifyKeyGenerated(in int securityLevel);
- /** Ping the provisioner service to indicate there are no remaining attestation keys left. */
- void generateKey(in int securityLevel);
+
+ /**
+ * Ping the provisioner service to indicate there are no remaining attestation keys left.
+ */
+ Status generateKey(in int securityLevel);
}
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 3d53cfb..c2cd6ff 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -345,6 +345,12 @@
case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
return new KeyStoreException(errorCode, "Key permanently invalidated",
serviceErrorMessage);
+ case ResponseCode.OUT_OF_KEYS:
+ // Getting a more specific RKP status requires the security level, which we
+ // don't have here. Higher layers of the stack can interpret this exception
+ // and add more flavor.
+ return new KeyStoreException(errorCode, serviceErrorMessage,
+ KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE);
default:
return new KeyStoreException(errorCode, String.valueOf(errorCode),
serviceErrorMessage);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 5950b5b..40659f5 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -28,6 +28,7 @@
import android.os.Build;
import android.os.RemoteException;
import android.security.GenerateRkpKey;
+import android.security.IGenerateRkpKeyService;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore2;
import android.security.KeyStoreException;
@@ -624,7 +625,7 @@
* GenerateRkpKey.notifyEmpty() will delay for a while before returning.
*/
result = generateKeyPairHelper();
- if (result.rkpStatus == KeyStoreException.RKP_SUCCESS) {
+ if (result.rkpStatus == KeyStoreException.RKP_SUCCESS && result.keyPair != null) {
return result.keyPair;
}
}
@@ -706,27 +707,12 @@
success = true;
KeyPair kp = new KeyPair(publicKey, publicKey.getPrivateKey());
return new GenerateKeyPairHelperResult(0, kp);
- } catch (android.security.KeyStoreException e) {
+ } catch (KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
case ResponseCode.OUT_OF_KEYS:
- GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
- .currentApplication());
- try {
- //TODO: When detailed error information is available from the remote
- //provisioner, propagate it up.
- keyGen.notifyEmpty(securityLevel);
- } catch (RemoteException f) {
- KeyStoreException ksException = new KeyStoreException(
- ResponseCode.OUT_OF_KEYS,
- "Remote exception: " + f.getMessage(),
- KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE);
- throw new ProviderException("Failed to talk to RemoteProvisioner",
- ksException);
- }
- return new GenerateKeyPairHelperResult(
- KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE, null);
+ throw makeOutOfKeysException(e, securityLevel);
default:
ProviderException p = new ProviderException("Failed to generate key pair.", e);
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
@@ -752,6 +738,52 @@
}
}
+ // In case keystore reports OUT_OF_KEYS, call this handler in an attempt to remotely provision
+ // some keys.
+ private ProviderException makeOutOfKeysException(KeyStoreException e, int securityLevel) {
+ GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+ .currentApplication());
+ KeyStoreException ksException;
+ try {
+ final int keyGenStatus = keyGen.notifyEmpty(securityLevel);
+ // Default stance: temporary error. This is a hint to the caller to try again with
+ // exponential back-off.
+ int rkpStatus;
+ switch (keyGenStatus) {
+ case IGenerateRkpKeyService.Status.NO_NETWORK_CONNECTIVITY:
+ rkpStatus = KeyStoreException.RKP_FETCHING_PENDING_CONNECTIVITY;
+ break;
+ case IGenerateRkpKeyService.Status.DEVICE_NOT_REGISTERED:
+ rkpStatus = KeyStoreException.RKP_SERVER_REFUSED_ISSUANCE;
+ break;
+ case IGenerateRkpKeyService.Status.OK:
+ // This will actually retry once immediately, so on "OK" go ahead and return
+ // "temporarily unavailable". @see generateKeyPair
+ case IGenerateRkpKeyService.Status.NETWORK_COMMUNICATION_ERROR:
+ case IGenerateRkpKeyService.Status.HTTP_CLIENT_ERROR:
+ case IGenerateRkpKeyService.Status.HTTP_SERVER_ERROR:
+ case IGenerateRkpKeyService.Status.HTTP_UNKNOWN_ERROR:
+ case IGenerateRkpKeyService.Status.INTERNAL_ERROR:
+ default:
+ // These errors really should never happen. The best we can do is assume they
+ // are transient and hint to the caller to retry with back-off.
+ rkpStatus = KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE;
+ break;
+ }
+ ksException = new KeyStoreException(
+ ResponseCode.OUT_OF_KEYS,
+ "Out of RKP keys due to IGenerateRkpKeyService status: " + keyGenStatus,
+ rkpStatus);
+ } catch (RemoteException f) {
+ ksException = new KeyStoreException(
+ ResponseCode.OUT_OF_KEYS,
+ "Remote exception: " + f.getMessage(),
+ KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE);
+ }
+ ksException.initCause(e);
+ return new ProviderException("Failed to talk to RemoteProvisioner", ksException);
+ }
+
private void addAttestationParameters(@NonNull List<KeyParameter> params)
throws ProviderException, IllegalArgumentException, DeviceIdAttestationException {
byte[] challenge = mSpec.getAttestationChallenge();
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 77709d7..5c75e47 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3634,6 +3634,7 @@
.parseIntRange(info.getString("quality-range"), mQualityRange);
}
if (info.containsKey("feature-bitrate-modes")) {
+ mBitControl = 0;
for (String mode: info.getString("feature-bitrate-modes").split(",")) {
mBitControl |= (1 << parseBitrateMode(mode));
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 522b021..050ae72 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1147,7 +1147,7 @@
* A key describing the per-frame average block QP (Quantization Parameter).
* This is a part of a video 'Encoding Statistics' export feature.
* This value is emitted from video encoder for a video frame.
- * The average value is rounded down (using floor()) to integer value.
+ * The average value is rounded to the nearest integer value.
*
* The associated value is an integer.
*/
diff --git a/omapi/java/android/se/omapi/SEService.java b/omapi/java/android/se/omapi/SEService.java
index f42ca36..306c09a 100644
--- a/omapi/java/android/se/omapi/SEService.java
+++ b/omapi/java/android/se/omapi/SEService.java
@@ -118,6 +118,16 @@
});
}
}
+
+ @Override
+ public String getInterfaceHash() {
+ return ISecureElementListener.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return ISecureElementListener.VERSION;
+ }
}
private SEListener mSEListener = new SEListener();
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 6c8a92d..4b07eaf 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -73,6 +73,7 @@
zakcohen@google.com
jernej@google.com
jglazier@google.com
+peskal@google.com
#Android Auto
hseog@google.com
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 99e12a8..ce0e69c 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -91,6 +91,10 @@
if (!volume.isMountedWritable()) {
continue;
}
+ // gsid only supports vfat external storage.
+ if (!"vfat".equalsIgnoreCase(volume.fsType)) {
+ continue;
+ }
DiskInfo disk = volume.getDisk();
long mega = disk.size >> 20;
Slog.i(TAG, volume.getPath() + ": " + mega + " MB");
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 81627a0..2ab477f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1803,7 +1803,10 @@
mComputedNightMode = false;
return;
}
- resetNightModeOverrideLocked();
+ if (mNightMode != MODE_NIGHT_AUTO || (mTwilightManager != null
+ && mTwilightManager.getLastTwilightState() != null)) {
+ resetNightModeOverrideLocked();
+ }
}
private boolean resetNightModeOverrideLocked() {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index eefeee3..f26d9f9 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -52,6 +52,7 @@
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
import android.os.Binder;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -82,6 +83,7 @@
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -162,7 +164,8 @@
public static final boolean VDBG = false; // STOPSHIP: if true
@VisibleForTesting(visibility = Visibility.PRIVATE)
- static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml";
+ static final String VCN_CONFIG_FILE =
+ new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath();
/* Binder context for this service */
@NonNull private final Context mContext;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0f450e1..ec9f1fe 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,6 +28,7 @@
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
@@ -45,6 +46,13 @@
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
@@ -1415,6 +1423,10 @@
final ActivityThread mSystemThread;
final UidObserverController mUidObserverController;
+ private volatile IUidObserver mNetworkPolicyUidObserver;
+
+ @GuardedBy("mUidNetworkBlockedReasons")
+ private final SparseIntArray mUidNetworkBlockedReasons = new SparseIntArray();
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
@@ -6784,6 +6796,9 @@
}
synchronized (mProcLock) {
+ if (mPendingStartActivityUids.isPendingTopUid(uid)) {
+ return PROCESS_STATE_TOP;
+ }
return mProcessList.getUidProcStateLOSP(uid);
}
}
@@ -10375,7 +10390,7 @@
"Native",
"System", "Persistent", "Persistent Service", "Foreground",
"Visible", "Perceptible", "Perceptible Low", "Perceptible Medium",
- "Heavy Weight", "Backup",
+ "Backup", "Heavy Weight",
"A Services", "Home",
"Previous", "B Services", "Cached"
};
@@ -10383,7 +10398,7 @@
"native",
"sys", "pers", "persvc", "fore",
"vis", "percept", "perceptl", "perceptm",
- "heavy", "backup",
+ "backup", "heavy",
"servicea", "home",
"prev", "serviceb", "cached"
};
@@ -14447,7 +14462,6 @@
uid, change, procState, procStateSeq, capability, ephemeral);
if (uidRec != null) {
uidRec.setLastReportedChange(enqueuedChange);
- uidRec.updateLastDispatchedProcStateSeq(enqueuedChange);
}
// Directly update the power manager, since we sit on top of it and it is critical
@@ -15585,18 +15599,13 @@
return;
}
record.lastNetworkUpdatedProcStateSeq = procStateSeq;
- if (record.curProcStateSeq > procStateSeq) {
- if (DEBUG_NETWORK) {
- Slog.d(TAG_NETWORK, "No need to handle older seq no., Uid: " + uid
- + ", curProcstateSeq: " + record.curProcStateSeq
- + ", procStateSeq: " + procStateSeq);
- }
- return;
- }
- if (record.waitingForNetwork) {
+ if (record.procStateSeqWaitingForNetwork != 0
+ && procStateSeq >= record.procStateSeqWaitingForNetwork) {
if (DEBUG_NETWORK) {
Slog.d(TAG_NETWORK, "Notifying all blocking threads for uid: " + uid
- + ", procStateSeq: " + procStateSeq);
+ + ", procStateSeq: " + procStateSeq
+ + ", procStateSeqWaitingForNetwork: "
+ + record.procStateSeqWaitingForNetwork);
}
record.networkStateLock.notifyAll();
}
@@ -15604,6 +15613,17 @@
}
@Override
+ public void onUidBlockedReasonsChanged(int uid, int blockedReasons) {
+ synchronized (mUidNetworkBlockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ mUidNetworkBlockedReasons.delete(uid);
+ } else {
+ mUidNetworkBlockedReasons.put(uid, blockedReasons);
+ }
+ }
+ }
+
+ @Override
public boolean isRuntimeRestarted() {
return mSystemServiceManager.isRuntimeRestarted();
}
@@ -16301,8 +16321,51 @@
}
@Override
- public void addPendingTopUid(int uid, int pid) {
- mPendingStartActivityUids.add(uid, pid);
+ public void addPendingTopUid(int uid, int pid, @Nullable IApplicationThread thread) {
+ final boolean isNewPending = mPendingStartActivityUids.add(uid, pid);
+ // We need to update the network rules for the app coming to the top state so that
+ // it can access network when the device or the app is in a restricted state
+ // (e.g. battery/data saver) but since waiting for updateOomAdj to complete and then
+ // informing NetworkPolicyManager might get delayed, informing the state change as soon
+ // as we know app is going to come to the top state.
+ if (isNewPending && mNetworkPolicyUidObserver != null) {
+ try {
+ final long procStateSeq = mProcessList.getNextProcStateSeq();
+ mNetworkPolicyUidObserver.onUidStateChanged(uid, PROCESS_STATE_TOP,
+ procStateSeq, PROCESS_CAPABILITY_ALL);
+ if (thread != null && isNetworkingBlockedForUid(uid)) {
+ thread.setNetworkBlockSeq(procStateSeq);
+ }
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Error calling setNetworkBlockSeq", e);
+ }
+ }
+ }
+
+ private boolean isNetworkingBlockedForUid(int uid) {
+ synchronized (mUidNetworkBlockedReasons) {
+ // TODO: We can consider only those blocked reasons that will be overridden
+ // by the TOP state. For other ones, there is no point in waiting.
+ // TODO: We can reuse this data in
+ // ProcessList#incrementProcStateSeqAndNotifyAppsLOSP instead of calling into
+ // NetworkManagementService.
+ final int uidBlockedReasons = mUidNetworkBlockedReasons.get(
+ uid, BLOCKED_REASON_NONE);
+ if (uidBlockedReasons == BLOCKED_REASON_NONE) {
+ return false;
+ }
+ final int topExemptedBlockedReasons = BLOCKED_REASON_BATTERY_SAVER
+ | BLOCKED_REASON_DOZE
+ | BLOCKED_REASON_APP_STANDBY
+ | BLOCKED_REASON_LOW_POWER_STANDBY
+ | BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ final int effectiveBlockedReasons =
+ uidBlockedReasons & ~topExemptedBlockedReasons;
+ // Only consider it as blocked if it is not blocked by a reason
+ // that is not exempted by app being in the top state.
+ return effectiveBlockedReasons == BLOCKED_REASON_NONE;
+ }
}
@Override
@@ -16449,6 +16512,14 @@
public void setStopUserOnSwitch(int value) {
ActivityManagerService.this.setStopUserOnSwitch(value);
}
+
+ @Override
+ public void registerNetworkPolicyUidObserver(@NonNull IUidObserver observer,
+ int which, int cutpoint, @NonNull String callingPackage) {
+ mNetworkPolicyUidObserver = observer;
+ mUidObserverController.register(observer, which, cutpoint, callingPackage,
+ Binder.getCallingUid());
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
@@ -16528,23 +16599,6 @@
}
}
synchronized (record.networkStateLock) {
- if (record.lastDispatchedProcStateSeq < procStateSeq) {
- if (DEBUG_NETWORK) {
- Slog.d(TAG_NETWORK, "Uid state change for seq no. " + procStateSeq + " is not "
- + "dispatched to NPMS yet, so don't wait. Uid: " + callingUid
- + " lastProcStateSeqDispatchedToObservers: "
- + record.lastDispatchedProcStateSeq);
- }
- return;
- }
- if (record.curProcStateSeq > procStateSeq) {
- if (DEBUG_NETWORK) {
- Slog.d(TAG_NETWORK, "Ignore the wait requests for older seq numbers. Uid: "
- + callingUid + ", curProcStateSeq: " + record.curProcStateSeq
- + ", procStateSeq: " + procStateSeq);
- }
- return;
- }
if (record.lastNetworkUpdatedProcStateSeq >= procStateSeq) {
if (DEBUG_NETWORK) {
Slog.d(TAG_NETWORK, "Network rules have been already updated for seq no. "
@@ -16560,9 +16614,9 @@
+ " Uid: " + callingUid + " procStateSeq: " + procStateSeq);
}
final long startTime = SystemClock.uptimeMillis();
- record.waitingForNetwork = true;
+ record.procStateSeqWaitingForNetwork = procStateSeq;
record.networkStateLock.wait(mWaitForNetworkTimeoutMs);
- record.waitingForNetwork = false;
+ record.procStateSeqWaitingForNetwork = 0;
final long totalTime = SystemClock.uptimeMillis() - startTime;
if (totalTime >= mWaitForNetworkTimeoutMs || DEBUG_NETWORK) {
Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 0bf0fe2..98412bd 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -577,12 +577,14 @@
mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
PackageWatchdog.FAILURE_REASON_APP_CRASH);
- mService.mProcessList.noteAppKill(r, (crashInfo != null
- && "Native crash".equals(crashInfo.exceptionClassName))
- ? ApplicationExitInfo.REASON_CRASH_NATIVE
- : ApplicationExitInfo.REASON_CRASH,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- "crash");
+ synchronized (mService) {
+ mService.mProcessList.noteAppKill(r, (crashInfo != null
+ && "Native crash".equals(crashInfo.exceptionClassName))
+ ? ApplicationExitInfo.REASON_CRASH_NATIVE
+ : ApplicationExitInfo.REASON_CRASH,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "crash");
+ }
}
final int relaunchReason = r != null
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2030b19..dedd898 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1978,7 +1978,7 @@
mHandler.post(() -> {
synchronized (mStats) {
mStats.noteBluetoothScanStoppedFromSourceLocked(localWs, isUnoptimized,
- uptime, elapsedRealtime);
+ elapsedRealtime, uptime);
}
});
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9e04410..ce40f85 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2911,8 +2911,7 @@
// To avoid some abuse patterns, we are going to be careful about what we consider
// to be an app interaction. Being the top activity doesn't count while the display
// is sleeping, nor do short foreground services.
- if (state.getCurProcState() <= PROCESS_STATE_TOP
- || state.getCurProcState() == PROCESS_STATE_BOUND_TOP) {
+ if (ActivityManager.isProcStateConsideredInteraction(state.getCurProcState())) {
isInteraction = true;
state.setFgInteractionTime(0);
} else if (state.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) {
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 20f6bb2..5beda31 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -44,10 +44,12 @@
mContext = context;
}
- synchronized void add(int uid, int pid) {
+ synchronized boolean add(int uid, int pid) {
if (mPendingUids.get(uid) == null) {
mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime()));
+ return true;
}
+ return false;
}
synchronized void delete(int uid, long nowElapsed) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1e66ed4..ca16f57 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -482,9 +482,8 @@
* Having a global counter ensures that seq numbers are monotonically increasing for a
* particular uid even when the uidRecord is re-created.
*/
- @GuardedBy("mService")
@VisibleForTesting
- long mProcStateSeqCounter = 0;
+ volatile long mProcStateSeqCounter = 0;
/**
* A global counter for generating sequence numbers to uniquely identify pending process starts.
@@ -2426,8 +2425,8 @@
if (!regularZygote) {
// webview and app zygote don't have the permission to create the nodes
if (Process.createProcessGroup(uid, startResult.pid) < 0) {
- Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
- + app.processName + " (" + startResult.pid + ")");
+ throw new AssertionError("Unable to create process group for " + app.processName
+ + " (" + startResult.pid + ")");
}
}
@@ -4878,13 +4877,17 @@
}
/**
- * Checks if any uid is coming from background to foreground or vice versa and if so, increments
- * the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter
- * {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block.
+ * Increments the {@link UidRecord#curProcStateSeq} for all uids using global seq counter
+ * {@link ProcessList#mProcStateSeqCounter} and checks if any uid is coming
+ * from background to foreground or vice versa and if so, notifies the app if it needs to block.
*/
@VisibleForTesting
@GuardedBy(anyOf = {"mService", "mProcLock"})
void incrementProcStateSeqAndNotifyAppsLOSP(ActiveUids activeUids) {
+ for (int i = activeUids.size() - 1; i >= 0; --i) {
+ final UidRecord uidRec = activeUids.valueAt(i);
+ uidRec.curProcStateSeq = getNextProcStateSeq();
+ }
if (mService.mWaitForNetworkTimeoutMs <= 0) {
return;
}
@@ -4911,7 +4914,6 @@
continue;
}
synchronized (uidRec.networkStateLock) {
- uidRec.curProcStateSeq = ++mProcStateSeqCounter; // TODO: use method
if (blockState == NETWORK_STATE_BLOCK) {
if (blockingUids == null) {
blockingUids = new ArrayList<>();
@@ -4922,7 +4924,7 @@
Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking"
+ " threads for uid: " + uidRec);
}
- if (uidRec.waitingForNetwork) {
+ if (uidRec.procStateSeqWaitingForNetwork != 0) {
uidRec.networkStateLock.notifyAll();
}
}
@@ -4956,6 +4958,10 @@
}
}
+ long getNextProcStateSeq() {
+ return ++mProcStateSeqCounter;
+ }
+
/**
* Create a server socket in system_server, zygote will connect to it
* in order to send unsolicited messages to system_server.
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index c1bfe25..67b9ae6 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -219,7 +219,6 @@
validateUid.setCurProcState(item.procState);
validateUid.setSetCapability(item.capability);
validateUid.setCurCapability(item.capability);
- validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
}
}
}
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 4ba59fa..2ec08a4 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -95,16 +95,9 @@
long lastNetworkUpdatedProcStateSeq;
/**
- * Last seq number for which AcitivityManagerService dispatched uid state change to
- * NetworkPolicyManagerService.
+ * Indicates if any thread is waiting for network rules to get updated for {@link #mUid}.
*/
- @GuardedBy("networkStateUpdate")
- long lastDispatchedProcStateSeq;
-
- /**
- * Indicates if any thread is waiting for network rules to get updated for {@link #uid}.
- */
- volatile boolean waitingForNetwork;
+ volatile long procStateSeqWaitingForNetwork;
/**
* Indicates whether this uid has internet permission or not.
@@ -309,18 +302,6 @@
mUid) == PackageManager.PERMISSION_GRANTED;
}
- /**
- * If the change being dispatched is not CHANGE_GONE (not interested in
- * these changes), then update the {@link #lastDispatchedProcStateSeq} with
- * {@link #curProcStateSeq}.
- */
- public void updateLastDispatchedProcStateSeq(int changeToDispatch) {
- if ((changeToDispatch & CHANGE_GONE) == 0) {
- lastDispatchedProcStateSeq = curProcStateSeq;
- }
- }
-
-
void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(UidRecordProto.UID, mUid);
@@ -341,7 +322,6 @@
proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq);
proto.write(UidRecordProto.ProcStateSequence.LAST_NETWORK_UPDATED,
lastNetworkUpdatedProcStateSeq);
- proto.write(UidRecordProto.ProcStateSequence.LAST_DISPATCHED, lastDispatchedProcStateSeq);
proto.end(seqToken);
proto.end(token);
@@ -412,8 +392,6 @@
sb.append(curProcStateSeq);
sb.append(",");
sb.append(lastNetworkUpdatedProcStateSeq);
- sb.append(",");
- sb.append(lastDispatchedProcStateSeq);
sb.append(")}");
return sb.toString();
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 33440a3..d9db28a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -85,6 +85,7 @@
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
@@ -208,7 +209,6 @@
private final NetworkInfo mNetworkInfo;
private int mLegacyState;
@VisibleForTesting protected String mPackage;
- private String mSessionKey;
private int mOwnerUID;
private boolean mIsPackageTargetingAtLeastQ;
@VisibleForTesting
@@ -1990,9 +1990,7 @@
public synchronized int getActiveVpnType() {
if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE;
if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE;
- return mVpnRunner instanceof IkeV2VpnRunner
- ? VpnManager.TYPE_VPN_PLATFORM
- : VpnManager.TYPE_VPN_LEGACY;
+ return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY;
}
private void updateAlwaysOnNotification(DetailedState networkState) {
@@ -2267,6 +2265,11 @@
profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
return;
+ case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
+ // All the necessary IKE options should come from IkeTunnelConnectionParams in the
+ // profile.
+ startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
+ return;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
racoon = new String[] {
iface, profile.server, "udppsk", profile.ipsecIdentifier,
@@ -2518,6 +2521,7 @@
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
+ private final String mSessionKey;
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
super(TAG);
@@ -2702,10 +2706,23 @@
resetIkeState();
mActiveNetwork = network;
- final IkeSessionParams ikeSessionParams =
- VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, network);
- final ChildSessionParams childSessionParams =
- VpnIkev2Utils.buildChildSessionParams(mProfile.getAllowedAlgorithms());
+ // Get Ike options from IkeTunnelConnectionParams if it's available in the
+ // profile.
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ final IkeSessionParams ikeSessionParams;
+ final ChildSessionParams childSessionParams;
+ if (ikeTunConnParams != null) {
+ final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(
+ ikeTunConnParams.getIkeSessionParams()).setNetwork(network);
+ ikeSessionParams = builder.build();
+ childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams();
+ } else {
+ ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams(
+ mContext, mProfile, network);
+ childSessionParams = VpnIkev2Utils.buildChildSessionParams(
+ mProfile.getAllowedAlgorithms());
+ }
// TODO: Remove the need for adding two unused addresses with
// IPsec tunnels.
@@ -2850,7 +2867,6 @@
*/
private void disconnectVpnRunner() {
mActiveNetwork = null;
- mSessionKey = null;
mIsRunning = false;
resetIkeState();
@@ -3226,6 +3242,7 @@
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+ case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_IPSEC_TUNNELS)) {
throw new UnsupportedOperationException(
@@ -3279,7 +3296,7 @@
}
private boolean isCurrentIkev2VpnLocked(@NonNull String packageName) {
- return isCurrentPreparedPackage(packageName) && mVpnRunner instanceof IkeV2VpnRunner;
+ return isCurrentPreparedPackage(packageName) && isIkev2VpnRunner();
}
/**
@@ -3333,6 +3350,16 @@
return VpnProfile.decode("" /* Key unused */, encoded);
}
+ private boolean isIkev2VpnRunner() {
+ return (mVpnRunner instanceof IkeV2VpnRunner);
+ }
+
+ @GuardedBy("this")
+ @Nullable
+ private String getSessionKeyLocked() {
+ return isIkev2VpnRunner() ? ((IkeV2VpnRunner) mVpnRunner).mSessionKey : null;
+ }
+
/**
* Starts an already provisioned VPN Profile, keyed by package name.
*
@@ -3360,7 +3387,11 @@
}
startVpnProfilePrivileged(profile, packageName);
- return mSessionKey;
+ if (!isIkev2VpnRunner()) {
+ throw new IllegalStateException("mVpnRunner shouldn't be null and should also be "
+ + "an instance of Ikev2VpnRunner");
+ }
+ return getSessionKeyLocked();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -3399,6 +3430,7 @@
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+ case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
mVpnRunner =
new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile));
mVpnRunner.start();
@@ -3462,11 +3494,8 @@
}
private VpnProfileState makeVpnProfileState() {
- // TODO: mSessionKey will be moved to Ikev2VpnRunner once aosp/2007077 is merged, so after
- // merging aosp/2007077, here should check Ikev2VpnRunner is null or not. Session key will
- // be null if Ikev2VpnRunner is null.
- return new VpnProfileState(getStateFromLegacyState(mLegacyState), mSessionKey, mAlwaysOn,
- mLockdown);
+ return new VpnProfileState(getStateFromLegacyState(mLegacyState),
+ isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown);
}
/**
diff --git a/services/core/java/com/android/server/health/HealthRegCallbackAidl.java b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
index 629011a..90a2f48 100644
--- a/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
+++ b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
@@ -115,5 +115,13 @@
public void healthInfoChanged(HealthInfo healthInfo) throws RemoteException {
mServiceInfoCallback.update(healthInfo);
}
+ @Override
+ public String getInterfaceHash() {
+ return IHealthInfoCallback.HASH;
+ }
+ @Override
+ public int getInterfaceVersion() {
+ return IHealthInfoCallback.VERSION;
+ }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 33ac6cd..c963154 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -77,6 +77,8 @@
private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
private static final int EVENT_APP_IDLE_WL_CHANGED = 14;
+ private static final int EVENT_METERED_ALLOWLIST_CHANGED = 15;
+ private static final int EVENT_METERED_DENYLIST_CHANGED = 16;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -89,7 +91,7 @@
void networkBlocked(int uid, @Nullable UidBlockedState uidBlockedState) {
synchronized (mLock) {
if (LOGD || uid == mDebugUid) {
- Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString());
+ Slog.d(TAG, "Blocked state of " + uid + ": " + uidBlockedState.toString());
}
if (uidBlockedState == null) {
mNetworkBlockedBuffer.networkBlocked(uid, BLOCKED_REASON_NONE, ALLOWED_REASON_NONE,
@@ -245,6 +247,24 @@
}
}
+ void meteredAllowlistChanged(int uid, boolean added) {
+ synchronized (mLock) {
+ if (LOGD || mDebugUid == uid) {
+ Slog.d(TAG, getMeteredAllowlistChangedLog(uid, added));
+ }
+ mEventsBuffer.meteredAllowlistChanged(uid, added);
+ }
+ }
+
+ void meteredDenylistChanged(int uid, boolean added) {
+ synchronized (mLock) {
+ if (LOGD || mDebugUid == uid) {
+ Slog.d(TAG, getMeteredDenylistChangedLog(uid, added));
+ }
+ mEventsBuffer.meteredDenylistChanged(uid, added);
+ }
+ }
+
void setDebugUid(int uid) {
mDebugUid = uid;
}
@@ -320,6 +340,14 @@
return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled;
}
+ private static String getMeteredAllowlistChangedLog(int uid, boolean added) {
+ return "metered-allowlist for " + uid + " changed to " + added;
+ }
+
+ private static String getMeteredDenylistChangedLog(int uid, boolean added) {
+ return "metered-denylist for " + uid + " changed to " + added;
+ }
+
private static String getFirewallChainName(int chain) {
switch (chain) {
case FIREWALL_CHAIN_DOZABLE:
@@ -520,6 +548,28 @@
data.timeStamp = System.currentTimeMillis();
}
+ public void meteredAllowlistChanged(int uid, boolean added) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_METERED_ALLOWLIST_CHANGED;
+ data.ifield1 = uid;
+ data.bfield1 = added;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void meteredDenylistChanged(int uid, boolean added) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_METERED_DENYLIST_CHANGED;
+ data.ifield1 = uid;
+ data.bfield1 = added;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
public void reverseDump(IndentingPrintWriter pw) {
final Data[] allData = toArray();
for (int i = allData.length - 1; i >= 0; --i) {
@@ -567,6 +617,10 @@
return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3);
case EVENT_FIREWALL_CHAIN_ENABLED:
return getFirewallChainEnabledLog(data.ifield1, data.bfield1);
+ case EVENT_METERED_ALLOWLIST_CHANGED:
+ return getMeteredAllowlistChangedLog(data.ifield1, data.bfield1);
+ case EVENT_METERED_DENYLIST_CHANGED:
+ return getMeteredDenylistChangedLog(data.ifield1, data.bfield1);
default:
return String.valueOf(data.type);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ea851ba..3858d7a 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -26,6 +26,9 @@
import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+import static android.app.ActivityManager.isProcStateConsideredInteraction;
+import static android.app.ActivityManager.procStateToString;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
@@ -90,6 +93,8 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
@@ -160,6 +165,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -168,6 +174,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
@@ -230,6 +237,7 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
+import android.util.SparseSetArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -418,6 +426,7 @@
private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20;
+
// TODO: Add similar docs for other messages.
/**
* Message to indicate that reasons for why an uid is blocked changed.
@@ -425,7 +434,8 @@
* arg2 = newBlockedReasons
* obj = oldBlockedReasons
*/
- private static final int MSG_BLOCKED_REASON_CHANGED = 21;
+ private static final int MSG_UID_BLOCKED_REASON_CHANGED = 21;
+
/**
* Message to indicate that subscription plans expired and should be cleared.
* arg1 = subId
@@ -434,6 +444,15 @@
*/
private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22;
+ /**
+ * Message to indicate that reasons for why some uids are blocked changed.
+ * obj = SparseArray<SomeArgs> where key = uid and value = SomeArgs object with
+ * value.argi1 = oldEffectiveBlockedReasons,
+ * value.argi2 = newEffectiveBlockedReasons,
+ * value.argi3 = uidRules
+ */
+ private static final int MSG_UIDS_BLOCKED_REASONS_CHANGED = 23;
+
private static final int UID_MSG_STATE_CHANGED = 100;
private static final int UID_MSG_GONE = 101;
@@ -471,7 +490,7 @@
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
- @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
+ @GuardedBy(anyOf = {"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
volatile boolean mSystemReady;
@GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
@@ -594,7 +613,7 @@
@GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidState> mUidState = new SparseArray<>();
- @GuardedBy("mUidRulesFirstLock")
+ @GuardedBy("mUidBlockedState")
private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
/** Objects used temporarily while computing the new blocked state for each uid. */
@@ -607,6 +626,9 @@
/** Map from network ID to last observed roaming state */
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkRoaming = new SparseBooleanArray();
+ /** Map from network ID to the last ifaces on it */
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ private SparseSetArray<String> mNetworkToIfaces = new SparseSetArray<>();
/** Map from netId to subId as of last update */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -909,6 +931,7 @@
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
mAppStandby = LocalServices.getService(AppStandbyInternal.class);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -986,12 +1009,11 @@
}
}
- mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
try {
final int changes = ActivityManager.UID_OBSERVER_PROCSTATE
| ActivityManager.UID_OBSERVER_GONE
| ActivityManager.UID_OBSERVER_CAPABILITY;
- mActivityManager.registerUidObserver(mUidObserver, changes,
+ mActivityManagerInternal.registerNetworkPolicyUidObserver(mUidObserver, changes,
NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android");
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
@@ -1107,7 +1129,9 @@
callbackInfo = new UidStateCallbackInfo();
mUidStateCallbackInfos.put(uid, callbackInfo);
}
- callbackInfo.update(uid, procState, procStateSeq, capability);
+ if (callbackInfo.procStateSeq == -1 || procStateSeq > callbackInfo.procStateSeq) {
+ callbackInfo.update(uid, procState, procStateSeq, capability);
+ }
if (!callbackInfo.isPending) {
mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
.sendToTarget();
@@ -1131,8 +1155,8 @@
private static final class UidStateCallbackInfo {
public int uid;
- public int procState;
- public long procStateSeq;
+ public int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+ public long procStateSeq = -1;
@ProcessCapability
public int capability;
public boolean isPending;
@@ -1324,11 +1348,28 @@
return changed;
}
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ private boolean updateNetworkToIfacesNL(int netId, @NonNull ArraySet<String> newIfaces) {
+ // TODO: Add a facility SparseSetArray.contains(key) to return whether the key exists.
+ final ArraySet<String> lastIfaces = mNetworkToIfaces.get(netId);
+ final boolean changed = lastIfaces == null ? true : !lastIfaces.equals(newIfaces);
+
+ if (changed) {
+ // Changed on the same network should remove last ifaces and add new ifaces.
+ // TODO: Add a facility SparseSetArray.put(key, value) for replacing the
+ // value for a given key.
+ mNetworkToIfaces.remove(netId);
+ for (String iface : newIfaces) {
+ mNetworkToIfaces.add(netId, iface);
+ }
+ }
+ return changed;
+ }
+
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {
- if (network == null || networkCapabilities == null) return;
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
synchronized (mNetworkPoliciesSecondLock) {
final boolean newMetered = !networkCapabilities
@@ -1347,6 +1388,25 @@
}
}
}
+
+ @Override
+ public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties lp) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ final ArraySet<String> newIfaces = new ArraySet<>(lp.getAllInterfaceNames());
+ final boolean ifacesChanged = updateNetworkToIfacesNL(network.getNetId(),
+ newIfaces);
+ if (ifacesChanged) {
+ updateNetworkRulesNL();
+ }
+ }
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ mNetworkToIfaces.remove(network.getNetId());
+ }
+ }
};
/**
@@ -3298,7 +3358,7 @@
if (mSystemReady) {
// Device idle change means we need to rebuild rules for all
// known apps, so do a global refresh.
- updateRulesForRestrictPowerUL();
+ handleDeviceIdleModeChangedUL(enabled);
}
}
if (enabled) {
@@ -3947,7 +4007,9 @@
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
- collectKeys(mUidBlockedState, knownUids);
+ synchronized (mUidBlockedState) {
+ collectKeys(mUidBlockedState, knownUids);
+ }
fout.println("Status for all known UIDs:");
fout.increaseIndent();
@@ -3965,12 +4027,14 @@
fout.print(uidState.toString());
}
- final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- fout.print(" blocked_state={null}");
- } else {
- fout.print(" blocked_state=");
- fout.print(uidBlockedState.toString());
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ fout.print(" blocked_state={null}");
+ } else {
+ fout.print(" blocked_state=");
+ fout.print(uidBlockedState);
+ }
}
fout.println();
}
@@ -4038,13 +4102,22 @@
* {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated.
*/
@GuardedBy("mUidRulesFirstLock")
- private boolean updateUidStateUL(int uid, int procState, @ProcessCapability int capability) {
+ private boolean updateUidStateUL(int uid, int procState, long procStateSeq,
+ @ProcessCapability int capability) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
try {
final UidState oldUidState = mUidState.get(uid);
+ if (oldUidState != null && procStateSeq < oldUidState.procStateSeq) {
+ if (LOGV) {
+ Slog.v(TAG, "Ignoring older uid state updates; uid=" + uid
+ + ",procState=" + procStateToString(procState) + ",seq=" + procStateSeq
+ + ",cap=" + capability + ",oldUidState=" + oldUidState);
+ }
+ return false;
+ }
if (oldUidState == null || oldUidState.procState != procState
|| oldUidState.capability != capability) {
- final UidState newUidState = new UidState(uid, procState, capability);
+ final UidState newUidState = new UidState(uid, procState, procStateSeq, capability);
// state changed, push updated rules
mUidState.put(uid, newUidState);
updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState);
@@ -4052,14 +4125,14 @@
isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
!= isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState);
if (allowedWhileIdleOrPowerSaveModeChanged) {
- updateRuleForAppIdleUL(uid);
+ updateRuleForAppIdleUL(uid, procState);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleUL(uid);
}
if (mRestrictPower) {
updateRuleForRestrictPowerUL(uid);
}
- updateRulesForPowerRestrictionsUL(uid);
+ updateRulesForPowerRestrictionsUL(uid, procState);
}
if (mLowPowerStandbyActive) {
boolean allowedInLpsChanged =
@@ -4067,7 +4140,7 @@
!= isProcStateAllowedWhileInLowPowerStandby(newUidState);
if (allowedInLpsChanged) {
if (!allowedWhileIdleOrPowerSaveModeChanged) {
- updateRulesForPowerRestrictionsUL(uid);
+ updateRulesForPowerRestrictionsUL(uid, procState);
}
updateRuleForLowPowerStandbyUL(uid);
}
@@ -4145,9 +4218,9 @@
mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> {
synchronized (mUidRulesFirstLock) {
- final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
+ final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(
uid);
- final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
+ final int newFirewallRule = getRestrictedModeFirewallRule(effectiveBlockedReasons);
// setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
// non-default rules.
@@ -4167,7 +4240,7 @@
@VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) {
- final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
+ final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated.
@@ -4175,37 +4248,48 @@
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added.
setUidFirewallRuleUL(FIREWALL_CHAIN_RESTRICTED, uid,
- getRestrictedModeFirewallRule(uidBlockedState));
+ getRestrictedModeFirewallRule(effectiveBlockedReasons));
}
}
@GuardedBy("mUidRulesFirstLock")
- private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- if (mRestrictedNetworkingMode) {
- uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
- } else {
- uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
- }
- if (hasRestrictedModeAccess(uid)) {
- uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
- } else {
- uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
- }
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- postBlockedReasonsChangedMsg(uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
+ private int updateBlockedReasonsForRestrictedModeUL(int uid) {
+ final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid);
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ if (mRestrictedNetworkingMode) {
+ uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+ } else {
+ uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if (hasRestrictedModeAccess) {
+ uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ } else {
+ uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ }
+ uidBlockedState.updateEffectiveBlockedReasons();
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+ ? RULE_NONE
+ : uidBlockedState.deriveUidRules();
}
- return uidBlockedState;
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+ handleBlockedReasonsChanged(uid,
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidRules);
+ }
+ return newEffectiveBlockedReasons;
}
- private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
- if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
+ private static int getRestrictedModeFirewallRule(int effectiveBlockedReasons) {
+ if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT;
} else {
@@ -4309,12 +4393,10 @@
mUidFirewallLowPowerStandbyModeRules.clear();
for (int i = mUidState.size() - 1; i >= 0; i--) {
final int uid = mUidState.keyAt(i);
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (hasInternetPermissionUL(uid) && uidBlockedState != null
- && (uidBlockedState.effectiveBlockedReasons
+ final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+ if (hasInternetPermissionUL(uid) && (effectiveBlockedReasons
& BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
- mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i),
- FIREWALL_RULE_ALLOW);
+ mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
}
}
setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY,
@@ -4333,10 +4415,9 @@
return;
}
- final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (mUidState.contains(uid) && uidBlockedState != null
- && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY)
- == 0) {
+ final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+ if (mUidState.contains(uid)
+ && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW);
} else {
@@ -4428,7 +4509,7 @@
}
@GuardedBy("mUidRulesFirstLock")
- void updateRuleForAppIdleUL(int uid) {
+ void updateRuleForAppIdleUL(int uid, int uidProcessState) {
if (!isUidValidForDenylistRulesUL(uid)) return;
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
@@ -4436,7 +4517,7 @@
}
try {
int appId = UserHandle.getAppId(uid);
- if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)
+ if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid, uidProcessState)
&& !isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid);
@@ -4465,9 +4546,8 @@
if (!isUidValidForDenylistRulesUL(uid)) {
continue;
}
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
+ final int blockedReasons = getBlockedReasons(uid);
+ if (!enableChain && (blockedReasons & ~BLOCKED_METERED_REASON_MASK)
== BLOCKED_REASON_NONE) {
// Chain isn't enabled and the uid had no restrictions to begin with.
continue;
@@ -4512,6 +4592,71 @@
}
}
+ @GuardedBy("mUidRulesFirstLock")
+ private void handleDeviceIdleModeChangedUL(boolean enabled) {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
+ try {
+ updateRulesForDeviceIdleUL();
+ if (enabled) {
+ forEachUid("updateRulesForRestrictPower", uid -> {
+ synchronized (mUidRulesFirstLock) {
+ updateRulesForPowerRestrictionsUL(uid);
+ }
+ });
+ } else {
+ // TODO: Note that we could handle the case of enabling-doze state similar
+ // to this but first, we need to update how we listen to uid state changes
+ // so that we always get a callback when a process moves from a NONEXISTENT state
+ // to a "background" state.
+ handleDeviceIdleModeDisabledUL();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
+ @GuardedBy("mUidRulesFirstLock")
+ private void handleDeviceIdleModeDisabledUL() {
+ Trace.traceBegin(TRACE_TAG_NETWORK, "handleDeviceIdleModeDisabledUL");
+ try {
+ final SparseArray<SomeArgs> uidStateUpdates = new SparseArray<>();
+ synchronized (mUidBlockedState) {
+ final int size = mUidBlockedState.size();
+ for (int i = 0; i < size; ++i) {
+ final int uid = mUidBlockedState.keyAt(i);
+ final UidBlockedState uidBlockedState = mUidBlockedState.valueAt(i);
+ if ((uidBlockedState.blockedReasons & BLOCKED_REASON_DOZE) == 0) {
+ continue;
+ }
+ uidBlockedState.blockedReasons &= ~BLOCKED_REASON_DOZE;
+ final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (LOGV) {
+ Log.v(TAG, "handleDeviceIdleModeDisabled(" + uid + "); "
+ + "newUidBlockedState=" + uidBlockedState
+ + ", oldEffectiveBlockedReasons=" + oldEffectiveBlockedReasons);
+ }
+ if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ final SomeArgs someArgs = SomeArgs.obtain();
+ someArgs.argi1 = oldEffectiveBlockedReasons;
+ someArgs.argi2 = uidBlockedState.effectiveBlockedReasons;
+ someArgs.argi3 = uidBlockedState.deriveUidRules();
+ uidStateUpdates.append(uid, someArgs);
+ // TODO: Update the state for all changed uids together.
+ mActivityManagerInternal.onUidBlockedReasonsChanged(uid,
+ uidBlockedState.effectiveBlockedReasons);
+ }
+ }
+ }
+ if (uidStateUpdates.size() != 0) {
+ mHandler.obtainMessage(MSG_UIDS_BLOCKED_REASONS_CHANGED, uidStateUpdates)
+ .sendToTarget();
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
+ }
+
// TODO: rename / document to make it clear these are global (not app-specific) rules
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForRestrictPowerUL() {
@@ -4543,9 +4688,7 @@
}
try {
// update rules for all installed applications
- final PackageManager pm = mContext.getPackageManager();
final List<UserInfo> users;
- final List<ApplicationInfo> apps;
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-users");
try {
@@ -4553,26 +4696,30 @@
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
- Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-uids");
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "iterate-uids");
try {
- apps = pm.getInstalledApplications(
- PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ final int usersSize = users.size();
+ for (int i = 0; i < usersSize; ++i) {
+ final int userId = users.get(i).id;
+ final SparseBooleanArray sharedAppIdsHandled = new SparseBooleanArray();
+ packageManagerInternal.forEachInstalledPackage(androidPackage -> {
+ final int appId = androidPackage.getUid();
+ if (androidPackage.getSharedUserId() != null) {
+ if (sharedAppIdsHandled.indexOfKey(appId) < 0) {
+ sharedAppIdsHandled.put(appId, true);
+ } else {
+ return;
+ }
+ }
+ final int uid = UserHandle.getUid(userId, appId);
+ consumer.accept(uid);
+ }, userId);
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
-
- final int usersSize = users.size();
- final int appsSize = apps.size();
- for (int i = 0; i < usersSize; i++) {
- final UserInfo user = users.get(i);
- for (int j = 0; j < appsSize; j++) {
- final ApplicationInfo app = apps.get(j);
- final int uid = UserHandle.getUid(user.id, app.uid);
- consumer.accept(uid);
- }
- }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -4586,7 +4733,7 @@
final UserInfo user = users.get(i);
int uid = UserHandle.getUid(user.id, appId);
// Update external firewall rules.
- updateRuleForAppIdleUL(uid);
+ updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
updateRuleForDeviceIdleUL(uid);
updateRuleForRestrictPowerUL(uid);
// Update internal rules.
@@ -4634,7 +4781,7 @@
} else {
mAppIdleTempWhitelistAppIds.delete(uid);
}
- updateRuleForAppIdleUL(uid);
+ updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
updateRulesForPowerRestrictionsUL(uid);
} finally {
Binder.restoreCallingIdentity(token);
@@ -4660,7 +4807,15 @@
/** Returns if the UID is currently considered idle. */
@VisibleForTesting
boolean isUidIdle(int uid) {
+ return isUidIdle(uid, PROCESS_STATE_UNKNOWN);
+ }
+
+ private boolean isUidIdle(int uid, int uidProcessState) {
synchronized (mUidRulesFirstLock) {
+ if (uidProcessState != PROCESS_STATE_UNKNOWN && isProcStateConsideredInteraction(
+ uidProcessState)) {
+ return false;
+ }
if (mAppIdleTempWhitelistAppIds.get(uid)) {
// UID is temporarily allowlisted.
return false;
@@ -4709,7 +4864,11 @@
@GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously...
- mUidBlockedState.delete(uid);
+ synchronized (mUidBlockedState) {
+ mUidBlockedState.delete(uid);
+ }
+ mUidState.delete(uid);
+ mActivityManagerInternal.onUidBlockedReasonsChanged(uid, BLOCKED_REASON_NONE);
mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid);
@@ -4745,7 +4904,7 @@
private void updateRestrictionRulesForUidUL(int uid) {
// Methods below only changes the firewall rules for the power-related modes.
updateRuleForDeviceIdleUL(uid);
- updateRuleForAppIdleUL(uid);
+ updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
updateRuleForRestrictPowerUL(uid);
// If the uid has the necessary permissions, then it should be added to the restricted mode
@@ -4821,11 +4980,6 @@
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
- mTmpUidBlockedState, uid);
- previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -4840,18 +4994,47 @@
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
- final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int oldAllowedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
+
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+
+ oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ oldAllowedReasons = previousUidBlockedState.allowedReasons;
+ uidRules = (oldEffectiveBlockedReasons == newEffectiveBlockedReasons)
+ ? RULE_NONE : uidBlockedState.deriveUidRules();
+
+ if (LOGV) {
+ Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ + ": isForeground=" + isForeground
+ + ", isDenied=" + isDenied
+ + ", isAllowed=" + isAllowed
+ + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ + ", oldBlockedState=" + previousUidBlockedState
+ + ", newBlockedState=" + uidBlockedState
+ + ", newBlockedMeteredReasons=" + blockedReasonsToString(newBlockedReasons)
+ + ", newAllowedMeteredReasons=" + allowedReasonsToString(
+ newAllowedReasons));
+ }
+ }
if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
- postBlockedReasonsChangedMsg(uid,
+ handleBlockedReasonsChanged(uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ postUidRulesChangedMsg(uid, uidRules);
}
// Note that the conditionals below are for avoiding unnecessary calls to netd.
@@ -4867,29 +5050,11 @@
}
final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
| ALLOWED_METERED_REASON_USER_EXEMPTED;
- final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
|| (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
setMeteredNetworkAllowlist(uid,
(newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
}
-
- if (LOGV) {
- Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
- + ": isForeground=" +isForeground
- + ", isDenied=" + isDenied
- + ", isAllowed=" + isAllowed
- + ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", oldBlockedState=" + previousUidBlockedState.toString()
- + ", newBlockedState="
- + ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
- + ", oldBlockedMeteredEffectiveReasons="
- + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.effectiveBlockedReasons & BLOCKED_METERED_REASON_MASK)
- + ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
- }
}
/**
@@ -4913,7 +5078,12 @@
*/
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForPowerRestrictionsUL(int uid) {
- updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
+ updateRulesForPowerRestrictionsUL(uid, PROCESS_STATE_UNKNOWN);
+ }
+
+ @GuardedBy("mUidRulesFirstLock")
+ private void updateRulesForPowerRestrictionsUL(int uid, int uidProcState) {
+ updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid, uidProcState));
}
/**
@@ -4949,56 +5119,66 @@
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
- mTmpUidBlockedState, uid);
- previousUidBlockedState.copyFrom(uidBlockedState);
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
- int newBlockedReasons = BLOCKED_REASON_NONE;
- int newAllowedReasons = ALLOWED_REASON_NONE;
- newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
- newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
- newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
- newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
- newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
+ int newBlockedReasons = BLOCKED_REASON_NONE;
+ int newAllowedReasons = ALLOWED_REASON_NONE;
+ newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
+ newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+ newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
+ newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
+ newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
- newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
- newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
- newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
- ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
- ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
- newAllowedReasons |= (uidBlockedState.allowedReasons
- & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
- newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
- ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
+ newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+ newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+ newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+ ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+ ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+ newAllowedReasons |= (uidBlockedState.allowedReasons
+ & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+ newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
+ ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (previousUidBlockedState.effectiveBlockedReasons
- != uidBlockedState.effectiveBlockedReasons) {
- postBlockedReasonsChangedMsg(uid,
- uidBlockedState.effectiveBlockedReasons,
- previousUidBlockedState.effectiveBlockedReasons);
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ if (LOGV) {
+ Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ + ", isIdle: " + isUidIdle
+ + ", mRestrictPower: " + mRestrictPower
+ + ", mDeviceIdleMode: " + mDeviceIdleMode
+ + ", isForeground=" + isForeground
+ + ", isTop=" + isTop
+ + ", isWhitelisted=" + isWhitelisted
+ + ", oldUidBlockedState=" + previousUidBlockedState
+ + ", newUidBlockedState=" + uidBlockedState);
+ }
+
+ oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+ ? RULE_NONE
+ : uidBlockedState.deriveUidRules();
}
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+ handleBlockedReasonsChanged(uid,
+ newEffectiveBlockedReasons,
+ oldEffectiveBlockedReasons);
- if (LOGV) {
- Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
- + ", isIdle: " + isUidIdle
- + ", mRestrictPower: " + mRestrictPower
- + ", mDeviceIdleMode: " + mDeviceIdleMode
- + ", isForeground=" + isForeground
- + ", isTop=" + isTop
- + ", isWhitelisted=" + isWhitelisted
- + ", oldUidBlockedState=" + previousUidBlockedState.toString()
- + ", newUidBlockedState=" + uidBlockedState.toString());
+ postUidRulesChangedMsg(uid, uidRules);
}
}
@@ -5011,7 +5191,7 @@
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
synchronized (mUidRulesFirstLock) {
mLogger.appIdleStateChanged(uid, idle);
- updateRuleForAppIdleUL(uid);
+ updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
updateRulesForPowerRestrictionsUL(uid);
}
} catch (NameNotFoundException nnfe) {
@@ -5027,9 +5207,15 @@
}
}
+ private void handleBlockedReasonsChanged(int uid, int newEffectiveBlockedReasons,
+ int oldEffectiveBlockedReasons) {
+ mActivityManagerInternal.onUidBlockedReasonsChanged(uid, newEffectiveBlockedReasons);
+ postBlockedReasonsChangedMsg(uid, newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
+ }
+
private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons,
int oldEffectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ mHandler.obtainMessage(MSG_UID_BLOCKED_REASON_CHANGED, uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
}
@@ -5276,7 +5462,7 @@
}
return true;
}
- case MSG_BLOCKED_REASON_CHANGED: {
+ case MSG_UID_BLOCKED_REASON_CHANGED: {
final int uid = msg.arg1;
final int newBlockedReasons = msg.arg2;
final int oldBlockedReasons = (int) msg.obj;
@@ -5289,6 +5475,35 @@
mListeners.finishBroadcast();
return true;
}
+ case MSG_UIDS_BLOCKED_REASONS_CHANGED: {
+ final SparseArray<SomeArgs> uidStateUpdates = (SparseArray<SomeArgs>) msg.obj;
+ final int uidsSize = uidStateUpdates.size();
+ final int listenersSize = mListeners.beginBroadcast();
+ for (int i = 0; i < listenersSize; ++i) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) {
+ final int uid = uidStateUpdates.keyAt(uidIndex);
+ final SomeArgs someArgs = uidStateUpdates.valueAt(uidIndex);
+ final int oldBlockedReasons = someArgs.argi1;
+ final int newBlockedReasons = someArgs.argi2;
+ final int uidRules = someArgs.argi3;
+
+ dispatchBlockedReasonChanged(listener, uid,
+ oldBlockedReasons, newBlockedReasons);
+ if (LOGV) {
+ Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ + " for uid=" + uid);
+ }
+ dispatchUidRulesChanged(listener, uid, uidRules);
+ }
+ }
+ mListeners.finishBroadcast();
+
+ for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) {
+ uidStateUpdates.valueAt(uidIndex).recycle();
+ }
+ return true;
+ }
default: {
return false;
}
@@ -5301,21 +5516,7 @@
public boolean handleMessage(Message msg) {
switch (msg.what) {
case UID_MSG_STATE_CHANGED: {
- final UidStateCallbackInfo uidStateCallbackInfo =
- (UidStateCallbackInfo) msg.obj;
- final int uid;
- final int procState;
- final long procStateSeq;
- final int capability;
- synchronized (mUidStateCallbackInfos) {
- uid = uidStateCallbackInfo.uid;
- procState = uidStateCallbackInfo.procState;
- procStateSeq = uidStateCallbackInfo.procStateSeq;
- capability = uidStateCallbackInfo.capability;
- uidStateCallbackInfo.isPending = false;
- }
-
- handleUidChanged(uid, procState, procStateSeq, capability);
+ handleUidChanged((UidStateCallbackInfo) msg.obj);
return true;
}
case UID_MSG_GONE: {
@@ -5330,17 +5531,28 @@
}
};
- void handleUidChanged(int uid, int procState, long procStateSeq,
- @ProcessCapability int capability) {
+ void handleUidChanged(@NonNull UidStateCallbackInfo uidStateCallbackInfo) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
try {
boolean updated;
+ final int uid;
+ final int procState;
+ final long procStateSeq;
+ final int capability;
synchronized (mUidRulesFirstLock) {
+ synchronized (mUidStateCallbackInfos) {
+ uid = uidStateCallbackInfo.uid;
+ procState = uidStateCallbackInfo.procState;
+ procStateSeq = uidStateCallbackInfo.procStateSeq;
+ capability = uidStateCallbackInfo.capability;
+ uidStateCallbackInfo.isPending = false;
+ }
+
// We received a uid state change callback, add it to the history so that it
// will be useful for debugging.
mLogger.uidStateChanged(uid, procState, procStateSeq, capability);
// Now update the network policy rules as per the updated uid state.
- updated = updateUidStateUL(uid, procState, capability);
+ updated = updateUidStateUL(uid, procState, procStateSeq, capability);
// Updating the network rules is done, so notify AMS about this.
mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
}
@@ -5437,6 +5649,12 @@
if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
+ mLogger.meteredDenylistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+ mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5448,6 +5666,12 @@
if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
+ mLogger.meteredAllowlistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+ mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5486,12 +5710,31 @@
}
}
+ private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+ final int size = uidRules.size();
+ final SparseIntArray sdkSandboxUids = new SparseIntArray();
+ for (int index = 0; index < size; index++) {
+ final int uid = uidRules.keyAt(index);
+ final int rule = uidRules.valueAt(index);
+ if (Process.isApplicationUid(uid)) {
+ sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+ }
+ }
+
+ for (int index = 0; index < sdkSandboxUids.size(); index++) {
+ final int uid = sdkSandboxUids.keyAt(index);
+ final int rule = sdkSandboxUids.valueAt(index);
+ uidRules.put(uid, rule);
+ }
+ }
+
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+ addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
int[] uids = new int[size];
@@ -5534,6 +5777,11 @@
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
mLogger.uidFirewallRuleChanged(chain, uid, rule);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+ mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -5570,22 +5818,28 @@
*/
private void resetUidFirewallRules(int uid) {
try {
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
- FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
+ mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
+ mLogger.meteredDenylistChanged(uid, false);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+ if (Process.isApplicationUid(uid)) {
+ resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+ }
}
@Deprecated
@@ -5745,7 +5999,7 @@
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
int blockedReasons;
- synchronized (mUidRulesFirstLock) {
+ synchronized (mUidBlockedState) {
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -5763,7 +6017,7 @@
@Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- synchronized (mUidRulesFirstLock) {
+ synchronized (mUidBlockedState) {
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
int blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -6011,10 +6265,6 @@
return restrictedUids != null && restrictedUids.contains(uid);
}
- private static boolean hasRule(int uidRules, int rule) {
- return (uidRules & rule) != 0;
- }
-
private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle,
String key, boolean defaultValue) {
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
@@ -6030,16 +6280,39 @@
return uidBlockedState;
}
+ private int getEffectiveBlockedReasons(int uid) {
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ return uidBlockedState == null
+ ? BLOCKED_REASON_NONE
+ : uidBlockedState.effectiveBlockedReasons;
+ }
+ }
+
+ private int getBlockedReasons(int uid) {
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ return uidBlockedState == null
+ ? BLOCKED_REASON_NONE
+ : uidBlockedState.blockedReasons;
+ }
+ }
+
@VisibleForTesting
static final class UidBlockedState {
public int blockedReasons;
public int allowedReasons;
public int effectiveBlockedReasons;
+ private UidBlockedState(int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
+ this.blockedReasons = blockedReasons;
+ this.allowedReasons = allowedReasons;
+ this.effectiveBlockedReasons = effectiveBlockedReasons;
+ }
+
UidBlockedState() {
- blockedReasons = BLOCKED_REASON_NONE;
- allowedReasons = ALLOWED_REASON_NONE;
- effectiveBlockedReasons = BLOCKED_REASON_NONE;
+ this(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, BLOCKED_REASON_NONE);
}
void updateEffectiveBlockedReasons() {
@@ -6276,7 +6549,7 @@
}
}
if (LOGV) {
- Slog.v(TAG, "uidBlockedState=" + this.toString()
+ Slog.v(TAG, "uidBlockedState=" + this
+ " -> uidRule=" + uidRulesToString(uidRule));
}
return uidRule;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fad18d2..7d1dbc5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13257,7 +13257,8 @@
// Don't use profiles since that may cause compilation to be skipped.
final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting,
new DexoptOptions(packageName,
- getDefaultCompilerFilter(),
+ REASON_CMDLINE,
+ getDefaultCompilerFilter(), null /* splitName */,
DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 89470ec..5c305c6 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.vcn.VcnManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
@@ -47,6 +48,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import java.util.ArrayList;
import java.util.Collections;
@@ -95,6 +98,10 @@
// TODO (Android T+): Add ability to handle multiple subIds per slot.
@NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
+
+ @NonNull
+ private final Map<Integer, PersistableBundleWrapper> mSubIdToCarrierConfigMap = new HashMap<>();
+
@NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@NonNull
@@ -250,7 +257,10 @@
final TelephonySubscriptionSnapshot newSnapshot =
new TelephonySubscriptionSnapshot(
- mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages);
+ mDeps.getActiveDataSubscriptionId(),
+ newSubIdToInfoMap,
+ mSubIdToCarrierConfigMap,
+ privilegedPackages);
// If snapshot was meaningfully updated, fire the callback
if (!newSnapshot.equals(mCurrentSnapshot)) {
@@ -311,47 +321,77 @@
}
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
- if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) {
+ final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
+ if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
mReadySubIdsBySlotId.put(slotId, subId);
+
+ final PersistableBundle minimized =
+ PersistableBundleUtils.minimizeBundle(
+ carrierConfig, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+ if (minimized != null) {
+ mSubIdToCarrierConfigMap.put(subId, new PersistableBundleWrapper(minimized));
+ }
handleSubscriptionsChanged();
}
} else {
- mReadySubIdsBySlotId.remove(slotId);
+ final Integer oldSubid = mReadySubIdsBySlotId.remove(slotId);
+ if (oldSubid != null) {
+ mSubIdToCarrierConfigMap.remove(oldSubid);
+ }
handleSubscriptionsChanged();
}
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setReadySubIdsBySlotId(Map<Integer, Integer> readySubIdsBySlotId) {
+ mReadySubIdsBySlotId.clear();
mReadySubIdsBySlotId.putAll(readySubIdsBySlotId);
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setSubIdToCarrierConfigMap(
+ Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap) {
+ mSubIdToCarrierConfigMap.clear();
+ mSubIdToCarrierConfigMap.putAll(subIdToCarrierConfigMap);
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
Map<Integer, Integer> getReadySubIdsBySlotId() {
return Collections.unmodifiableMap(mReadySubIdsBySlotId);
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ Map<Integer, PersistableBundleWrapper> getSubIdToCarrierConfigMap() {
+ return Collections.unmodifiableMap(mSubIdToCarrierConfigMap);
+ }
+
/** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
public static class TelephonySubscriptionSnapshot {
private final int mActiveDataSubId;
private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap;
+ private final Map<Integer, PersistableBundleWrapper> mSubIdToCarrierConfigMap;
private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;
public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
new TelephonySubscriptionSnapshot(
- INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap());
+ INVALID_SUBSCRIPTION_ID,
+ Collections.emptyMap(),
+ Collections.emptyMap(),
+ Collections.emptyMap());
@VisibleForTesting(visibility = Visibility.PRIVATE)
TelephonySubscriptionSnapshot(
int activeDataSubId,
@NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap,
+ @NonNull Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap,
@NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
mActiveDataSubId = activeDataSubId;
Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null");
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
+ Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null");
mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap);
+ mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap);
final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>();
for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) {
@@ -423,9 +463,40 @@
: false;
}
+ /**
+ * Retrieves a carrier config for a subscription in the provided group.
+ *
+ * <p>This method will prioritize non-opportunistic subscriptions, but will use the a
+ * carrier config for an opportunistic subscription if no other subscriptions are found.
+ */
+ @Nullable
+ public PersistableBundleWrapper getCarrierConfigForSubGrp(@NonNull ParcelUuid subGrp) {
+ PersistableBundleWrapper result = null;
+
+ for (int subId : getAllSubIdsInGroup(subGrp)) {
+ final PersistableBundleWrapper config = mSubIdToCarrierConfigMap.get(subId);
+ if (config != null) {
+ result = config;
+
+ // Attempt to use (any) non-opportunistic subscription. If this subscription is
+ // opportunistic, continue and try to find a non-opportunistic subscription,
+ // using the opportunistic ones as a last resort.
+ if (!isOpportunistic(subId)) {
+ return config;
+ }
+ }
+ }
+
+ return result;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages);
+ return Objects.hash(
+ mActiveDataSubId,
+ mSubIdToInfoMap,
+ mSubIdToCarrierConfigMap,
+ mPrivilegedPackages);
}
@Override
@@ -438,6 +509,7 @@
return mActiveDataSubId == other.mActiveDataSubId
&& mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
+ && mSubIdToCarrierConfigMap.equals(other.mSubIdToCarrierConfigMap)
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
}
@@ -448,6 +520,7 @@
pw.println("mActiveDataSubId: " + mActiveDataSubId);
pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap);
+ pw.println("mSubIdToCarrierConfigMap: " + mSubIdToCarrierConfigMap);
pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
pw.decreaseIndent();
@@ -458,6 +531,7 @@
return "TelephonySubscriptionSnapshot{ "
+ "mActiveDataSubId=" + mActiveDataSubId
+ ", mSubIdToInfoMap=" + mSubIdToInfoMap
+ + ", mSubIdToCarrierConfigMap=" + mSubIdToCarrierConfigMap
+ ", mPrivilegedPackages=" + mPrivilegedPackages
+ " }";
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index cefd8ef..05df22f 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -61,6 +61,7 @@
import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.ipsec.ike.exceptions.IkeException;
@@ -509,6 +510,42 @@
}
}
+ /**
+ * Sent when an IKE session connection information has changed.
+ *
+ * <p>This signal is always fired before EVENT_SETUP_COMPLETED and EVENT_MIGRATION_COMPLETED.
+ *
+ * <p>Only relevant in the Connecting and Connected state.
+ *
+ * @param arg1 The session token for the IKE Session whose connection information has changed,
+ * used to prevent out-of-date signals from propagating.
+ * @param obj @NonNull An EventIkeConnectionInfoChangedInfo instance with relevant data.
+ */
+ private static final int EVENT_IKE_CONNECTION_INFO_CHANGED = 12;
+
+ private static class EventIkeConnectionInfoChangedInfo implements EventInfo {
+ @NonNull public final IkeSessionConnectionInfo ikeConnectionInfo;
+
+ EventIkeConnectionInfoChangedInfo(@NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
+ this.ikeConnectionInfo = ikeConnectionInfo;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ikeConnectionInfo);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof EventIkeConnectionInfoChangedInfo)) {
+ return false;
+ }
+
+ final EventIkeConnectionInfoChangedInfo rhs = (EventIkeConnectionInfoChangedInfo) other;
+ return Objects.equals(ikeConnectionInfo, rhs.ikeConnectionInfo);
+ }
+ }
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
final DisconnectedState mDisconnectedState = new DisconnectedState();
@@ -624,6 +661,14 @@
private UnderlyingNetworkRecord mUnderlying;
/**
+ * The current IKE Session connection information
+ *
+ * <p>Set in Connected and Migrating states, always @NonNull in Connected, Migrating
+ * states, @Nullable otherwise.
+ */
+ private IkeSessionConnectionInfo mIkeConnectionInfo;
+
+ /**
* The active IKE session.
*
* <p>Set in Connecting or Migrating States, always @NonNull in Connecting, Connected, and
@@ -1197,6 +1242,14 @@
exceptionMessage);
}
+ private void ikeConnectionInfoChanged(
+ int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_IKE_CONNECTION_INFO_CHANGED,
+ token,
+ new EventIkeConnectionInfoChangedInfo(ikeConnectionInfo));
+ }
+
private void sessionClosed(int token, @Nullable Exception exception) {
if (exception != null) {
notifyStatusCallbackForSessionClosed(exception);
@@ -1313,7 +1366,8 @@
case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough
case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough
- case EVENT_MIGRATION_COMPLETED:
+ case EVENT_MIGRATION_COMPLETED: // Fallthrough
+ case EVENT_IKE_CONNECTION_INFO_CHANGED:
logUnexpectedEvent(msg.what);
break;
default:
@@ -1592,6 +1646,7 @@
transitionTo(mDisconnectingState);
break;
case EVENT_SETUP_COMPLETED: // fallthrough
+ case EVENT_IKE_CONNECTION_INFO_CHANGED: // fallthrough
case EVENT_TRANSFORM_CREATED:
// Child setup complete; move to ConnectedState for NetworkAgent registration
deferMessage(msg);
@@ -1614,12 +1669,17 @@
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnNetworkAgent agent,
- @NonNull VcnChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
- mConnectionConfig, tunnelIface, childConfig, mUnderlying);
+ mConnectionConfig,
+ tunnelIface,
+ childConfig,
+ mUnderlying,
+ ikeConnectionInfo);
agent.sendNetworkCapabilities(caps);
agent.sendLinkProperties(lp);
@@ -1630,12 +1690,17 @@
protected VcnNetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
- mConnectionConfig, tunnelIface, childConfig, mUnderlying);
+ mConnectionConfig,
+ tunnelIface,
+ childConfig,
+ mUnderlying,
+ ikeConnectionInfo);
final NetworkAgentConfig nac =
new NetworkAgentConfig.Builder()
.setLegacyType(ConnectivityManager.TYPE_MOBILE)
@@ -1838,7 +1903,11 @@
mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
setupInterfaceAndNetworkAgent(
- mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
+ mCurrentToken,
+ mTunnelIface,
+ mChildConfig,
+ oldChildConfig,
+ mIkeConnectionInfo);
break;
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
@@ -1852,6 +1921,10 @@
handleMigrationCompleted(migrationCompletedInfo);
break;
+ case EVENT_IKE_CONNECTION_INFO_CHANGED:
+ mIkeConnectionInfo =
+ ((EventIkeConnectionInfoChangedInfo) msg.obj).ikeConnectionInfo;
+ break;
default:
logUnhandledMessage(msg);
break;
@@ -1875,7 +1948,7 @@
migrationCompletedInfo.outTransform,
IpSecManager.DIRECTION_OUT);
- updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig);
+ updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo);
// Trigger re-validation after migration events.
mConnectivityManager.reportNetworkConnectivity(
@@ -1906,7 +1979,8 @@
// Network not yet set up, or child not yet connected.
if (mNetworkAgent != null && mChildConfig != null) {
// If only network properties changed and agent is active, update properties
- updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig);
+ updateNetworkAgent(
+ mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo);
}
}
}
@@ -1915,13 +1989,14 @@
int token,
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
- @NonNull VcnChildSessionConfiguration oldChildConfig) {
+ @NonNull VcnChildSessionConfiguration oldChildConfig,
+ @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
setupInterface(token, tunnelIface, childConfig, oldChildConfig);
if (mNetworkAgent == null) {
- mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
+ mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig, ikeConnectionInfo);
} else {
- updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig);
+ updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig, ikeConnectionInfo);
// mNetworkAgent not null, so the VCN Network has already been established. Clear
// the failed attempt counter and safe mode alarm since this transition is complete.
@@ -2098,7 +2173,8 @@
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
- @Nullable UnderlyingNetworkRecord underlying) {
+ @Nullable UnderlyingNetworkRecord underlying,
+ @NonNull IkeSessionConnectionInfo ikeConnectionInfo) {
final IkeTunnelConnectionParams ikeTunnelParams =
gatewayConnectionConfig.getTunnelConnectionParams();
final LinkProperties lp = new LinkProperties();
@@ -2139,7 +2215,8 @@
MtuUtils.getMtu(
ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
gatewayConnectionConfig.getMaxMtu(),
- underlyingMtu));
+ underlyingMtu,
+ ikeConnectionInfo.getLocalAddress() instanceof Inet4Address));
return lp;
}
@@ -2154,7 +2231,7 @@
@Override
public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
logDbg("IkeOpened for token " + mToken);
- // Nothing to do here.
+ ikeConnectionInfoChanged(mToken, ikeSessionConfig.getIkeSessionConnectionInfo());
}
@Override
@@ -2174,6 +2251,13 @@
logInfo("IkeError for token " + mToken, exception);
// Non-fatal, log and continue.
}
+
+ @Override
+ public void onIkeSessionConnectionInfoChanged(
+ @NonNull IkeSessionConnectionInfo connectionInfo) {
+ logDbg("onIkeSessionConnectionInfoChanged for token " + mToken);
+ ikeConnectionInfoChanged(mToken, connectionInfo);
+ }
}
/** Implementation of ChildSessionCallback, exposed for testing. */
@@ -2350,6 +2434,11 @@
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
+ IkeSessionConnectionInfo getIkeConnectionInfo() {
+ return mIkeConnectionInfo;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
boolean isQuitting() {
return mIsQuitting.getValue();
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
index c96c1ee..2f84fdd 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -24,6 +24,7 @@
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static com.android.server.VcnManagementService.LOCAL_LOG;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,7 +35,6 @@
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.net.vcn.VcnWifiUnderlyingNetworkTemplate;
import android.os.ParcelUuid;
-import android.os.PersistableBundle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Slog;
@@ -81,7 +81,7 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
// mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
if (networkRecord.isBlocked) {
@@ -119,7 +119,7 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
final NetworkCapabilities caps = networkRecord.networkCapabilities;
final boolean isSelectedUnderlyingNetwork =
currentlySelected != null
@@ -181,7 +181,7 @@
VcnWifiUnderlyingNetworkTemplate networkPriority,
UnderlyingNetworkRecord networkRecord,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
final NetworkCapabilities caps = networkRecord.networkCapabilities;
if (!caps.hasTransport(TRANSPORT_WIFI)) {
@@ -204,7 +204,7 @@
private static boolean isWifiRssiAcceptable(
UnderlyingNetworkRecord networkRecord,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
final NetworkCapabilities caps = networkRecord.networkCapabilities;
final boolean isSelectedNetwork =
currentlySelected != null
@@ -314,7 +314,7 @@
return false;
}
- static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ static int getWifiEntryRssiThreshold(@Nullable PersistableBundleWrapper carrierConfig) {
if (carrierConfig != null) {
return carrierConfig.getInt(
VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
@@ -323,7 +323,7 @@
return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
}
- static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ static int getWifiExitRssiThreshold(@Nullable PersistableBundleWrapper carrierConfig) {
if (carrierConfig != null) {
return carrierConfig.getInt(
VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index a3babf7..d474c5d 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -21,7 +21,7 @@
import static com.android.server.VcnManagementService.LOCAL_LOG;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold;
-import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.isOpportunistic;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -37,8 +37,6 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -51,7 +49,6 @@
import com.android.server.vcn.util.LogUtils;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -87,7 +84,7 @@
@Nullable private UnderlyingNetworkListener mRouteSelectionCallback;
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
- @Nullable private PersistableBundle mCarrierConfig;
+ @Nullable private PersistableBundleWrapper mCarrierConfig;
private boolean mIsQuitting = false;
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
@@ -124,25 +121,7 @@
.getSystemService(TelephonyManager.class)
.registerTelephonyCallback(new HandlerExecutor(mHandler), mActiveDataSubIdListener);
- // TODO: Listen for changes in carrier config that affect this.
- for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
- PersistableBundle config =
- mVcnContext
- .getContext()
- .getSystemService(CarrierConfigManager.class)
- .getConfigForSubId(subId);
-
- if (config != null) {
- mCarrierConfig = config;
-
- // Attempt to use (any) non-opportunistic subscription. If this subscription is
- // opportunistic, continue and try to find a non-opportunistic subscription, using
- // the opportunistic ones as a last resort.
- if (!isOpportunistic(mLastSnapshot, Collections.singleton(subId))) {
- break;
- }
- }
- }
+ mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup);
registerOrUpdateNetworkRequests();
}
@@ -334,6 +313,9 @@
final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
mLastSnapshot = newSnapshot;
+ // Update carrier config
+ mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup);
+
// Only trigger re-registration if subIds in this group have changed
if (oldSnapshot
.getAllSubIdsInGroup(mSubscriptionGroup)
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
index 06f9280..319680e 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
@@ -16,6 +16,8 @@
package com.android.server.vcn.routeselection;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkProperties;
@@ -23,7 +25,6 @@
import android.net.NetworkCapabilities;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.ParcelUuid;
-import android.os.PersistableBundle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -68,7 +69,7 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
// Never changes after the underlying network record is created.
if (mPriorityClass == PRIORITY_CLASS_INVALID) {
mPriorityClass =
@@ -113,7 +114,7 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
return (left, right) -> {
final int leftIndex =
left.getOrCalculatePriorityClass(
@@ -167,7 +168,7 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
+ PersistableBundleWrapper carrierConfig) {
pw.println("UnderlyingNetworkRecord:");
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java
index 5d40cca..356c71f 100644
--- a/services/core/java/com/android/server/vcn/util/MtuUtils.java
+++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java
@@ -51,9 +51,20 @@
/**
* Max ESP overhead possible
*
- * <p>60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader)
+ * <p>60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next
+ * Header). Note: Payload data, Pad Length and Next Header will need to be padded to be multiple
+ * of the block size of a cipher, and at the same time be aligned on a 4-byte boundary.
*/
- private static final int GENERIC_ESP_OVERHEAD_MAX = 78;
+ private static final int GENERIC_ESP_OVERHEAD_MAX_V4 = 78;
+
+ /**
+ * Max ESP overhead possible
+ *
+ * <p>40 (Outer IPv6) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next Header). Note: Payload data,
+ * Pad Length and Next Header will need to be padded to be multiple of the block size of a
+ * cipher, and at the same time be aligned on a 4-byte boundary.
+ */
+ private static final int GENERIC_ESP_OVERHEAD_MAX_V6 = 50;
/** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */
private static final Map<Integer, Integer> AUTH_ALGORITHM_OVERHEAD;
@@ -108,7 +119,10 @@
* </ul>
*/
public static int getMtu(
- @NonNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu) {
+ @NonNull List<ChildSaProposal> childProposals,
+ int maxMtu,
+ int underlyingMtu,
+ boolean isIpv4) {
if (underlyingMtu <= 0) {
return IPV6_MIN_MTU;
}
@@ -145,10 +159,13 @@
}
}
+ final int genericEspOverheadMax =
+ isIpv4 ? GENERIC_ESP_OVERHEAD_MAX_V4 : GENERIC_ESP_OVERHEAD_MAX_V6;
+
// Return minimum of maxMtu, and the adjusted MTUs based on algorithms.
- final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX;
+ final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - genericEspOverheadMax;
final int normalModeMtu =
- underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX;
+ underlyingMtu - maxCryptOverhead - maxAuthOverhead - genericEspOverheadMax;
return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu);
}
}
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 1c675c2..08e8eebb 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -28,11 +28,13 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.TreeSet;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -354,4 +356,182 @@
}
}
}
+
+ /**
+ * Returns a copy of the persistable bundle with only the specified keys
+ *
+ * <p>This allows for holding minimized copies for memory-saving purposes.
+ */
+ @NonNull
+ public static PersistableBundle minimizeBundle(
+ @NonNull PersistableBundle bundle, String... keys) {
+ final PersistableBundle minimized = new PersistableBundle();
+
+ if (bundle == null) {
+ return minimized;
+ }
+
+ for (String key : keys) {
+ if (bundle.containsKey(key)) {
+ final Object value = bundle.get(key);
+ if (value == null) {
+ continue;
+ }
+
+ if (value instanceof Boolean) {
+ minimized.putBoolean(key, (Boolean) value);
+ } else if (value instanceof boolean[]) {
+ minimized.putBooleanArray(key, (boolean[]) value);
+ } else if (value instanceof Double) {
+ minimized.putDouble(key, (Double) value);
+ } else if (value instanceof double[]) {
+ minimized.putDoubleArray(key, (double[]) value);
+ } else if (value instanceof Integer) {
+ minimized.putInt(key, (Integer) value);
+ } else if (value instanceof int[]) {
+ minimized.putIntArray(key, (int[]) value);
+ } else if (value instanceof Long) {
+ minimized.putLong(key, (Long) value);
+ } else if (value instanceof long[]) {
+ minimized.putLongArray(key, (long[]) value);
+ } else if (value instanceof String) {
+ minimized.putString(key, (String) value);
+ } else if (value instanceof String[]) {
+ minimized.putStringArray(key, (String[]) value);
+ } else if (value instanceof PersistableBundle) {
+ minimized.putPersistableBundle(key, (PersistableBundle) value);
+ } else {
+ continue;
+ }
+ }
+ }
+
+ return minimized;
+ }
+
+ /** Builds a stable hashcode */
+ public static int getHashCode(@Nullable PersistableBundle bundle) {
+ if (bundle == null) {
+ return -1;
+ }
+
+ int iterativeHashcode = 0;
+ TreeSet<String> treeSet = new TreeSet<>(bundle.keySet());
+ for (String key : treeSet) {
+ Object val = bundle.get(key);
+ if (val instanceof PersistableBundle) {
+ iterativeHashcode =
+ Objects.hash(iterativeHashcode, key, getHashCode((PersistableBundle) val));
+ } else {
+ iterativeHashcode = Objects.hash(iterativeHashcode, key, val);
+ }
+ }
+
+ return iterativeHashcode;
+ }
+
+ /** Checks for persistable bundle equality */
+ public static boolean isEqual(
+ @Nullable PersistableBundle left, @Nullable PersistableBundle right) {
+ // Check for pointer equality & null equality
+ if (Objects.equals(left, right)) {
+ return true;
+ }
+
+ // If only one of the two is null, but not the other, not equal by definition.
+ if (Objects.isNull(left) != Objects.isNull(right)) {
+ return false;
+ }
+
+ if (!left.keySet().equals(right.keySet())) {
+ return false;
+ }
+
+ for (String key : left.keySet()) {
+ Object leftVal = left.get(key);
+ Object rightVal = right.get(key);
+
+ // Check for equality
+ if (Objects.equals(leftVal, rightVal)) {
+ continue;
+ } else if (Objects.isNull(leftVal) != Objects.isNull(rightVal)) {
+ // If only one of the two is null, but not the other, not equal by definition.
+ return false;
+ } else if (!Objects.equals(leftVal.getClass(), rightVal.getClass())) {
+ // If classes are different, not equal by definition.
+ return false;
+ }
+ if (leftVal instanceof PersistableBundle) {
+ if (!isEqual((PersistableBundle) leftVal, (PersistableBundle) rightVal)) {
+ return false;
+ }
+ } else if (leftVal.getClass().isArray()) {
+ if (leftVal instanceof boolean[]) {
+ if (!Arrays.equals((boolean[]) leftVal, (boolean[]) rightVal)) {
+ return false;
+ }
+ } else if (leftVal instanceof double[]) {
+ if (!Arrays.equals((double[]) leftVal, (double[]) rightVal)) {
+ return false;
+ }
+ } else if (leftVal instanceof int[]) {
+ if (!Arrays.equals((int[]) leftVal, (int[]) rightVal)) {
+ return false;
+ }
+ } else if (leftVal instanceof long[]) {
+ if (!Arrays.equals((long[]) leftVal, (long[]) rightVal)) {
+ return false;
+ }
+ } else if (!Arrays.equals((Object[]) leftVal, (Object[]) rightVal)) {
+ return false;
+ }
+ } else {
+ if (!Objects.equals(leftVal, rightVal)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Wrapper class around PersistableBundles to allow equality comparisons
+ *
+ * <p>This class exposes the minimal getters to retrieve values.
+ */
+ public static class PersistableBundleWrapper {
+ @NonNull private final PersistableBundle mBundle;
+
+ public PersistableBundleWrapper(@NonNull PersistableBundle bundle) {
+ mBundle = Objects.requireNonNull(bundle, "Bundle was null");
+ }
+
+ /**
+ * Retrieves the integer associated with the provided key.
+ *
+ * @param key the string key to query
+ * @param defaultValue the value to return if key does not exist
+ * @return the int value, or the default
+ */
+ public int getInt(String key, int defaultValue) {
+ return mBundle.getInt(key, defaultValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return getHashCode(mBundle);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PersistableBundleWrapper)) {
+ return false;
+ }
+
+ final PersistableBundleWrapper other = (PersistableBundleWrapper) obj;
+
+ return isEqual(mBundle, other.mBundle);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 3ccb06c..ab8527e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1123,7 +1123,7 @@
/** Makes the process have top state before oom-adj is computed from a posted message. */
void addToPendingTop() {
- mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+ mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread);
}
void updateServiceConnectionActivities() {
@@ -1176,7 +1176,7 @@
}
// update ActivityManagerService.PendingStartActivityUids list.
if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
- mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+ mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread);
}
prepareOomAdjustment();
// Posting the message at the front of queue so WM lock isn't held when we call into AM,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8e4afe6..dc729f2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1382,8 +1382,9 @@
Slog.i(TAG, SECONDARY_ZYGOTE_PRELOAD);
TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
traceLog.traceBegin(SECONDARY_ZYGOTE_PRELOAD);
- if (!Process.ZYGOTE_PROCESS.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) {
- Slog.e(TAG, "Unable to preload default resources");
+ String[] abis32 = Build.SUPPORTED_32_BIT_ABIS;
+ if (abis32.length > 0 && !Process.ZYGOTE_PROCESS.preloadDefault(abis32[0])) {
+ Slog.e(TAG, "Unable to preload default resources for secondary");
}
traceLog.traceEnd();
} catch (Exception ex) {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 8c21a39..16406bc 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -129,7 +129,7 @@
thread2.assertWaiting("Unexpected state for " + record2);
thread2.interrupt();
- mAms.mProcessList.mActiveUids.clear();
+ clearActiveUids();
}
private UidRecord addActiveUidRecord(int uid, long curProcStateSeq,
@@ -137,11 +137,21 @@
final UidRecord record = new UidRecord(uid, mAms);
record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
record.curProcStateSeq = curProcStateSeq;
- record.waitingForNetwork = true;
- mAms.mProcessList.mActiveUids.put(uid, record);
+ record.procStateSeqWaitingForNetwork = 1;
+ addActiveUidRecord(uid, record);
return record;
}
+ @SuppressWarnings("GuardedBy")
+ private void addActiveUidRecord(int uid, UidRecord record) {
+ mAms.mProcessList.mActiveUids.put(uid, record);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void clearActiveUids() {
+ mAms.mProcessList.mActiveUids.clear();
+ }
+
static class CustomThread extends Thread {
private static final long WAIT_TIMEOUT_MS = 1000;
private static final long WAIT_INTERVAL_MS = 100;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 12e0d8b..968a3e2 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -191,8 +191,6 @@
verifySeqCounterAndInteractions(uidRec,
PROCESS_STATE_TOP, // prevState
PROCESS_STATE_TOP, // curState
- 0, // expectedGlobalCounter
- 0, // exptectedCurProcStateSeq
NETWORK_STATE_NO_CHANGE, // expectedBlockState
false); // expectNotify
@@ -200,8 +198,6 @@
verifySeqCounterAndInteractions(uidRec,
PROCESS_STATE_FOREGROUND_SERVICE, // prevState
PROCESS_STATE_SERVICE, // curState
- 1, // expectedGlobalCounter
- 1, // exptectedCurProcStateSeq
NETWORK_STATE_UNBLOCK, // expectedBlockState
true); // expectNotify
@@ -213,8 +209,6 @@
verifySeqCounterAndInteractions(uidRec,
PROCESS_STATE_TRANSIENT_BACKGROUND, // prevState
PROCESS_STATE_IMPORTANT_BACKGROUND, // curState
- 42, // expectedGlobalCounter
- 1, // exptectedCurProcStateSeq
NETWORK_STATE_NO_CHANGE, // expectedBlockState
false); // expectNotify
@@ -222,73 +216,22 @@
verifySeqCounterAndInteractions(uidRec,
PROCESS_STATE_LAST_ACTIVITY, // prevState
PROCESS_STATE_TOP, // curState
- 43, // expectedGlobalCounter
- 43, // exptectedCurProcStateSeq
NETWORK_STATE_BLOCK, // expectedBlockState
false); // expectNotify
// verify waiting threads are not notified.
- uidRec.waitingForNetwork = false;
+ uidRec.procStateSeqWaitingForNetwork = 0;
// Uid state is moving from foreground to background.
verifySeqCounterAndInteractions(uidRec,
PROCESS_STATE_FOREGROUND_SERVICE, // prevState
PROCESS_STATE_SERVICE, // curState
- 44, // expectedGlobalCounter
- 44, // exptectedCurProcStateSeq
NETWORK_STATE_UNBLOCK, // expectedBlockState
false); // expectNotify
-
- // Verify when uid is not restricted, procStateSeq is not incremented.
- uidRec.waitingForNetwork = true;
- mInjector.setNetworkRestrictedForUid(false);
- verifySeqCounterAndInteractions(uidRec,
- PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState
- PROCESS_STATE_TOP, // curState
- 44, // expectedGlobalCounter
- 44, // exptectedCurProcStateSeq
- -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
- false); // expectNotify
-
- // Verify when waitForNetworkTimeout is 0, then procStateSeq is not incremented.
- mAms.mWaitForNetworkTimeoutMs = 0;
- mInjector.setNetworkRestrictedForUid(true);
- verifySeqCounterAndInteractions(uidRec,
- PROCESS_STATE_TOP, // prevState
- PROCESS_STATE_IMPORTANT_BACKGROUND, // curState
- 44, // expectedGlobalCounter
- 44, // exptectedCurProcStateSeq
- -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
- false); // expectNotify
-
- // Verify when the uid doesn't have internet permission, then procStateSeq is not
- // incremented.
- uidRec.hasInternetPermission = false;
- mAms.mWaitForNetworkTimeoutMs = 111;
- mInjector.setNetworkRestrictedForUid(true);
- verifySeqCounterAndInteractions(uidRec,
- PROCESS_STATE_CACHED_ACTIVITY, // prevState
- PROCESS_STATE_FOREGROUND_SERVICE, // curState
- 44, // expectedGlobalCounter
- 44, // exptectedCurProcStateSeq
- -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
- false); // expectNotify
-
- // Verify procStateSeq is not incremented when the uid is not an application, regardless
- // of the process state.
- final int notAppUid = 111;
- final UidRecord uidRec2 = addUidRecord(notAppUid);
- verifySeqCounterAndInteractions(uidRec2,
- PROCESS_STATE_CACHED_EMPTY, // prevState
- PROCESS_STATE_TOP, // curState
- 44, // expectedGlobalCounter
- 0, // exptectedCurProcStateSeq
- -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
- false); // expectNotify
}
private UidRecord addUidRecord(int uid) {
final UidRecord uidRec = new UidRecord(uid, mAms);
- uidRec.waitingForNetwork = true;
+ uidRec.procStateSeqWaitingForNetwork = 1;
uidRec.hasInternetPermission = true;
mAms.mProcessList.mActiveUids.put(uid, uidRec);
@@ -305,18 +248,26 @@
@SuppressWarnings("GuardedBy")
private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState,
- int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState,
- boolean expectNotify) throws Exception {
+ int expectedBlockState, boolean expectNotify) throws Exception {
CustomThread thread = new CustomThread(uidRec.networkStateLock);
thread.startAndWait("Unexpected state for " + uidRec);
uidRec.setSetProcState(prevState);
uidRec.setCurProcState(curState);
+ final long beforeProcStateSeq = mAms.mProcessList.mProcStateSeqCounter;
+
mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(mAms.mProcessList.mActiveUids);
- // @SuppressWarnings("GuardedBy")
- assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter);
- assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq);
+ final long afterProcStateSeq = beforeProcStateSeq
+ + mAms.mProcessList.mActiveUids.size();
+ assertEquals("beforeProcStateSeq=" + beforeProcStateSeq
+ + ",activeUids.size=" + mAms.mProcessList.mActiveUids.size(),
+ afterProcStateSeq, mAms.mProcessList.mProcStateSeqCounter);
+ assertTrue("beforeProcStateSeq=" + beforeProcStateSeq
+ + ",afterProcStateSeq=" + afterProcStateSeq
+ + ",uidCurProcStateSeq=" + uidRec.curProcStateSeq,
+ uidRec.curProcStateSeq > beforeProcStateSeq
+ && uidRec.curProcStateSeq <= afterProcStateSeq);
for (int i = mAms.mProcessList.getLruSizeLOSP() - 1; i >= 0; --i) {
final ProcessRecord app = mAms.mProcessList.getLruProcessesLOSP().get(i);
@@ -815,48 +766,11 @@
}
@Test
- public void testEnqueueUidChangeLocked_procStateSeqUpdated() {
- final UidRecord uidRecord = new UidRecord(TEST_UID, mAms);
- uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
-
- // Verify with no pending changes for TEST_UID.
- verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1);
-
- // Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as
- // expected.
- uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2;
- verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2);
- }
-
- @Test
public void testEnqueueUidChangeLocked_nullUidRecord() {
// Use "null" uidRecord to make sure there is no crash.
mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
}
- private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) {
- // Test enqueueUidChangeLocked with every UidRecord.CHANGE_*
- for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) {
- final int changeToDispatch = UID_RECORD_CHANGES[i];
- // Reset lastProcStateSeqDispatchToObservers after every test.
- uidRecord.lastDispatchedProcStateSeq = 0;
- mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
- // Verify there is no effect on curProcStateSeq.
- assertEquals(curProcstateSeq, uidRecord.curProcStateSeq);
- if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) {
- // Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that
- // lastProcStateSeqDispatchedToObservers is not updated.
- assertNotEquals(uidRecord.curProcStateSeq,
- uidRecord.lastDispatchedProcStateSeq);
- } else {
- // Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that
- // lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq.
- assertEquals(uidRecord.curProcStateSeq,
- uidRecord.lastDispatchedProcStateSeq);
- }
- }
- }
-
@MediumTest
@Test
public void testEnqueueUidChangeLocked_dispatchUidsChanged() {
@@ -893,29 +807,10 @@
// Check there is no crash when there is no UidRecord for myUid
mAms.waitForNetworkStateUpdate(TEST_PROC_STATE_SEQ1);
- // Verify there is no waiting when UidRecord.curProcStateSeq is greater than
- // the procStateSeq in the request to wait.
- verifyWaitingForNetworkStateUpdate(
- TEST_PROC_STATE_SEQ1, // curProcStateSeq
- TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
- TEST_PROC_STATE_SEQ1 - 4, // lastNetworkUpdatedProcStateSeq
- TEST_PROC_STATE_SEQ1 - 2, // procStateSeqToWait
- false); // expectWait
-
- // Verify there is no waiting when the procStateSeq in the request to wait is
- // not dispatched to NPMS.
- verifyWaitingForNetworkStateUpdate(
- TEST_PROC_STATE_SEQ1, // curProcStateSeq
- TEST_PROC_STATE_SEQ1 - 1, // lastDsipatchedProcStateSeq
- TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
- TEST_PROC_STATE_SEQ1, // procStateSeqToWait
- false); // expectWait
-
// Verify there is not waiting when the procStateSeq in the request already has
// an updated network state.
verifyWaitingForNetworkStateUpdate(
TEST_PROC_STATE_SEQ1, // curProcStateSeq
- TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
TEST_PROC_STATE_SEQ1, // lastNetworkUpdatedProcStateSeq
TEST_PROC_STATE_SEQ1, // procStateSeqToWait
false); // expectWait
@@ -923,18 +818,16 @@
// Verify waiting for network works
verifyWaitingForNetworkStateUpdate(
TEST_PROC_STATE_SEQ1, // curProcStateSeq
- TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
TEST_PROC_STATE_SEQ1, // procStateSeqToWait
true); // expectWait
}
private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
- long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq,
+ long lastNetworkUpdatedProcStateSeq,
final long procStateSeqToWait, boolean expectWait) throws Exception {
final UidRecord record = new UidRecord(Process.myUid(), mAms);
record.curProcStateSeq = curProcStateSeq;
- record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq;
record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
mAms.mProcessList.mActiveUids.put(Process.myUid(), record);
@@ -953,7 +846,7 @@
}
thread.assertTerminated(errMsg);
assertTrue(thread.mNotified);
- assertFalse(record.waitingForNetwork);
+ assertEquals(0, record.procStateSeqWaitingForNetwork);
} else {
thread.start();
thread.assertTerminated(errMsg);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index af8ac6f..0f2fe44 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -118,6 +118,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
@@ -166,6 +167,7 @@
import com.android.internal.util.test.FsUtil;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.usage.AppStandbyInternal;
import com.google.common.util.concurrent.AbstractFuture;
@@ -216,6 +218,7 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -274,6 +277,7 @@
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
private ActivityManagerInternal mActivityManagerInternal;
+ private PackageManagerInternal mPackageManagerInternal;
private IUidObserver mUidObserver;
private INetworkManagementEventObserver mNetworkObserver;
@@ -335,6 +339,7 @@
when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{});
mActivityManagerInternal = addLocalServiceMock(ActivityManagerInternal.class);
+ mPackageManagerInternal = addLocalServiceMock(PackageManagerInternal.class);
final PowerSaveState state = new PowerSaveState.Builder()
.setBatterySaverEnabled(false).build();
@@ -436,14 +441,14 @@
setNetpolicyXml(context);
doAnswer(new Answer<Void>() {
-
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
mUidObserver = (IUidObserver) invocation.getArguments()[0];
Log.d(TAG, "set mUidObserver to " + mUidObserver);
return null;
}
- }).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class));
+ }).when(mActivityManagerInternal).registerNetworkPolicyUidObserver(any(),
+ anyInt(), anyInt(), any(String.class));
mFutureIntent = newRestrictBackgroundChangedFuture();
mDeps = new TestDependencies(mServiceContext);
@@ -483,8 +488,15 @@
.thenReturn(buildApplicationInfo(PKG_NAME_B, UID_B));
when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt()))
.thenReturn(buildApplicationInfo(PKG_NAME_C, UID_C));
- when(mPackageManager.getInstalledApplications(anyInt())).thenReturn(
- buildInstalledApplicationInfoList());
+ doAnswer(arg -> {
+ final Consumer<AndroidPackage> consumer =
+ (Consumer<AndroidPackage>) arg.getArguments()[0];
+ for (AndroidPackage androidPackage : buildInstalledPackageList()) {
+ consumer.accept(androidPackage);
+ }
+ return null;
+ }).when(mPackageManagerInternal).forEachInstalledPackage(
+ any(Consumer.class), anyInt());
when(mUserManager.getUsers()).thenReturn(buildUserInfoList());
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
@@ -536,6 +548,7 @@
LocalServices.removeServiceForTest(DeviceIdleInternal.class);
LocalServices.removeServiceForTest(AppStandbyInternal.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
@After
@@ -978,19 +991,20 @@
@Test
public void testUidForeground() throws Exception {
// push all uids into background
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0);
- callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, 0);
+ long procStateSeq = 0;
+ callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
+ callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
assertFalse(mService.isUidForeground(UID_A));
assertFalse(mService.isUidForeground(UID_B));
// push one of the uids into foreground
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0);
+ callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
assertTrue(mService.isUidForeground(UID_A));
assertFalse(mService.isUidForeground(UID_B));
// and swap another uid into foreground
- callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0);
- callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, 0);
+ callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
+ callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
assertFalse(mService.isUidForeground(UID_A));
assertTrue(mService.isUidForeground(UID_B));
}
@@ -2037,14 +2051,20 @@
return ai;
}
- private List<ApplicationInfo> buildInstalledApplicationInfoList() {
- final List<ApplicationInfo> installedApps = new ArrayList<>();
- installedApps.add(buildApplicationInfo(PKG_NAME_A, UID_A));
- installedApps.add(buildApplicationInfo(PKG_NAME_B, UID_B));
- installedApps.add(buildApplicationInfo(PKG_NAME_C, UID_C));
+ private List<AndroidPackage> buildInstalledPackageList() {
+ final List<AndroidPackage> installedApps = new ArrayList<>();
+ installedApps.add(createPackageMock(UID_A));
+ installedApps.add(createPackageMock(UID_B));
+ installedApps.add(createPackageMock(UID_C));
return installedApps;
}
+ private AndroidPackage createPackageMock(int uid) {
+ final AndroidPackage androidPackage = mock(AndroidPackage.class);
+ when(androidPackage.getUid()).thenReturn(uid);
+ return androidPackage;
+ }
+
private List<UserInfo> buildUserInfoList() {
final List<UserInfo> users = new ArrayList<>();
users.add(new UserInfo(USER_ID, "user1", 0));
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 83c78cd..0d0142c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2853,11 +2853,11 @@
* <p>
* 4 threshold integers must be within the boundaries [-140 dB, -44 dB], and the levels are:
* <UL>
- * <LI>"NONE: [-140, threshold1]"</LI>
- * <LI>"POOR: (threshold1, threshold2]"</LI>
- * <LI>"MODERATE: (threshold2, threshold3]"</LI>
- * <LI>"GOOD: (threshold3, threshold4]"</LI>
- * <LI>"EXCELLENT: (threshold4, -44]"</LI>
+ * <LI>"NONE: [-140, threshold1)"</LI>
+ * <LI>"POOR: [threshold1, threshold2)"</LI>
+ * <LI>"MODERATE: [threshold2, threshold3)"</LI>
+ * <LI>"GOOD: [threshold3, threshold4)"</LI>
+ * <LI>"EXCELLENT: [threshold4, -44]"</LI>
* </UL>
* <p>
* This key is considered invalid if the format is violated. If the key is invalid or
@@ -2873,11 +2873,11 @@
* <p>
* 4 threshold integers must be within the boundaries [-43 dB, 20 dB], and the levels are:
* <UL>
- * <LI>"NONE: [-43, threshold1]"</LI>
- * <LI>"POOR: (threshold1, threshold2]"</LI>
- * <LI>"MODERATE: (threshold2, threshold3]"</LI>
- * <LI>"GOOD: (threshold3, threshold4]"</LI>
- * <LI>"EXCELLENT: (threshold4, 20]"</LI>
+ * <LI>"NONE: [-43, threshold1)"</LI>
+ * <LI>"POOR: [threshold1, threshold2)"</LI>
+ * <LI>"MODERATE: [threshold2, threshold3)"</LI>
+ * <LI>"GOOD: [threshold3, threshold4)"</LI>
+ * <LI>"EXCELLENT: [threshold4, 20]"</LI>
* </UL>
* <p>
* This key is considered invalid if the format is violated. If the key is invalid or
@@ -2894,11 +2894,11 @@
* <p>
* 4 threshold integers must be within the boundaries [-23 dB, 40 dB], and the levels are:
* <UL>
- * <LI>"NONE: [-23, threshold1]"</LI>
- * <LI>"POOR: (threshold1, threshold2]"</LI>
- * <LI>"MODERATE: (threshold2, threshold3]"</LI>
- * <LI>"GOOD: (threshold3, threshold4]"</LI>
- * <LI>"EXCELLENT: (threshold4, 40]"</LI>
+ * <LI>"NONE: [-23, threshold1)"</LI>
+ * <LI>"POOR: [threshold1, threshold2)"</LI>
+ * <LI>"MODERATE: [threshold2, threshold3)"</LI>
+ * <LI>"GOOD: [threshold3, threshold4)"</LI>
+ * <LI>"EXCELLENT: [threshold4, 40]"</LI>
* </UL>
* <p>
* This key is considered invalid if the format is violated. If the key is invalid or
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index cd22abd..417fd49 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -438,13 +438,13 @@
int level;
if (measure == CellInfo.UNAVAILABLE) {
level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- } else if (measure > thresholds[3]) {
+ } else if (measure >= thresholds[3]) {
level = SIGNAL_STRENGTH_GREAT;
- } else if (measure > thresholds[2]) {
+ } else if (measure >= thresholds[2]) {
level = SIGNAL_STRENGTH_GOOD;
- } else if (measure > thresholds[1]) {
+ } else if (measure >= thresholds[1]) {
level = SIGNAL_STRENGTH_MODERATE;
- } else if (measure > thresholds[0]) {
+ } else if (measure >= thresholds[0]) {
level = SIGNAL_STRENGTH_POOR;
} else {
level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 5f606e1..09080be 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -26,6 +26,7 @@
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -50,9 +51,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.vcn.VcnManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
+import android.os.PersistableBundle;
import android.os.test.TestLooper;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
@@ -104,6 +107,26 @@
TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap);
}
+ private static final String TEST_CARRIER_CONFIG_KEY_1 = "TEST_CARRIER_CONFIG_KEY_1";
+ private static final String TEST_CARRIER_CONFIG_KEY_2 = "TEST_CARRIER_CONFIG_KEY_2";
+ private static final PersistableBundle TEST_CARRIER_CONFIG = new PersistableBundle();
+ private static final PersistableBundleWrapper TEST_CARRIER_CONFIG_WRAPPER;
+ private static final Map<Integer, PersistableBundleWrapper> TEST_SUBID_TO_CARRIER_CONFIG_MAP;
+
+ static {
+ TEST_CARRIER_CONFIG.putString(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY);
+ TEST_CARRIER_CONFIG.putString(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY);
+ TEST_CARRIER_CONFIG_WRAPPER = new PersistableBundleWrapper(TEST_CARRIER_CONFIG);
+
+ final Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap = new HashMap<>();
+ subIdToCarrierConfigMap.put(TEST_SUBSCRIPTION_ID_1, TEST_CARRIER_CONFIG_WRAPPER);
+ TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap);
+ }
+
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
@NonNull private final Handler mHandler;
@@ -144,6 +167,9 @@
doReturn(mCarrierConfigManager)
.when(mContext)
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ doReturn(TEST_CARRIER_CONFIG)
+ .when(mCarrierConfigManager)
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
// subId 1, 2 are in same subGrp, only subId 1 is active
doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
@@ -227,14 +253,24 @@
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
Map<Integer, SubscriptionInfo> subIdToInfoMap,
Map<ParcelUuid, Set<String>> privilegedPackages) {
- return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
+ return buildExpectedSnapshot(0, subIdToInfoMap, privilegedPackages);
}
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
int activeSubId,
Map<Integer, SubscriptionInfo> subIdToInfoMap,
Map<ParcelUuid, Set<String>> privilegedPackages) {
- return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
+ return buildExpectedSnapshot(
+ activeSubId, subIdToInfoMap, TEST_SUBID_TO_CARRIER_CONFIG_MAP, privilegedPackages);
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ int activeSubId,
+ Map<Integer, SubscriptionInfo> subIdToInfoMap,
+ Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap,
+ Map<ParcelUuid, Set<String>> privilegedPackages) {
+ return new TelephonySubscriptionSnapshot(
+ activeSubId, subIdToInfoMap, subIdToCarrierConfigMap, privilegedPackages);
}
private void verifyNoActiveSubscriptions() {
@@ -245,6 +281,8 @@
private void setupReadySubIds() {
mTelephonySubscriptionTracker.setReadySubIdsBySlotId(
Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1));
+ mTelephonySubscriptionTracker.setSubIdToCarrierConfigMap(
+ Collections.singletonMap(TEST_SUBSCRIPTION_ID_1, TEST_CARRIER_CONFIG_WRAPPER));
}
private void setPrivilegedPackagesForMock(@NonNull List<String> privilegedPackages) {
@@ -300,6 +338,7 @@
readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX + 1, TEST_SUBSCRIPTION_ID_1);
mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId);
+ mTelephonySubscriptionTracker.setSubIdToCarrierConfigMap(TEST_SUBID_TO_CARRIER_CONFIG_MAP);
doReturn(1).when(mTelephonyManager).getActiveModemCount();
List<CarrierPrivilegesCallback> carrierPrivilegesCallbacks =
@@ -464,8 +503,16 @@
mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
mTestLooper.dispatchAll();
- verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap())));
+ verify(mCallback)
+ .onNewSnapshot(
+ eq(
+ buildExpectedSnapshot(
+ 0, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap())));
assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+ assertNull(
+ mTelephonySubscriptionTracker
+ .getSubIdToCarrierConfigMap()
+ .get(TEST_SUBSCRIPTION_ID_1));
}
@Test
@@ -493,7 +540,7 @@
public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
final TelephonySubscriptionSnapshot snapshot =
new TelephonySubscriptionSnapshot(
- TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap());
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
@@ -503,7 +550,7 @@
public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
final TelephonySubscriptionSnapshot snapshot =
new TelephonySubscriptionSnapshot(
- TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap(), emptyMap());
assertEquals(
new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 841b81c..15d4f10 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -56,6 +56,7 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -216,14 +217,23 @@
@Test
public void testMigration() throws Exception {
triggerChildOpened();
+ mTestLooper.dispatchAll();
+ assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo());
mGatewayConnection
.getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+
+ final IkeSessionConnectionInfo newIkeConnectionInfo =
+ new IkeSessionConnectionInfo(
+ TEST_ADDR_V4, TEST_ADDR_V4_2, TEST_UNDERLYING_NETWORK_RECORD_2.network);
+ getIkeSessionCallback().onIkeSessionConnectionInfoChanged(newIkeConnectionInfo);
getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll();
+ assertEquals(newIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo());
+
verify(mIpSecSvc, times(2))
.setNetworkForTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
@@ -246,7 +256,8 @@
MtuUtils.getMtu(
saProposals,
mConfig.getMaxMtu(),
- TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu(),
+ true /* isIpv4 */);
verify(mNetworkAgent).sendLinkProperties(
argThat(lp -> expectedMtu == lp.getMtu()
&& TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
@@ -269,6 +280,7 @@
.when(mMockChildSessionConfig)
.getInternalDnsServers();
+ getIkeSessionCallback().onOpened(mIkeSessionConfiguration);
getChildSessionCallback().onOpened(mMockChildSessionConfig);
}
@@ -298,6 +310,7 @@
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo());
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index b9dfda3..6a9a1e2 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -213,7 +213,8 @@
VcnGatewayConnectionConfigTest.buildTestConfig(),
tunnelIface,
childSessionConfig,
- record);
+ record,
+ mIkeConnectionInfo);
verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
@@ -226,7 +227,8 @@
VcnGatewayConnectionConfigTest.buildTestConfig(),
tunnelIface,
childSessionConfig,
- record);
+ record,
+ mIkeConnectionInfo);
verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 5628321..785bff1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -47,6 +47,8 @@
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
@@ -80,6 +82,13 @@
doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid();
}
+ protected static final InetAddress TEST_ADDR = InetAddresses.parseNumericAddress("2001:db8::1");
+ protected static final InetAddress TEST_ADDR_2 =
+ InetAddresses.parseNumericAddress("2001:db8::2");
+ protected static final InetAddress TEST_ADDR_V4 =
+ InetAddresses.parseNumericAddress("192.0.2.1");
+ protected static final InetAddress TEST_ADDR_V4_2 =
+ InetAddresses.parseNumericAddress("192.0.2.2");
protected static final InetAddress TEST_DNS_ADDR =
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
protected static final InetAddress TEST_DNS_ADDR_2 =
@@ -129,6 +138,7 @@
new TelephonySubscriptionSnapshot(
TEST_SUB_ID,
Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO),
+ Collections.EMPTY_MAP,
Collections.EMPTY_MAP);
@NonNull protected final Context mContext;
@@ -148,6 +158,9 @@
@NonNull protected final IpSecService mIpSecSvc;
@NonNull protected final ConnectivityManager mConnMgr;
+ @NonNull protected final IkeSessionConnectionInfo mIkeConnectionInfo;
+ @NonNull protected final IkeSessionConfiguration mIkeSessionConfiguration;
+
protected VcnIkeSession mMockIkeSession;
protected VcnGatewayConnection mGatewayConnection;
@@ -173,6 +186,10 @@
VcnTestUtils.setupSystemService(
mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ mIkeConnectionInfo =
+ new IkeSessionConnectionInfo(TEST_ADDR, TEST_ADDR_2, mock(Network.class));
+ mIkeSessionConfiguration = new IkeSessionConfiguration.Builder(mIkeConnectionInfo).build();
+
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index 6c849b5..b0d6895 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -30,6 +30,7 @@
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -309,7 +310,9 @@
wifiNetworkPriority,
mWifiNetworkRecord,
selectedNetworkRecord,
- carrierConfig));
+ carrierConfig == null
+ ? null
+ : new PersistableBundleWrapper(carrierConfig)));
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
index 29511f7..e9e7078 100644
--- a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
+++ b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
@@ -46,34 +46,85 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MtuUtilsTest {
- @Test
- public void testUnderlyingMtuZero() {
+ private void verifyUnderlyingMtuZero(boolean isIpv4) {
assertEquals(
- IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */));
+ IPV6_MIN_MTU,
+ getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */, isIpv4));
}
@Test
- public void testClampsToMaxMtu() {
- assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */));
+ public void testUnderlyingMtuZeroV4() {
+ verifyUnderlyingMtuZero(true /* isIpv4 */);
}
@Test
- public void testNormalModeAlgorithmLessThanUnderlyingMtu() {
- final List<ChildSaProposal> saProposals =
- Arrays.asList(
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)
- .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
- .build());
+ public void testUnderlyingMtuZeroV6() {
+ verifyUnderlyingMtuZero(false /* isIpv4 */);
+ }
+ private void verifyClampsToMaxMtu(boolean isIpv4) {
+ assertEquals(
+ 0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */, isIpv4));
+ }
+
+ @Test
+ public void testClampsToMaxMtuV4() {
+ verifyClampsToMaxMtu(true /* isIpv4 */);
+ }
+
+ @Test
+ public void testClampsToMaxMtuV6() {
+ verifyClampsToMaxMtu(false /* isIpv4 */);
+ }
+
+ private List<ChildSaProposal> buildChildSaProposalsWithNormalModeAlgo() {
+ return Arrays.asList(
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)
+ .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+ .build());
+ }
+
+ private void verifyNormalModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) {
final int actualMtu =
- getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ getMtu(
+ buildChildSaProposalsWithNormalModeAlgo(),
+ ETHER_MTU /* maxMtu */,
+ ETHER_MTU /* underlyingMtu */,
+ isIpv4);
assertTrue(ETHER_MTU > actualMtu);
}
@Test
- public void testCombinedModeAlgorithmLessThanUnderlyingMtu() {
+ public void testNormalModeAlgorithmLessThanUnderlyingMtuV4() {
+ verifyNormalModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */);
+ }
+
+ @Test
+ public void testNormalModeAlgorithmLessThanUnderlyingMtuV6() {
+ verifyNormalModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */);
+ }
+
+ @Test
+ public void testMtuIpv4LessThanMtuIpv6() {
+ final int actualMtuV4 =
+ getMtu(
+ buildChildSaProposalsWithNormalModeAlgo(),
+ ETHER_MTU /* maxMtu */,
+ ETHER_MTU /* underlyingMtu */,
+ true /* isIpv4 */);
+
+ final int actualMtuV6 =
+ getMtu(
+ buildChildSaProposalsWithNormalModeAlgo(),
+ ETHER_MTU /* maxMtu */,
+ ETHER_MTU /* underlyingMtu */,
+ false /* isIpv4 */);
+
+ assertTrue(actualMtuV4 < actualMtuV6);
+ }
+
+ private void verifyCombinedModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) {
final List<ChildSaProposal> saProposals =
Arrays.asList(
new ChildSaProposal.Builder()
@@ -86,7 +137,17 @@
.build());
final int actualMtu =
- getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */, isIpv4);
assertTrue(ETHER_MTU > actualMtu);
}
+
+ @Test
+ public void testCombinedModeAlgorithmLessThanUnderlyingMtuV4() {
+ verifyCombinedModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */);
+ }
+
+ @Test
+ public void testCombinedModeAlgorithmLessThanUnderlyingMtuV6() {
+ verifyCombinedModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
index a44a734..294f5c1 100644
--- a/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
+++ b/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.os.PersistableBundle;
@@ -211,4 +213,84 @@
assertEquals(testInt, result);
}
+
+ private PersistableBundle getTestBundle() {
+ final PersistableBundle bundle = new PersistableBundle();
+
+ bundle.putBoolean(TEST_KEY + "Boolean", true);
+ bundle.putBooleanArray(TEST_KEY + "BooleanArray", new boolean[] {true, false});
+ bundle.putDouble(TEST_KEY + "Double", 0.1);
+ bundle.putDoubleArray(TEST_KEY + "DoubleArray", new double[] {0.1, 0.2, 0.3});
+ bundle.putInt(TEST_KEY + "Int", 1);
+ bundle.putIntArray(TEST_KEY + "IntArray", new int[] {1, 2});
+ bundle.putLong(TEST_KEY + "Long", 5L);
+ bundle.putLongArray(TEST_KEY + "LongArray", new long[] {0L, -1L, -2L});
+ bundle.putString(TEST_KEY + "String", "TEST");
+ bundle.putStringArray(TEST_KEY + "StringArray", new String[] {"foo", "bar", "bas"});
+ bundle.putPersistableBundle(
+ TEST_KEY + "PersistableBundle",
+ new TestClass(1, TEST_INT_ARRAY, TEST_STRING_PREFIX, new PersistableBundle())
+ .toPersistableBundle());
+
+ return bundle;
+ }
+
+ @Test
+ public void testMinimizeBundle() throws Exception {
+ final String[] minimizedKeys =
+ new String[] {
+ TEST_KEY + "Boolean",
+ TEST_KEY + "BooleanArray",
+ TEST_KEY + "Double",
+ TEST_KEY + "DoubleArray",
+ TEST_KEY + "Int",
+ TEST_KEY + "IntArray",
+ TEST_KEY + "Long",
+ TEST_KEY + "LongArray",
+ TEST_KEY + "String",
+ TEST_KEY + "StringArray",
+ TEST_KEY + "PersistableBundle"
+ };
+
+ final PersistableBundle testBundle = getTestBundle();
+ testBundle.putBoolean(TEST_KEY + "Boolean2", true);
+
+ final PersistableBundle minimized =
+ PersistableBundleUtils.minimizeBundle(testBundle, minimizedKeys);
+
+ // Verify that the minimized bundle is NOT the same in size OR values due to the extra
+ // Boolean2 key
+ assertFalse(PersistableBundleUtils.isEqual(testBundle, minimized));
+
+ // Verify that removing the extra key from the source bundle results in equality.
+ testBundle.remove(TEST_KEY + "Boolean2");
+ assertTrue(PersistableBundleUtils.isEqual(testBundle, minimized));
+ }
+
+ @Test
+ public void testEquality_identical() throws Exception {
+ final PersistableBundle left = getTestBundle();
+ final PersistableBundle right = getTestBundle();
+
+ assertTrue(PersistableBundleUtils.isEqual(left, right));
+ }
+
+ @Test
+ public void testEquality_different() throws Exception {
+ final PersistableBundle left = getTestBundle();
+ final PersistableBundle right = getTestBundle();
+
+ left.putBoolean(TEST_KEY + "Boolean2", true);
+ assertFalse(PersistableBundleUtils.isEqual(left, right));
+
+ left.remove(TEST_KEY + "Boolean2");
+ assertTrue(PersistableBundleUtils.isEqual(left, right));
+ }
+
+ @Test
+ public void testEquality_null() throws Exception {
+ assertFalse(PersistableBundleUtils.isEqual(getTestBundle(), null));
+ assertFalse(PersistableBundleUtils.isEqual(null, getTestBundle()));
+ assertTrue(PersistableBundleUtils.isEqual(null, null));
+ }
}