blob: a4e1b66348e8d93b63cc6b224a65305c6af8b40f [file] [log] [blame]
/*
* Copyright (C) 2023 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.ext.services.hosttests;
import static com.google.common.truth.Truth.assertWithMessage;
import android.ext.services.hosttests.utils.ExtServicesLogcatReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.PackageInfo;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.IDeviceTest;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Locale;
import java.util.function.Predicate;
import java.util.regex.Pattern;
// TODO(b/297207132) - extend AdServicesHostSideTestCase instead.
@RunWith(DeviceJUnit4ClassRunner.class)
public class AdServicesFilesCleanupBootCompleteReceiverHostTest implements IDeviceTest {
private static final String EXTSERVICES_PACKAGE_SUFFIX = "android.ext.services";
private static final String CLEANUP_RECEIVER_CLASS_NAME =
"android.ext.services.common.AdServicesFilesCleanupBootCompleteReceiver";
private static final String LOGCAT_COMMAND = "logcat -s extservices";
private static final String RECEIVER_DISABLED_LOG_TEXT =
"Disabled AdServices files cleanup receiver";
private static final String RECEIVER_EXECUTED_LOG_TEXT = "AdServices files cleanup receiver";
private ITestDevice mDevice;
private String mAdServicesFilePath;
private String mExtServicesPackageName;
@Override
public void setDevice(ITestDevice device) {
mDevice = device;
}
@Override
public ITestDevice getDevice() {
return mDevice;
}
@Before
public void setUp() throws Exception {
overridePhSync();
ITestDevice device = getDevice();
// Find the extservices package
PackageInfo extServicesPackage =
device.getAppPackageInfos().stream()
.filter(s -> s.getPackageName().endsWith(EXTSERVICES_PACKAGE_SUFFIX))
.findFirst()
.orElse(null);
assertWithMessage("ExtServices package").that(extServicesPackage).isNotNull();
mExtServicesPackageName = extServicesPackage.getPackageName();
// Put some data in the ExtServices apk
mAdServicesFilePath =
String.format(
"/data/user/%d/%s/adservices_data.txt",
device.getCurrentUser(), extServicesPackage.getPackageName());
String dataPutCommand = String.format("echo \"Hello\" > %s", mAdServicesFilePath);
device.executeShellCommand(dataPutCommand);
assertWithMessage("%s exists", mAdServicesFilePath)
.that(device.doesFileExist(mAdServicesFilePath))
.isTrue();
}
@After
public void tearDown() throws Exception {
resetPhSync();
if (mDevice != null && mAdServicesFilePath != null
&& mDevice.doesFileExist(mAdServicesFilePath)) {
mDevice.deleteFile(mAdServicesFilePath);
}
}
@Test
public void testReceiver_doesNotExecuteOnSMinus() throws Exception {
// TODO(b/297207132) - use SdkLevelSupportRule instead of this manual check
Assume.assumeTrue(getDevice().getApiLevel() < 33); // Run only on Android S-
ITestDevice device = getDevice();
// TODO(b/297207132) - use a rule instead of this shell command
// Enable the flag that the receiver checks. By default, the flag is enabled in the binary,
// so it's enough to just delete the flag override, if any.
device.executeShellCommand(
"device_config delete adservices extservices_adservices_data_cleanup_enabled");
// Reboot, wait, and verify logs.
verifyReceiverDidNotExecute(device);
// Verify that adservices files are still present.
assertWithMessage("%s exists", mAdServicesFilePath)
.that(device.doesFileExist(mAdServicesFilePath))
.isTrue();
}
@Test
public void testReceiver_deletesFiles() throws Exception {
// TODO(b/297207132) - use SdkLevelSupportRule instead of this manual check
Assume.assumeTrue(getDevice().getApiLevel() >= 33); // Run only on Android T+
ITestDevice device = getDevice();
// Re-enable the cleanup receiver in case it's been disabled due to a prior run
enableReceiver(device);
// Enable the flag that the receiver checks. By default, the flag is enabled in the binary,
// so it's enough to just delete the flag override, if any.
device.executeShellCommand(
"device_config delete adservices extservices_adservices_data_cleanup_enabled");
// Reboot, wait, and verify logs.
verifyReceiverExecuted(device);
// Verify that all adservices files were deleted.
assertWithMessage("%s exists", mAdServicesFilePath)
.that(device.doesFileExist(mAdServicesFilePath))
.isFalse();
String lsCommand =
String.format(
"ls /data/user/%d/%s -R", device.getCurrentUser(), mExtServicesPackageName);
String lsOutput = device.executeShellCommand(lsCommand).toLowerCase(Locale.ROOT);
assertWithMessage("Output of %s", lsCommand).that(lsOutput).doesNotContain("adservices");
// Verify that after a reboot the receiver does not execute
verifyReceiverDidNotExecute(device);
}
@Test
public void testReceiver_doesNotExecuteIfFlagDisabled() throws Exception {
// TODO(b/297207132) - use SdkLevelSupportRule instead of this manual check
Assume.assumeTrue(getDevice().getApiLevel() >= 33); // Run only on Android T+
ITestDevice device = getDevice();
// Re-enable the cleanup receiver in case it's been disabled due to a prior run
enableReceiver(device);
// Disable the flag that the receiver checks
device.executeShellCommand(
"device_config put adservices extservices_adservices_data_cleanup_enabled false");
// Verify that after a reboot the receiver executes but doesn't disable itself
ExtServicesLogcatReceiver logcatReceiver =
rebootDeviceAndCollectLogs(device, RECEIVER_DISABLED_LOG_TEXT);
Pattern errorPattern = Pattern.compile(makePattern(RECEIVER_DISABLED_LOG_TEXT));
assertWithMessage("Presence of log indicating receiver disabled itself")
.that(logcatReceiver.patternMatches(errorPattern))
.isFalse();
// Verify that the file is still there and that the receiver didn't delete it.
assertWithMessage("%s exists", mAdServicesFilePath)
.that(device.doesFileExist(mAdServicesFilePath))
.isTrue();
}
private void verifyReceiverExecuted(ITestDevice device)
throws DeviceNotAvailableException, InterruptedException {
ExtServicesLogcatReceiver logcatReceiver =
rebootDeviceAndCollectLogs(device, RECEIVER_DISABLED_LOG_TEXT);
Pattern errorPattern = Pattern.compile(makePattern(RECEIVER_DISABLED_LOG_TEXT));
assertWithMessage("Presence of log indicating receiver disabled itself")
.that(logcatReceiver.patternMatches(errorPattern))
.isTrue();
}
private void verifyReceiverDidNotExecute(ITestDevice device)
throws DeviceNotAvailableException, InterruptedException {
ExtServicesLogcatReceiver logcatReceiver =
rebootDeviceAndCollectLogs(device, RECEIVER_EXECUTED_LOG_TEXT);
Pattern errorPattern = Pattern.compile(makePattern(RECEIVER_EXECUTED_LOG_TEXT));
assertWithMessage("Presence of log indicating receiver was invoked")
.that(logcatReceiver.patternMatches(errorPattern))
.isFalse();
}
private Predicate<String[]> stopIfTextOccurs(String toMatch) {
return (s) -> Arrays.stream(s).anyMatch(t -> t.contains(toMatch));
}
private ExtServicesLogcatReceiver rebootDeviceAndCollectLogs(ITestDevice device, String text)
throws DeviceNotAvailableException, InterruptedException {
// reboot the device
device.reboot();
device.waitForDeviceAvailable();
// Enable verbose logs
// TODO(b/297207132) - add to the rule instead of this shell command
device.executeShellCommand("setprop log.tag.extservices VERBOSE");
// Start log collection
ExtServicesLogcatReceiver logcatReceiver =
new ExtServicesLogcatReceiver.Builder()
.setDevice(device)
.setLogCatCommand(LOGCAT_COMMAND)
.setEarlyStopCondition(stopIfTextOccurs(text))
.build();
logcatReceiver.collectLogs(/* timeoutMilliseconds= */ 5 * 60 * 1000); // Wait up to 5 mins
return logcatReceiver;
}
private String makePattern(String text) {
return ".*" + text + ".*";
}
private void overridePhSync() throws DeviceNotAvailableException {
getDevice()
.executeShellCommand(
"device_config put adservices set_sync_disabled_for_tests persistent");
}
private void resetPhSync() throws DeviceNotAvailableException {
getDevice()
.executeShellCommand(
"device_config put adservices set_sync_disabled_for_tests none");
}
private void enableReceiver(ITestDevice device) throws DeviceNotAvailableException {
String enableCommand =
String.format(
"pm enable %s/%s", mExtServicesPackageName, CLEANUP_RECEIVER_CLASS_NAME);
device.executeShellCommand(enableCommand);
}
}