Test for: digester detection.
Bug: 168504184
Test: atest PackageManagerShellCommandIncrementalTest
Change-Id: I4d17e079ee9f1b300820c24b5880ed50dd953a7f
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
index 65a71b5..858d87c 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -29,13 +29,16 @@
import android.net.Uri;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
import android.provider.DeviceConfig;
import android.service.dataloader.DataLoaderService;
import android.text.TextUtils;
+import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -58,11 +61,13 @@
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Optional;
+import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -242,6 +247,204 @@
(stdout) -> stdout.contains(unexpected)));
}
+
+ static class ReadLogEntry {
+ public final String line;
+ public final int blockIdx;
+ public final int count;
+ public final int fileIdx;
+ public final int appId;
+ public final int userId;
+
+ private ReadLogEntry(String line, int blockIdx, int count, int fileIdx, int appId,
+ int userId) {
+ this.line = line;
+ this.blockIdx = blockIdx;
+ this.count = count;
+ this.fileIdx = fileIdx;
+ this.appId = appId;
+ this.userId = userId;
+ }
+
+ public String toString() {
+ return blockIdx + "/" + count + "/" + fileIdx + "/" + appId + "/" + userId;
+ }
+
+ static final String BLOCK_PREFIX = "|page_read: index=";
+ static final String COUNT_PREFIX = " count=";
+ static final String FILE_PREFIX = " file=";
+ static final String APP_ID_PREFIX = " appid=";
+ static final String USER_ID_PREFIX = " userid=";
+
+ private static int parseInt(String line, int prefixIdx, int prefixLen, int endIdx) {
+ if (prefixIdx == -1) {
+ return -1;
+ }
+ final String intStr;
+ if (endIdx != -1) {
+ intStr = line.substring(prefixIdx + prefixLen, endIdx);
+ } else {
+ intStr = line.substring(prefixIdx + prefixLen);
+ }
+
+ return Integer.parseInt(intStr);
+ }
+
+ static ReadLogEntry parse(String line) {
+ int blockIdx = line.indexOf(BLOCK_PREFIX);
+ if (blockIdx == -1) {
+ return null;
+ }
+ int countIdx = line.indexOf(COUNT_PREFIX, blockIdx + BLOCK_PREFIX.length());
+ if (countIdx == -1) {
+ return null;
+ }
+ int fileIdx = line.indexOf(FILE_PREFIX, countIdx + COUNT_PREFIX.length());
+ if (fileIdx == -1) {
+ return null;
+ }
+ int appIdIdx = line.indexOf(APP_ID_PREFIX, fileIdx + FILE_PREFIX.length());
+ final int userIdIdx;
+ if (appIdIdx != -1) {
+ userIdIdx = line.indexOf(USER_ID_PREFIX, appIdIdx + APP_ID_PREFIX.length());
+ } else {
+ userIdIdx = -1;
+ }
+
+ return new ReadLogEntry(
+ line,
+ parseInt(line, blockIdx, BLOCK_PREFIX.length(), countIdx),
+ parseInt(line, countIdx, COUNT_PREFIX.length(), fileIdx),
+ parseInt(line, fileIdx, FILE_PREFIX.length(), appIdIdx),
+ parseInt(line, appIdIdx, APP_ID_PREFIX.length(), userIdIdx),
+ parseInt(line, userIdIdx, USER_ID_PREFIX.length(), -1));
+ }
+ }
+ ;
+
+ @Test
+ public void testReadLogParser() throws Exception {
+ assertEquals(null, ReadLogEntry.parse("# tracer: nop\n"));
+ assertEquals(
+ "178/290/0/10184/0",
+ ReadLogEntry.parse(
+ "<...>-2777 ( 1639) [006] .... 2764.227110: tracing_mark_write: "
+ + "B|1639|page_read: index=178 count=290 file=0 appid=10184 "
+ + "userid=0")
+ .toString());
+ assertEquals(
+ null,
+ ReadLogEntry.parse(
+ "<...>-2777 ( 1639) [006] .... 2764.227111: tracing_mark_write: E|1639"));
+ assertEquals(
+ "468/337/0/10184/2",
+ ReadLogEntry.parse(
+ "<...>-2777 ( 1639) [006] .... 2764.243227: tracing_mark_write: "
+ + "B|1639|page_read: index=468 count=337 file=0 appid=10184 "
+ + "userid=2")
+ .toString());
+ assertEquals(
+ null,
+ ReadLogEntry.parse(
+ "<...>-2777 ( 1639) [006] .... 2764.243229: tracing_mark_write: E|1639"));
+ assertEquals(
+ "18/9/3/-1/-1",
+ ReadLogEntry.parse(
+ " <...>-2777 ( 1639) [006] .... 2764.227095: "
+ + "tracing_mark_write: B|1639|page_read: index=18 count=9 file=3")
+ .toString());
+ }
+
+ static class AppReads {
+ public final String packageName;
+ public final int reads;
+
+ AppReads(String packageName, int reads) {
+ this.packageName = packageName;
+ this.reads = reads;
+ }
+ }
+
+ @LargeTest
+ @Test
+ @Ignore("Pending fix in GMSCore")
+ public void testInstallWithIdSigNoDigesting() throws Exception {
+ // Overall timeout of 3secs in 100ms intervals.
+ final int atraceDumpIterations = 30;
+ final int atraceDumpDelayMs = 100;
+ final int blockSize = 4096;
+
+ File apkfile = new File(createApkPath(TEST_APK));
+ int blocks = (int) ((apkfile.length() + blockSize - 1) / blockSize);
+ boolean[] touched = new boolean[blocks];
+
+ final ArrayMap<Integer, Integer> uids = new ArrayMap<>();
+
+ final AtomicInteger totalTouchedBlocks = new AtomicInteger(0);
+ checkSysTrace(atraceDumpIterations, atraceDumpDelayMs, () -> installPackage(TEST_APK),
+ (stdout) -> {
+ try (Scanner scanner = new Scanner(stdout)) {
+ while (scanner.hasNextLine()) {
+ final ReadLogEntry readLogEntry = ReadLogEntry.parse(
+ scanner.nextLine());
+ if (readLogEntry == null) {
+ continue;
+ }
+ for (int i = 0, count = readLogEntry.count; i < count; ++i) {
+ int blockIdx = readLogEntry.blockIdx + i;
+ if (touched[blockIdx]) {
+ continue;
+ }
+
+ touched[blockIdx] = true;
+
+ int uid = UserHandle.getUid(readLogEntry.userId,
+ readLogEntry.appId);
+ Integer touchedByUid = uids.get(uid);
+ uids.put(uid, touchedByUid == null ? 1 : touchedByUid + 1);
+
+ if (totalTouchedBlocks.incrementAndGet() >= blocks) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ });
+
+ if (totalTouchedBlocks.get() < blocks) {
+ return;
+ }
+
+ PackageManager pm = getPackageManager();
+
+ AppReads[] appIdReads = new AppReads[uids.size()];
+ for (int i = 0, size = uids.size(); i < size; ++i) {
+ final int uid = uids.keyAt(i);
+ final int appId = UserHandle.getAppId(uid);
+ final int userId = UserHandle.getUserId(uid);
+
+ final String packageName;
+ if (appId < Process.FIRST_APPLICATION_UID) {
+ packageName = "<system>";
+ } else {
+ String[] packages = pm.getPackagesForUid(uid);
+ if (packages == null || packages.length == 0) {
+ packageName = "<unknown package, appId=" + appId + ", userId=" + userId + ">";
+ } else {
+ packageName = "[" + String.join(",", packages) + "]";
+ }
+ }
+ appIdReads[i] = new AppReads(packageName, uids.valueAt(i));
+ }
+ Arrays.sort(appIdReads, (lhs, rhs) -> Integer.compare(rhs.reads, lhs.reads));
+
+ final String packages = String.join("\n", Arrays.stream(appIdReads).map(
+ item -> item.packageName + " : " + item.reads + " blocks").toArray(String[]::new));
+ assertTrue("Digesting detected, list of packages: " + packages,
+ totalTouchedBlocks.get() < blocks);
+ }
+
@LargeTest
@Test
public void testInstallWithIdSigPerUidTimeouts() throws Exception {