1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.packagemanager.stats.host; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.cts.statsdatom.lib.AtomTestUtils; 22 import android.cts.statsdatom.lib.ConfigUtils; 23 import android.cts.statsdatom.lib.DeviceUtils; 24 import android.cts.statsdatom.lib.ReportUtils; 25 26 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 27 import com.android.os.AtomsProto; 28 import com.android.os.StatsLog; 29 import com.android.tradefed.device.DeviceNotAvailableException; 30 import com.android.tradefed.util.RunUtil; 31 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.stream.Collectors; 39 40 public class PackageInstallationSessionReportedStatsTests extends PackageManagerStatsTestsBase { 41 private static final int STEP_FREEZE_INSTALL = 6; 42 private static final String TEST_INSTALL_APK = "CtsStatsdAtomEmptyApp.apk"; 43 private static final String TEST_INSTALL_APK_V2 = "CtsStatsdAtomEmptyAppV2.apk"; 44 private static final String TEST_INSTALL_PACKAGE = 45 "com.android.cts.packagemanager.stats.emptyapp"; 46 private static final String HELPER_PACKAGE = "com.android.cts.packagemanager.stats.device"; 47 private static final String HELPER_CLASS = 48 ".PackageInstallationSessionReportedStatsTestsHelper"; 49 private static final String GET_USER_TYPES_HELPER_METHOD = "getUserTypeIntegers"; 50 private static final String GET_USER_TYPES_HELPER_ARG_USER_IDS = "userIds"; 51 private static final String GET_USER_TYPES_HELPER_ARG_USER_TYPES = "userTypes"; 52 private static final String TEST_INSTALL_STATIC_SHARED_LIB_V1_APK = 53 "CtsStatsdAtomStaticSharedLibProviderV1.apk"; 54 private static final String TEST_INSTALL_STATIC_SHARED_LIB_V2_APK = 55 "CtsStatsdAtomStaticSharedLibProviderV2.apk"; 56 private static final String TEST_INSTALL_STATIC_SHARED_LIB_V1_PACKAGE = 57 "com.android.cts.packagemanager.stats.emptystaticsharedlib"; 58 private static final String TEST_INSTALL_STATIC_SHARED_LIB_NAME = "test.stats.lib"; 59 60 @Override tearDown()61 protected void tearDown() throws Exception { 62 getDevice().uninstallPackage(TEST_INSTALL_PACKAGE); 63 getDevice().uninstallPackage(TEST_INSTALL_STATIC_SHARED_LIB_V1_PACKAGE); 64 super.tearDown(); 65 } 66 testPackageInstallationSessionReportedForApkSuccessWithReplace()67 public void testPackageInstallationSessionReportedForApkSuccessWithReplace() throws Exception { 68 if (!Utils.hasIncrementalFeature(getDevice())) { 69 return; 70 } 71 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 72 AtomsProto.Atom.PACKAGE_INSTALLATION_SESSION_REPORTED_FIELD_NUMBER); 73 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 74 DeviceUtils.installTestApp(getDevice(), TEST_INSTALL_APK, TEST_INSTALL_PACKAGE, mCtsBuild); 75 assertThat(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE, 76 String.valueOf(getDevice().getCurrentUser()))).isTrue(); 77 installPackageUsingIncremental(new String[]{TEST_INSTALL_APK_V2}); 78 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 79 List<AtomsProto.PackageInstallationSessionReported> reports = new ArrayList<>(); 80 for (StatsLog.EventMetricData data : ReportUtils.getEventMetricDataList(getDevice())) { 81 if (data.getAtom().hasPackageInstallationSessionReported()) { 82 reports.add(data.getAtom().getPackageInstallationSessionReported()); 83 } 84 } 85 assertThat(reports.size()).isEqualTo(2); 86 final int expectedUid = getAppUid(TEST_INSTALL_PACKAGE); 87 final int expectedUser = getDevice().getCurrentUser(); 88 final long expectedApksSizeBytes = getTestFileSize(TEST_INSTALL_APK); 89 // TODO(b/249294752): check installer in the report 90 checkReportResult(reports.get(0), expectedUid, Collections.singletonList(expectedUser), 91 Collections.emptyList(), 1 /* success */, 0 /* internalErrorCode */, 92 1 /* versionCode */, expectedApksSizeBytes, 0 /* dataLoaderType */, 93 0 /* expectedUserActionRequiredType */, false, 94 false, false, false, false, false, false); 95 checkDurationResult(reports.get(0)); 96 97 checkReportResult(reports.get(1), expectedUid, Collections.singletonList(expectedUser), 98 Collections.singletonList(expectedUser), 1 /* success */, 0 /* internalErrorCode */, 99 2 /* versionCode */, getTestFileSize(TEST_INSTALL_APK_V2), 2 /* dataLoaderType */, 100 0 /* expectedUserActionRequiredType */, false, 101 true, false, false, false, false, false); 102 checkDurationResult(reports.get(1)); 103 104 // No uninstall log from app update 105 List<AtomsProto.PackageUninstallationReported> uninstallReports = new ArrayList<>(); 106 for (StatsLog.EventMetricData data : ReportUtils.getEventMetricDataList(getDevice())) { 107 if (data.getAtom().hasPackageUninstallationReported()) { 108 uninstallReports.add(data.getAtom().getPackageUninstallationReported()); 109 } 110 } 111 assertThat(uninstallReports).isEmpty(); 112 } 113 checkDurationResult(AtomsProto.PackageInstallationSessionReported report)114 private void checkDurationResult(AtomsProto.PackageInstallationSessionReported report) { 115 final long totalDuration = report.getTotalDurationMillis(); 116 assertThat(totalDuration).isGreaterThan(0); 117 // TODO(b/308138823): Use hortenInstallFreeze(), meet java.lang.NoClassDefFoundError: 118 // android/provider/DeviceConfig error 119 // @RequiresFlagsEnabled still runs even the flag is false. 120 //int expectedSteps = shortenInstallFreeze() ? 5 : 4; 121 assertThat(report.getInstallStepsCount()).isAtLeast(4); 122 long sumStepDurations = 0; 123 int stepCount = report.getInstallStepsCount(); 124 for (int i = 0; i < stepCount; i++) { 125 int step = report.getInstallSteps(i); 126 // Don't count freeze step time 127 if (step != STEP_FREEZE_INSTALL) { 128 long duration = report.getStepDurationMillis(i); 129 assertThat(duration).isAtLeast(0); 130 sumStepDurations += duration; 131 } 132 } 133 assertThat(sumStepDurations).isGreaterThan(0); 134 assertThat(sumStepDurations).isLessThan(totalDuration); 135 } 136 checkReportResult(AtomsProto.PackageInstallationSessionReported report, int expectedUid, List<Integer> expectedUserIds, List<Integer> expectedOriginalUserIds, int expectedPublicReturnCode, int expectedInternalErrorCode, long expectedVersionCode, long expectedApksSizeBytes, int expectedDataLoaderType, int expectedUserActionRequiredType, boolean expectedIsInstant, boolean expectedIsReplace, boolean expectedIsSystem, boolean expectedIsInherit, boolean expectedInstallingExistingAsUser, boolean expectedIsMoveInstall, boolean expectedIsStaged)137 private void checkReportResult(AtomsProto.PackageInstallationSessionReported report, 138 int expectedUid, List<Integer> expectedUserIds, 139 List<Integer> expectedOriginalUserIds, int expectedPublicReturnCode, 140 int expectedInternalErrorCode, 141 long expectedVersionCode, long expectedApksSizeBytes, int expectedDataLoaderType, 142 int expectedUserActionRequiredType, 143 boolean expectedIsInstant, boolean expectedIsReplace, boolean expectedIsSystem, 144 boolean expectedIsInherit, boolean expectedInstallingExistingAsUser, 145 boolean expectedIsMoveInstall, boolean expectedIsStaged) 146 throws DeviceNotAvailableException { 147 assertThat(report.getSessionId()).isNotEqualTo(-1); 148 assertThat(report.getUid()).isEqualTo(expectedUid); 149 assertThat(report.getUserIdsList()).containsAtLeastElementsIn(expectedUserIds); 150 checkUserTypes(expectedUserIds, report.getUserTypesList()); 151 assertThat(report.getOriginalUserIdsList()).containsAtLeastElementsIn( 152 expectedOriginalUserIds); 153 assertThat(report.getPublicReturnCode()).isEqualTo(expectedPublicReturnCode); 154 assertThat(report.getInternalErrorCode()).isEqualTo(expectedInternalErrorCode); 155 assertThat(report.getVersionCode()).isEqualTo(expectedVersionCode); 156 assertThat(report.getApksSizeBytes()).isEqualTo(expectedApksSizeBytes); 157 assertThat(report.getOriginalInstallerPackageUid()).isEqualTo(-1); 158 assertThat(report.getDataLoaderType()).isEqualTo(expectedDataLoaderType); 159 assertThat(report.getUserActionRequiredType()).isEqualTo(expectedUserActionRequiredType); 160 assertThat(report.getIsInstant()).isEqualTo(expectedIsInstant); 161 assertThat(report.getIsReplace()).isEqualTo(expectedIsReplace); 162 assertThat(report.getIsSystem()).isEqualTo(expectedIsSystem); 163 assertThat(report.getIsInherit()).isEqualTo(expectedIsInherit); 164 assertThat(report.getIsInstallingExistingAsUser()).isEqualTo( 165 expectedInstallingExistingAsUser); 166 assertThat(report.getIsMoveInstall()).isEqualTo(expectedIsMoveInstall); 167 assertThat(report.getIsStaged()).isEqualTo(expectedIsStaged); 168 // assert that package name is not set if install comes from adb 169 if ((report.getInstallFlags() & 0x00000020 /* INSTALL_FROM_ADB */) != 0) { 170 assertThat(report.getPackageName()).isEmpty(); 171 } 172 } 173 checkUserTypes(List<Integer> userIds, List<Integer> reportedUserTypes)174 private void checkUserTypes(List<Integer> userIds, List<Integer> reportedUserTypes) 175 throws DeviceNotAvailableException { 176 if (userIds == null || userIds.isEmpty()) { 177 return; 178 } 179 final HashMap<String, String> testArgs = new HashMap<>(); 180 testArgs.put(GET_USER_TYPES_HELPER_ARG_USER_IDS, 181 userIds.stream().map(Object::toString).collect(Collectors.joining(",")) 182 ); 183 Map<String, String> testResult = Utils.runDeviceTests(getDevice(), HELPER_PACKAGE, 184 HELPER_CLASS, GET_USER_TYPES_HELPER_METHOD, testArgs); 185 assertNotNull(testResult); 186 assertEquals(1, testResult.size()); 187 String[] userTypesStrings = testResult.get(GET_USER_TYPES_HELPER_ARG_USER_TYPES).split(","); 188 List<Integer> expectedUserTypes = Arrays.stream(userTypesStrings).map( 189 Integer::valueOf).collect(Collectors.toList()); 190 assertThat(reportedUserTypes).containsAtLeastElementsIn(expectedUserTypes); 191 } 192 testPackageUninstalledReported()193 public void testPackageUninstalledReported() throws Exception { 194 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 195 AtomsProto.Atom.PACKAGE_UNINSTALLATION_REPORTED_FIELD_NUMBER); 196 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 197 DeviceUtils.installTestApp(getDevice(), TEST_INSTALL_APK, TEST_INSTALL_PACKAGE, mCtsBuild); 198 assertThat(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE, 199 String.valueOf(getDevice().getCurrentUser()))).isTrue(); 200 final int expectedUid = getAppUid(TEST_INSTALL_PACKAGE); 201 DeviceUtils.uninstallTestApp(getDevice(), TEST_INSTALL_PACKAGE); 202 assertThat(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE, 203 String.valueOf(getDevice().getCurrentUser()))).isFalse(); 204 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 205 List<AtomsProto.PackageUninstallationReported> reports = new ArrayList<>(); 206 for (StatsLog.EventMetricData data : ReportUtils.getEventMetricDataList(getDevice())) { 207 if (data.getAtom().hasPackageUninstallationReported()) { 208 reports.add(data.getAtom().getPackageUninstallationReported()); 209 } 210 } 211 assertThat(reports.size()).isEqualTo(1); 212 AtomsProto.PackageUninstallationReported report = reports.get(0); 213 assertThat(report.getUid()).isEqualTo(expectedUid); 214 final List<Integer> users = Collections.singletonList(getDevice().getCurrentUser()); 215 assertThat(report.getUserIdsList()).containsAtLeastElementsIn(users); 216 assertThat(report.getOriginalUserIdsList()).containsAtLeastElementsIn(users); 217 assertThat(report.getUninstallFlags()).isEqualTo(2 /* DELETE_ALL_USERS */); 218 assertThat(report.getReturnCode()).isEqualTo(1); 219 assertThat(report.getIsSystem()).isFalse(); 220 assertThat(report.getIsUninstallForUsers()).isFalse(); 221 } 222 testPackageInstallationFailedVersionDowngradeReported()223 public void testPackageInstallationFailedVersionDowngradeReported() throws Exception { 224 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 225 AtomsProto.Atom.PACKAGE_INSTALLATION_SESSION_REPORTED_FIELD_NUMBER); 226 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 227 DeviceUtils.installTestApp(getDevice(), TEST_INSTALL_APK_V2, TEST_INSTALL_PACKAGE, 228 mCtsBuild); 229 assertThat(getDevice().isPackageInstalled(TEST_INSTALL_PACKAGE, 230 String.valueOf(getDevice().getCurrentUser()))).isTrue(); 231 // Second install should fail because of version downgrade 232 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); 233 final String result = getDevice().installPackage(buildHelper.getTestFile(TEST_INSTALL_APK), 234 /*reinstall=*/true, /*grantPermissions=*/true); 235 assertThat(result).isNotNull(); 236 237 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 238 List<AtomsProto.PackageInstallationSessionReported> reports = new ArrayList<>(); 239 for (StatsLog.EventMetricData data : ReportUtils.getEventMetricDataList(getDevice())) { 240 if (data.getAtom().hasPackageInstallationSessionReported()) { 241 reports.add(data.getAtom().getPackageInstallationSessionReported()); 242 } 243 } 244 assertThat(reports.size()).isEqualTo(2); 245 final int expectedUid = getAppUid(TEST_INSTALL_PACKAGE); 246 final int expectedUser = getDevice().getCurrentUser(); 247 checkReportResult(reports.get(0), expectedUid, Collections.singletonList(expectedUser), 248 Collections.emptyList(), 1 /* success */, 0 /* internalErrorCode */, 249 2 /* versionCode */, getTestFileSize(TEST_INSTALL_APK_V2), 0 /* dataLoaderType */, 250 0 /* expectedUserActionRequiredType */, false, 251 false, false, false, false, false, false); 252 checkDurationResult(reports.get(0)); 253 checkReportResult( 254 reports.get(1), -1 /* uid */, Collections.emptyList(), Collections.emptyList(), 255 -25 /* INSTALL_FAILED_VERSION_DOWNGRADE */, 0 /* internalErrorCode */, 256 0 /* versionCode */, 0, 0 /* dataLoaderType */, 257 0 /* expectedUserActionRequiredType */, false, 258 false, false, false, false, false, false); 259 } 260 testPackageInstallationFailedInternalErrorReported()261 public void testPackageInstallationFailedInternalErrorReported() throws Exception { 262 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 263 AtomsProto.Atom.PACKAGE_INSTALLATION_SESSION_REPORTED_FIELD_NUMBER); 264 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 265 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); 266 String result = getDevice().installPackage(buildHelper.getTestFile( 267 TEST_INSTALL_STATIC_SHARED_LIB_V1_APK), 268 /*reinstall=*/true, /*grantPermissions=*/true); 269 assertThat(result).isNull(); 270 assertThat(isLibraryInstalled(TEST_INSTALL_STATIC_SHARED_LIB_NAME)).isTrue(); 271 // Second install should fail because of static shared lib version order mismatch 272 result = getDevice().installPackage(buildHelper.getTestFile( 273 TEST_INSTALL_STATIC_SHARED_LIB_V2_APK), 274 /*reinstall=*/true, /*grantPermissions=*/true); 275 assertThat(result).isNotNull(); 276 277 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 278 List<AtomsProto.PackageInstallationSessionReported> reports = new ArrayList<>(); 279 for (StatsLog.EventMetricData data : ReportUtils.getEventMetricDataList(getDevice())) { 280 if (data.getAtom().hasPackageInstallationSessionReported()) { 281 reports.add(data.getAtom().getPackageInstallationSessionReported()); 282 } 283 } 284 assertThat(reports.size()).isEqualTo(2); 285 final int expectedUid = getAppUid(TEST_INSTALL_STATIC_SHARED_LIB_V1_PACKAGE); 286 final int expectedUser = getDevice().getCurrentUser(); 287 checkReportResult(reports.get(0), expectedUid, Collections.singletonList(expectedUser), 288 Collections.emptyList(), 1 /* success */, 0 /* internalErrorCode */, 289 1 /* versionCode */, getTestFileSize(TEST_INSTALL_APK_V2), 0 /* dataLoaderType */, 290 0 /* expectedUserActionRequiredType */, false, 291 false, false, false, false, false, false); 292 checkDurationResult(reports.get(0)); 293 checkReportResult( 294 reports.get(1), -1 /* uid */, Collections.emptyList(), Collections.emptyList(), 295 -110 /* INSTALL_FAILED_INTERNAL_ERROR */, 296 -14 /* INTERNAL_ERROR_STATIC_SHARED_LIB_VERSION_CODES_ORDER */, 297 0 /* versionCode */, 298 0, 0 /* dataLoaderType */, 299 0 /* expectedUserActionRequiredType */, false, 300 false, false, false, false, false, false); 301 } 302 } 303