1 /*
2  * Copyright (C) 2023 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.tests.sdksandbox.host;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.junit.Assume.assumeTrue;
23 
24 import android.app.sdksandbox.hosttestutils.DeviceSupportHostUtils;
25 
26 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
27 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
28 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
29 
30 import org.junit.After;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 
35 @RunWith(DeviceJUnit4ClassRunner.class)
36 public final class SdkSandboxSmallModuleHostTest extends BaseHostJUnit4Test {
37 
38     private static final String TEST_APP_PACKAGE = "com.android.tests.sdksandbox";
39     private static final String MODULE_NAME = "com.android.adservices";
40     private static final String SYSTEM_APEX_PATH = "/system/apex/" + MODULE_NAME + ".capex";
41     private static final String PRIV_APP_DIR = "/apex/" + MODULE_NAME + "/priv-app";
42     private static final String ACTIVE_APEX_DIR = "/data/apex/active/";
43 
44     private final DeviceSupportHostUtils mDeviceSupportUtils = new DeviceSupportHostUtils(this);
45 
46     /**
47      * Runs the given phase of a test by calling into the device.
48      *
49      * <p>Hidden API checks are disabled.
50      *
51      * <p>For example, <code>runPhase("testExample");</code>
52      *
53      * @throws AssertionException if test phase fails.
54      */
runPhase(String phase)55     private void runPhase(String phase) throws Exception {
56         DeviceTestRunOptions options =
57                 new DeviceTestRunOptions(TEST_APP_PACKAGE)
58                         .setTestClassName(TEST_APP_PACKAGE + ".SdkSandboxSmallModuleTestApp")
59                         .setTestMethodName(phase)
60                         .setDisableHiddenApiCheck(true);
61 
62         assertThat(runDeviceTests(options)).isTrue();
63     }
64 
65     @Before
setUp()66     public void setUp() throws Exception {
67         assumeTrue(
68                 "Device needs to support SdkSandbox", mDeviceSupportUtils.isSdkSandboxSupported());
69 
70         // Determine if Small module related test can be run on the device
71         boolean canBeUpdatedWithSmallModule = isSmallModuleUpdatePossible();
72         boolean alreadyHasSmallModuleInstalled = !isAdServicesApkPresent();
73         assumeTrue(
74                 "Device has com.android.adservices APEX or small module pre-installed",
75                 canBeUpdatedWithSmallModule || alreadyHasSmallModuleInstalled);
76 
77         removeUpdatedApexIfNecessary();
78     }
79 
80     @After
tearDown()81     public void tearDown() throws Exception {
82         removeUpdatedApexIfNecessary();
83     }
84 
85     @Test
testSmallModuleCanBeInstalled()86     public void testSmallModuleCanBeInstalled() throws Exception {
87         // This test only makes sense for devices where we can install the small module apex
88         assumeTrue(
89                 "Device has com.android.adservices APEX pre-installed",
90                 isSmallModuleUpdatePossible());
91 
92         runPhase("installSmallModulePendingReboot");
93         getDevice().reboot();
94 
95         assertWithMessage("AdServices APK is present").that(isAdServicesApkPresent()).isFalse();
96     }
97 
98     @Test
testSmallModuleCanBeInstalled_andThenUpdatedToFullModule()99     public void testSmallModuleCanBeInstalled_andThenUpdatedToFullModule() throws Exception {
100         // This test only makes sense for devices where we can install the small module apex
101         assumeTrue(
102                 "Device has com.android.adservices APEX pre-installed",
103                 isSmallModuleUpdatePossible());
104 
105         runPhase("installSmallModulePendingReboot");
106         getDevice().reboot();
107 
108         runPhase("installFullModulePendingReboot");
109         getDevice().reboot();
110 
111         assertWithMessage("AdServices APK is present").that(isAdServicesApkPresent()).isTrue();
112     }
113 
114     /** Verify services exported from AdServices APK are unavailable on small module. */
115     @Test
testVerifyAdServicesAreUnavailableOnSmallModule()116     public void testVerifyAdServicesAreUnavailableOnSmallModule() throws Exception {
117         if (isAdServicesApkPresent()) {
118             // Device does not have small module pre-installed. Prepare it.
119             runPhase("testVerifyAdServicesAreAvailable_preSmallModuleInstall");
120 
121             installSmallModule();
122         }
123         runPhase("testVerifyAdServicesAreUnavailable_postSmallModuleInstall");
124     }
125 
126     @Test
testLoadSdk()127     public void testLoadSdk() throws Exception {
128         if (isAdServicesApkPresent()) {
129             // Device does not have small module pre-installed and loadSdk should work
130             // Test that loadSdk works
131             runPhase("testLoadSdkWithAdServiceApk");
132 
133             installSmallModule();
134         }
135         // Test that loadSdk returns error when AdServices apk is not present
136         runPhase("testLoadSdkWithoutAdServiceApk");
137     }
138 
installSmallModule()139     private void installSmallModule() throws Exception {
140         runPhase("installSmallModulePendingReboot");
141         getDevice().reboot();
142     }
143 
isSmallModuleUpdatePossible()144     private boolean isSmallModuleUpdatePossible() throws Exception {
145         return getDevice().doesFileExist(SYSTEM_APEX_PATH);
146     }
147 
isAdServicesApkPresent()148     private boolean isAdServicesApkPresent() throws Exception {
149         // If the mounted module contains AdServices apk, it will get mounted as priv-app
150         // apk at PRIV_APP_DIR
151         return getDevice().isDirectory(PRIV_APP_DIR);
152     }
153 
removeUpdatedApexIfNecessary()154     private void removeUpdatedApexIfNecessary() throws Exception {
155         String[] children = getDevice().getChildren(ACTIVE_APEX_DIR);
156         boolean activeApexFound = false;
157         for (int i = 0; i < children.length; i++) {
158             String child = children[i];
159             if (child.startsWith(MODULE_NAME)) {
160                 activeApexFound = true;
161                 String childPath = ACTIVE_APEX_DIR + "/" + child;
162                 getDevice().deleteFile(childPath);
163                 getDevice().reboot();
164                 assertWithMessage("Module update removed").that(isAdServicesApkPresent()).isTrue();
165             }
166         }
167     }
168 }
169