1 /* 2 * Copyright (C) 2021 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.android.cts.packagemanager.stats.host.Utils.SIGNATURE_FILE_SUFFIX; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import android.cts.statsdatom.lib.AtomTestUtils; 24 import android.cts.statsdatom.lib.ConfigUtils; 25 import android.cts.statsdatom.lib.DeviceUtils; 26 import android.cts.statsdatom.lib.ReportUtils; 27 import android.platform.test.annotations.LargeTest; 28 import android.server.ErrorSource; 29 30 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 31 import com.android.incfs.install.IncrementalInstallSession; 32 import com.android.incfs.install.adb.ddmlib.DeviceConnection; 33 import com.android.os.AtomsProto; 34 import com.android.os.StatsLog; 35 import com.android.tradefed.build.IBuildInfo; 36 import com.android.tradefed.log.LogUtil; 37 import com.android.tradefed.testtype.DeviceTestCase; 38 import com.android.tradefed.testtype.IBuildReceiver; 39 import com.android.tradefed.util.RunUtil; 40 41 import org.junit.After; 42 import org.junit.Before; 43 44 import java.io.File; 45 import java.nio.file.Paths; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.concurrent.Executors; 50 import java.util.concurrent.TimeUnit; 51 52 public final class IncrementalAppErrorStatsTests extends DeviceTestCase implements IBuildReceiver { 53 private static final String TEST_REMOTE_DIR = "/data/local/tmp/appErrorTest"; 54 private static final String HELPER_PACKAGE = "com.android.cts.packagemanager.stats.device"; 55 private static final String HELPER_CLASS = ".IncrementalAppErrorStatsTestsHelper"; 56 private static final String HELPER_METHOD_GET_PAGE_INDEX_TO_BLOCK = "getPageIndexToBlock"; 57 private static final String HELPER_METHOD_LOAD_APKS = "loadingApks"; 58 private static final String HELPER_ARG_APK_PATH = "remoteApkPath"; 59 private static final String HELPER_ARG_PKG_NAME = "packageName"; 60 private static final String PAGE_INDEX_TO_BLOCK = "pageIndexToBlock"; 61 private static final int INSTALL_TIMEOUT_SECONDS = 10; 62 private static final int METRICS_WAIT_MILLISECONDS = 1_000; 63 64 private IBuildInfo mCtsBuild; 65 private IncrementalInstallSession mSession; 66 67 @Override setBuild(IBuildInfo buildInfo)68 public void setBuild(IBuildInfo buildInfo) { 69 mCtsBuild = buildInfo; 70 } 71 72 @Before setUp()73 public void setUp() throws Exception { 74 if (!Utils.hasIncrementalFeature(getDevice())) { 75 return; 76 } 77 super.setUp(); 78 ConfigUtils.removeConfig(getDevice()); 79 ReportUtils.clearReports(getDevice()); 80 81 String remoteApkPath = Utils.pushApkToRemote( 82 DeviceUtils.STATSD_ATOM_TEST_APK, TEST_REMOTE_DIR, mCtsBuild, getDevice()); 83 final HashMap<String, String> testArgs = new HashMap<>(); 84 testArgs.put(HELPER_ARG_APK_PATH, remoteApkPath); 85 Map<String, String> testResult = Utils.runDeviceTests(getDevice(), HELPER_PACKAGE, 86 HELPER_CLASS, HELPER_METHOD_GET_PAGE_INDEX_TO_BLOCK, testArgs); 87 assertNotNull(testResult); 88 assertEquals(1, testResult.size()); 89 90 int blockedPageIndex = Integer.parseInt(testResult.get(PAGE_INDEX_TO_BLOCK)); 91 assertTrue(blockedPageIndex > 0); 92 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); 93 final File apk = buildHelper.getTestFile(DeviceUtils.STATSD_ATOM_TEST_APK); 94 assertNotNull(apk); 95 final File v4Signature = buildHelper.getTestFile( 96 DeviceUtils.STATSD_ATOM_TEST_APK + SIGNATURE_FILE_SUFFIX); 97 assertNotNull(v4Signature); 98 LogUtil.CLog.i("Blocking page at index: " + blockedPageIndex); 99 mSession = new IncrementalInstallSession.Builder() 100 .addApk(Paths.get(apk.getAbsolutePath()), 101 Paths.get(v4Signature.getAbsolutePath())) 102 .addExtraArgs("-g") // grant permissions 103 .setBlockFilter(block -> { 104 // block a page from res/raw; does not affect test run 105 return block.getBlockIndex() != blockedPageIndex; 106 }) 107 .build(); 108 mSession.start(Executors.newCachedThreadPool(), 109 DeviceConnection.getFactory(getDevice().getSerialNumber())); 110 mSession.waitForInstallCompleted(INSTALL_TIMEOUT_SECONDS, TimeUnit.SECONDS); 111 assertTrue(getDevice().isPackageInstalled(DeviceUtils.STATSD_ATOM_TEST_PKG)); 112 // Preload most of the pages to make sure the test can run but it also causes pending reads 113 final HashMap<String, String> testArgsForLoading = new HashMap<>(); 114 testArgsForLoading.put(HELPER_ARG_PKG_NAME, DeviceUtils.STATSD_ATOM_TEST_PKG); 115 Utils.runDeviceTests(getDevice(), HELPER_PACKAGE, HELPER_CLASS, 116 HELPER_METHOD_LOAD_APKS, testArgsForLoading); 117 } 118 hasIncrementalDeliveryV2Feature()119 private boolean hasIncrementalDeliveryV2Feature() throws Exception { 120 return "true\n".equals(getDevice().executeShellCommand( 121 "pm has-feature android.software.incremental_delivery 2")); 122 } 123 124 @After tearDown()125 public void tearDown() throws Exception { 126 if (mSession != null) { 127 mSession.close(); 128 } 129 getDevice().uninstallPackage(DeviceUtils.STATSD_ATOM_TEST_PKG); 130 assertFalse(getDevice().isPackageInstalled(DeviceUtils.STATSD_ATOM_TEST_PKG)); 131 super.tearDown(); 132 } 133 134 @LargeTest testAppCrashOnIncremental()135 public void testAppCrashOnIncremental() throws Exception { 136 if (!Utils.hasIncrementalFeature(getDevice())) { 137 return; 138 } 139 final int atomTag = AtomsProto.Atom.APP_CRASH_OCCURRED_FIELD_NUMBER; 140 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 141 atomTag, /*uidInAttributionChain=*/false); 142 143 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 144 "StatsdCtsForegroundActivity", "action", "action.crash"); 145 RunUtil.getDefault().sleep(METRICS_WAIT_MILLISECONDS); 146 // Sorted list of events in order in which they occurred. 147 List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 148 149 assertThat(data).hasSize(1); 150 AtomsProto.AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred(); 151 // UID should belong to the run activity, not any system service. 152 assertThat(atom.getUid()).isGreaterThan(10000); 153 assertThat(atom.getEventType()).isEqualTo("crash"); 154 assertThat(atom.getIsInstantApp().getNumber()) 155 .isEqualTo(AtomsProto.AppCrashOccurred.InstantApp.FALSE_VALUE); 156 assertThat(atom.getForegroundState().getNumber()) 157 .isEqualTo(AtomsProto.AppCrashOccurred.ForegroundState.FOREGROUND_VALUE); 158 assertThat(atom.getPackageName()).isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG); 159 assertThat(atom.getErrorSource()).isEqualTo(ErrorSource.DATA_APP); 160 assertTrue(atom.getIsIncremental()); 161 assertFalse((1.0f - atom.getLoadingProgress()) < 0.0000001f); 162 assertTrue(atom.getMillisSinceOldestPendingRead() > 0); 163 assertEquals(3 /* HEALTH_STATUS_UNHEALTHY */, atom.getStorageHealthCode()); 164 assertEquals(6 /* DATA_LOADER_IMAGE_READY */, atom.getDataLoaderStatusCode()); 165 assertFalse(atom.getReadLogsEnabled()); 166 assertTrue(atom.getMillisSinceLastDataLoaderBind() > 0); 167 assertEquals(0, atom.getDataLoaderBindDelayMillis()); 168 if (!hasIncrementalDeliveryV2Feature()) { 169 // Skip kernel stats check if it's not supported 170 return; 171 } 172 assertTrue(atom.getTotalDelayedReads() > 0); 173 assertTrue(atom.getTotalFailedReads() > 0); 174 assertTrue(atom.getLastReadErrorMillisSince() > 0); 175 assertEquals(-62 /* -ETIME */, atom.getLastReadErrorCode()); 176 assertTrue(atom.getTotalDelayedReadsDurationMillis() > 0); 177 } 178 179 @LargeTest testAppAnrIncremental()180 public void testAppAnrIncremental() throws Exception { 181 if (!Utils.hasIncrementalFeature(getDevice())) { 182 return; 183 } 184 final int atomTag = AtomsProto.Atom.ANR_OCCURRED_FIELD_NUMBER; 185 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 186 atomTag, /*useUidAttributionChain=*/false); 187 final int ANR_WAIT_MILLS = 15_000; 188 189 try (AutoCloseable a = DeviceUtils.withActivity(getDevice(), 190 DeviceUtils.STATSD_ATOM_TEST_PKG, "ANRActivity", null, null)) { 191 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 192 getDevice().executeShellCommand( 193 "am broadcast -a action_anr -p " + DeviceUtils.STATSD_ATOM_TEST_PKG); 194 RunUtil.getDefault().sleep(ANR_WAIT_MILLS); 195 } 196 197 // Sorted list of events in order in which they occurred. 198 List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 199 200 assertThat(data).hasSize(1); 201 assertThat(data.get(0).getAtom().hasAnrOccurred()).isTrue(); 202 AtomsProto.ANROccurred atom = data.get(0).getAtom().getAnrOccurred(); 203 assertThat(atom.getIsInstantApp().getNumber()) 204 .isEqualTo(AtomsProto.ANROccurred.InstantApp.FALSE_VALUE); 205 assertThat(atom.getForegroundState().getNumber()) 206 .isEqualTo(AtomsProto.ANROccurred.ForegroundState.FOREGROUND_VALUE); 207 assertThat(atom.getErrorSource()).isEqualTo(ErrorSource.DATA_APP); 208 assertThat(atom.getPackageName()).isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG); 209 assertTrue(atom.getIsIncremental()); 210 assertFalse((1.0f - atom.getLoadingProgress()) < 0.0000001f); 211 } 212 } 213