[cts] test for InstalledIncrementalPackage metrics

BUG: 187872906
Test: atest CtsPackageManagerStatsHostTestCases
Change-Id: Ic23b39277e8c33f17b818f319688685a262884d6
diff --git a/hostsidetests/packagemanager/stats/Android.bp b/hostsidetests/packagemanager/stats/Android.bp
index e2df9de..d05ed3b 100644
--- a/hostsidetests/packagemanager/stats/Android.bp
+++ b/hostsidetests/packagemanager/stats/Android.bp
@@ -36,6 +36,7 @@
     ],
     data: [
         ":CtsStatsdAtomEmptyApp",
+        ":CtsStatsdAtomEmptyApp2",
         ":CtsStatsdAtomEmptySplitApp",
     ],
     java_resource_dirs: ["res"],
diff --git a/hostsidetests/packagemanager/stats/apps/emptyapp2/Android.bp b/hostsidetests/packagemanager/stats/apps/emptyapp2/Android.bp
new file mode 100644
index 0000000..f4aea5c
--- /dev/null
+++ b/hostsidetests/packagemanager/stats/apps/emptyapp2/Android.bp
@@ -0,0 +1,24 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsStatsdAtomEmptyApp2",
+    defaults: ["cts_defaults"],
+    sdk_version: "current",
+    v4_signature: true,
+}
diff --git a/hostsidetests/packagemanager/stats/apps/emptyapp2/AndroidManifest.xml b/hostsidetests/packagemanager/stats/apps/emptyapp2/AndroidManifest.xml
new file mode 100644
index 0000000..f7b4a1d
--- /dev/null
+++ b/hostsidetests/packagemanager/stats/apps/emptyapp2/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.cts.packagemanager.stats.emptyapp2">
+    <application android:hasCode="false" android:label="Empty Test App2" />
+</manifest>
+
diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java
new file mode 100644
index 0000000..aec859d
--- /dev/null
+++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packagemanager.stats.host;
+
+import android.cts.statsdatom.lib.AtomTestUtils;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
+import com.android.os.AtomsProto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InstalledIncrementalPackageStatsTests extends PackageManagerStatsTestsBase {
+    private static final String TEST_INSTALL_APK = "CtsStatsdAtomEmptyApp.apk";
+    private static final String TEST_INSTALL_PACKAGE =
+            "com.android.cts.packagemanager.stats.emptyapp";
+    private static final String TEST_INSTALL_APK2 = "CtsStatsdAtomEmptyApp2.apk";
+    private static final String TEST_INSTALL_PACKAGE2 =
+            "com.android.cts.packagemanager.stats.emptyapp2";
+
+    @Override
+    protected void tearDown() throws Exception {
+        getDevice().uninstallPackage(TEST_INSTALL_PACKAGE);
+        getDevice().uninstallPackage(TEST_INSTALL_PACKAGE2);
+        super.tearDown();
+    }
+
+    // Install 2 incremental packages and check if their UIDs are included in the pulled metrics
+    public void testInstalledIncrementalMetricsReported() throws Throwable {
+        if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) {
+            return;
+        }
+        ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
+                AtomsProto.Atom.INSTALLED_INCREMENTAL_PACKAGE_FIELD_NUMBER);
+        installPackageUsingIncremental(new String[]{TEST_INSTALL_APK});
+        assertTrue(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE,
+                String.valueOf(getDevice().getCurrentUser())));
+        installPackageUsingIncremental(new String[]{TEST_INSTALL_APK2});
+        assertTrue(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE2,
+                String.valueOf(getDevice().getCurrentUser())));
+        AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice());
+        Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
+
+        List<AtomsProto.Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice());
+        assertEquals(2, data.size());
+        // The order of the UIDs in the metrics can be different from the order of the installations
+        List<Integer> uidsReported = new ArrayList<>();
+        for (AtomsProto.Atom atom : data) {
+            uidsReported.add(atom.getInstalledIncrementalPackage().getUid());
+        }
+        assertTrue(uidsReported.contains(getAppUid(TEST_INSTALL_PACKAGE)));
+        assertTrue(uidsReported.contains(getAppUid(TEST_INSTALL_PACKAGE2)));
+    }
+}
diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallerV2StatsTests.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallerV2StatsTests.java
index 3f604fb..ec177f6 100644
--- a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallerV2StatsTests.java
+++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageInstallerV2StatsTests.java
@@ -15,65 +15,41 @@
  */
 
 package com.android.cts.packagemanager.stats.host;
-import static com.google.common.truth.Truth.assertThat;
 
 import android.cts.statsdatom.lib.AtomTestUtils;
 import android.cts.statsdatom.lib.ConfigUtils;
 import android.cts.statsdatom.lib.DeviceUtils;
 import android.cts.statsdatom.lib.ReportUtils;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.os.AtomsProto;
 import com.android.os.StatsLog;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-public class PackageInstallerV2StatsTests extends DeviceTestCase implements IBuildReceiver {
-    private static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
+public class PackageInstallerV2StatsTests extends PackageManagerStatsTestsBase {
     private static final String TEST_INSTALL_APK = "CtsStatsdAtomEmptyApp.apk";
     private static final String TEST_INSTALL_APK_BASE = "CtsStatsdAtomEmptySplitApp.apk";
     private static final String TEST_INSTALL_APK_SPLIT = "CtsStatsdAtomEmptySplitApp_pl.apk";
     private static final String TEST_INSTALL_PACKAGE =
             "com.android.cts.packagemanager.stats.emptyapp";
-    private static final String TEST_REMOTE_DIR = "/data/local/tmp/statsdatom";
-    private static final String SIGNATURE_FILE_SUFFIX = ".idsig";
-
-    private IBuildInfo mCtsBuild;
-
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
-    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        assertThat(mCtsBuild).isNotNull();
-        ConfigUtils.removeConfig(getDevice());
-        ReportUtils.clearReports(getDevice());
-        DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild);
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        ConfigUtils.removeConfig(getDevice());
-        ReportUtils.clearReports(getDevice());
-        DeviceUtils.uninstallStatsdTestApp(getDevice());
-        getDevice().deleteFile(TEST_REMOTE_DIR);
         getDevice().uninstallPackage(TEST_INSTALL_PACKAGE);
         super.tearDown();
     }
 
     public void testPackageInstallerV2MetricsReported() throws Throwable {
-        if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) return;
+        if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) {
+            return;
+        }
         final AtomsProto.PackageInstallerV2Reported report = installPackageUsingV2AndGetReport(
                 new String[]{TEST_INSTALL_APK});
         assertTrue(report.getIsIncremental());
@@ -87,7 +63,9 @@
     }
 
     public void testPackageInstallerV2MetricsReportedForSplits() throws Throwable {
-        if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) return;
+        if (!DeviceUtils.hasFeature(getDevice(), FEATURE_INCREMENTAL_DELIVERY)) {
+            return;
+        }
         final AtomsProto.PackageInstallerV2Reported report = installPackageUsingV2AndGetReport(
                 new String[]{TEST_INSTALL_APK_BASE, TEST_INSTALL_APK_SPLIT});
         assertTrue(report.getIsIncremental());
@@ -102,18 +80,12 @@
         assertEquals(getAppUid(TEST_INSTALL_PACKAGE), report.getUid());
     }
 
-    private long getTestFileSize(String fileName) throws Exception {
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
-        final File file = buildHelper.getTestFile(fileName);
-        return file.length();
-    }
-
     private AtomsProto.PackageInstallerV2Reported installPackageUsingV2AndGetReport(
             String[] apkNames) throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 AtomsProto.Atom.PACKAGE_INSTALLER_V2_REPORTED_FIELD_NUMBER);
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
-        installPackageUsingIncremental(apkNames, TEST_REMOTE_DIR);
+        installPackageUsingIncremental(apkNames);
         assertTrue(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE,
                 String.valueOf(getDevice().getCurrentUser())));
         Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
@@ -127,45 +99,4 @@
         assertEquals(1, reports.size());
         return reports.get(0);
     }
-
-    private void installPackageUsingIncremental(String[] apkNames, String remoteDirPath)
-            throws Exception {
-        getDevice().executeShellCommand("mkdir " + remoteDirPath);
-        String[] remoteApkPaths = new String[apkNames.length];
-        for (int i = 0; i < remoteApkPaths.length; i++) {
-            remoteApkPaths[i] = pushApkToRemote(apkNames[i], remoteDirPath);
-        }
-        String installResult = getDevice().executeShellCommand(
-                "pm install-incremental -t -g " + "--user " + getDevice().getCurrentUser() + " "
-                        + String.join(" ", remoteApkPaths));
-        assertEquals("Success\n", installResult);
-    }
-
-    private String pushApkToRemote(String apkName, String remoteDirPath)
-            throws Exception {
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
-        final File apk = buildHelper.getTestFile(apkName);
-        final File signature = buildHelper.getTestFile(apkName + SIGNATURE_FILE_SUFFIX);
-        assertNotNull(apk);
-        assertNotNull(signature);
-        final String remoteApkPath = remoteDirPath + "/" + apk.getName();
-        final String remoteSignaturePath = remoteApkPath + SIGNATURE_FILE_SUFFIX;
-        assertTrue(getDevice().pushFile(apk, remoteApkPath));
-        assertTrue(getDevice().pushFile(signature, remoteSignaturePath));
-        return remoteApkPath;
-    }
-
-    protected int getAppUid(String pkgName) throws Exception {
-        final int currentUser = getDevice().getCurrentUser();
-        final String uidLine = getDevice().executeShellCommand(
-                "cmd package list packages -U --user " + currentUser + " " + pkgName);
-        final Pattern pattern = Pattern.compile("package:" + pkgName + " uid:(\\d+)");
-        final Matcher matcher = pattern.matcher(uidLine);
-        if (matcher.find()) {
-            return Integer.parseInt(matcher.group(1));
-        } else {
-            return -1;
-        }
-    }
-
 }
diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageManagerStatsTestsBase.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageManagerStatsTestsBase.java
new file mode 100644
index 0000000..7a27f74
--- /dev/null
+++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/PackageManagerStatsTestsBase.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.packagemanager.stats.host;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PackageManagerStatsTestsBase extends DeviceTestCase implements IBuildReceiver {
+    protected static final String FEATURE_INCREMENTAL_DELIVERY =
+            "android.software.incremental_delivery";
+    protected static final String TEST_REMOTE_DIR = "/data/local/tmp/statsdatom";
+    private static final String SIGNATURE_FILE_SUFFIX = ".idsig";
+    protected IBuildInfo mCtsBuild;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        assertThat(mCtsBuild).isNotNull();
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        ConfigUtils.removeConfig(getDevice());
+        ReportUtils.clearReports(getDevice());
+        DeviceUtils.uninstallStatsdTestApp(getDevice());
+        getDevice().deleteFile(TEST_REMOTE_DIR);
+        super.tearDown();
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    protected void installPackageUsingIncremental(String[] apkNames)
+            throws Exception {
+        getDevice().executeShellCommand("mkdir -p " + TEST_REMOTE_DIR);
+        String[] remoteApkPaths = new String[apkNames.length];
+        for (int i = 0; i < remoteApkPaths.length; i++) {
+            remoteApkPaths[i] = pushApkToRemote(apkNames[i], TEST_REMOTE_DIR);
+        }
+        String installResult = getDevice().executeShellCommand(
+                "pm install-incremental -t -g " + "--user " + getDevice().getCurrentUser() + " "
+                        + String.join(" ", remoteApkPaths));
+        assertEquals("Success\n", installResult);
+    }
+
+    protected String pushApkToRemote(String apkName, String remoteDirPath)
+            throws Exception {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File apk = buildHelper.getTestFile(apkName);
+        final File signature = buildHelper.getTestFile(apkName + SIGNATURE_FILE_SUFFIX);
+        assertNotNull(apk);
+        assertNotNull(signature);
+        final String remoteApkPath = remoteDirPath + "/" + apk.getName();
+        final String remoteSignaturePath = remoteApkPath + SIGNATURE_FILE_SUFFIX;
+        assertTrue(getDevice().pushFile(apk, remoteApkPath));
+        assertTrue(getDevice().pushFile(signature, remoteSignaturePath));
+        return remoteApkPath;
+    }
+
+    protected int getAppUid(String pkgName) throws Exception {
+        final int currentUser = getDevice().getCurrentUser();
+        final String uidLine = getDevice().executeShellCommand(
+                "cmd package list packages -U --user " + currentUser + " " + pkgName);
+        final Pattern pattern = Pattern.compile("package:" + pkgName + " uid:(\\d+)");
+        final Matcher matcher = pattern.matcher(uidLine);
+        if (matcher.find()) {
+            return Integer.parseInt(matcher.group(1));
+        }
+        throw new IllegalStateException("Package " + pkgName + " is not installed for user "
+                + currentUser);
+    }
+
+    protected long getTestFileSize(String fileName) throws Exception {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File file = buildHelper.getTestFile(fileName);
+        return file.length();
+    }
+}