blob: e8c42d15d4a06466a06c9bbb1fa20e5ab3656d81 [file] [log] [blame]
/*
* 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 android.cts.statsdatom.appexit;
import static android.app.AppExitReasonCode.REASON_OTHER;
import static android.app.AppExitReasonCode.REASON_PERMISSION_CHANGE;
import static android.app.AppExitSubReasonCode.SUBREASON_ISOLATED_NOT_NEEDED;
import static android.app.Importance.IMPORTANCE_CACHED;
import static android.app.Importance.IMPORTANCE_SERVICE;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
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 com.android.os.StatsLog;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AppExitHostTest extends DeviceTestCase implements IBuildReceiver {
private static final String TEST_PKG = "android.app.cts.appexit";
private static final String HELPER_PKG1 = "android.externalservice.service";
private static final String HELPER_PKG2 = "com.android.cts.launcherapps.simpleapp";
private static final String TEST_APK = "CtsAppExitTestCases.apk";
private static final String HELPER_APK1 = "CtsExternalServiceService.apk";
private static final String HELPER_APK2 = "CtsSimpleApp.apk";
private static final String TEST_CLASS = "android.app.cts.ActivityManagerAppExitInfoTest";
private static final long APP_EXIT_INFO_STATSD_LOG_DEBOUNCE_MSEC = 15_000;
private static final String PERM_PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
private static final String PERM_READ_LOGS = "android.permission.READ_LOGS";
private IBuildInfo mCtsBuild;
@Override
protected void setUp() throws Exception {
super.setUp();
assertThat(mCtsBuild).isNotNull();
ConfigUtils.removeConfig(getDevice());
ReportUtils.clearReports(getDevice());
DeviceUtils.installTestApp(getDevice(), TEST_APK, TEST_PKG, mCtsBuild);
DeviceUtils.installTestApp(getDevice(), HELPER_APK1, HELPER_PKG1, mCtsBuild);
DeviceUtils.installTestApp(getDevice(), HELPER_APK2, HELPER_PKG2, mCtsBuild);
Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
getDevice().executeShellCommand("cmd deviceidle tempwhitelist -r " + HELPER_PKG1);
getDevice().executeShellCommand("cmd deviceidle tempwhitelist -r " + HELPER_PKG2);
getDevice().executeShellCommand("pm grant " + TEST_PKG + " " + PERM_PACKAGE_USAGE_STATS);
getDevice().executeShellCommand("pm grant " + TEST_PKG + " " + PERM_READ_LOGS);
}
@Override
protected void tearDown() throws Exception {
ConfigUtils.removeConfig(getDevice());
ReportUtils.clearReports(getDevice());
getDevice().executeShellCommand("pm revoke " + TEST_PKG + " " + PERM_PACKAGE_USAGE_STATS);
getDevice().executeShellCommand("pm revoke " + TEST_PKG + " " + PERM_READ_LOGS);
DeviceUtils.uninstallTestApp(getDevice(), TEST_PKG);
DeviceUtils.uninstallTestApp(getDevice(), HELPER_PKG1);
DeviceUtils.uninstallTestApp(getDevice(), HELPER_PKG2);
super.tearDown();
}
@Override
public void setBuild(IBuildInfo buildInfo) {
mCtsBuild = buildInfo;
}
public void testLogStatsdPermChanged() throws Exception {
final String helperPackage = HELPER_PKG2;
final int expectedUid = getAppUid(helperPackage);
performLogStatsdTest("testPermissionChange", helperPackage, 1, appDied -> {
assertThat(appDied.getUid()).isEqualTo(expectedUid);
assertThat(appDied.getProcessName()).isEqualTo("");
assertThat(appDied.getReason()).isEqualTo(REASON_PERMISSION_CHANGE);
assertThat(appDied.getImportance()).isEqualTo(IMPORTANCE_CACHED);
assertThat(appDied.getPss()).isAtLeast(0);
assertThat(appDied.getRss()).isAtLeast(0);
});
}
public void testLogStatsdOther() throws Exception {
final String helperPackage = HELPER_PKG1;
final int expectedUid = getAppUid(TEST_PKG);
performLogStatsdTest("testOther", TEST_PKG, 2, appDied -> {
assertThat(appDied.getUid()).isEqualTo(expectedUid);
assertThat(appDied.getProcessName()).isEqualTo(
helperPackage + ":android.externalservice.service.ExternalServiceWithZygote");
assertThat(appDied.getReason()).isEqualTo(REASON_OTHER);
assertThat(appDied.getSubReason()).isEqualTo(SUBREASON_ISOLATED_NOT_NEEDED);
assertThat(appDied.getImportance()).isEqualTo(IMPORTANCE_SERVICE);
});
}
private void performLogStatsdTest(String testMethod, String targetPackage, int expectedSize,
Consumer<AtomsProto.AppProcessDied> verifier) throws Exception {
final int atomTag = AtomsProto.Atom.APP_PROCESS_DIED_FIELD_NUMBER;
ConfigUtils.removeConfig(getDevice());
ReportUtils.clearReports(getDevice());
ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), targetPackage,
atomTag, /* useUidAttributionChain= */ false);
DeviceUtils.runDeviceTests(getDevice(), TEST_PKG, TEST_CLASS, testMethod);
Thread.sleep(APP_EXIT_INFO_STATSD_LOG_DEBOUNCE_MSEC);
List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
assertThat(data).isNotNull();
assertThat(data.size()).isEqualTo(expectedSize);
verifier.accept(data.get(0).getAtom().getAppProcessDied());
}
private 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);
assertWithMessage("Pkg not found: " + pkgName).that(matcher.find()).isTrue();
final int appUid = Integer.parseInt(matcher.group(1));
return appUid;
}
}