• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.tests.sdksandbox.host;
18 
19 
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import android.app.sdksandbox.hosttestutils.AwaitUtils;
23 import android.app.sdksandbox.hosttestutils.SdkSandboxDeviceSupportedHostRule;
24 
25 import com.android.tradefed.invoker.TestInformation;
26 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
27 import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
28 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
29 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
30 import com.android.tradefed.util.CommandResult;
31 import com.android.tradefed.util.CommandStatus;
32 
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 
39 import java.util.HashSet;
40 
41 @RunWith(DeviceJUnit4ClassRunner.class)
42 public final class SdkSandboxShellHostTest extends BaseHostJUnit4Test {
43 
44     @Rule(order = 0)
45     public final SdkSandboxDeviceSupportedHostRule deviceSupportRule =
46             new SdkSandboxDeviceSupportedHostRule(this);
47 
48     private static final String DEBUGGABLE_APP_PACKAGE = "com.android.sdksandbox.debuggable";
49     private static final String DEBUGGABLE_APP_ACTIVITY = "SdkSandboxTestDebuggableActivity";
50 
51     private static final String APP_PACKAGE = "com.android.sdksandbox.app";
52     private static final String APP_ACTIVITY = "SdkSandboxTestActivity";
53 
54     private static final String DEBUGGABLE_APP_SANDBOX_NAME = DEBUGGABLE_APP_PACKAGE
55       + "_sdk_sandbox";
56     private static final String APP_SANDBOX_NAME = APP_PACKAGE + "_sdk_sandbox";
57     private final HashSet<Integer> mOriginalUsers = new HashSet<>();
58 
59     /** Root device for all tests. */
60     @BeforeClassWithInfo
beforeClassWithDevice(TestInformation testInfo)61     public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
62         assertThat(testInfo.getDevice().enableAdbRoot()).isTrue();
63     }
64 
65     /** UnRoot device after all tests. */
66     @AfterClassWithInfo
afterClassWithDevice(TestInformation testInfo)67     public static void afterClassWithDevice(TestInformation testInfo) throws Exception {
68         testInfo.getDevice().disableAdbRoot();
69     }
70 
71     @Before
setUp()72     public void setUp() throws Exception {
73         assertThat(getBuild()).isNotNull();
74         assertThat(getDevice()).isNotNull();
75 
76         // Ensure neither app is currently running
77         for (String pkg : new String[]{APP_PACKAGE, DEBUGGABLE_APP_PACKAGE}) {
78             clearProcess(pkg);
79             getDevice().executeShellV2Command(String.format("cmd deviceidle whitelist +%s", pkg));
80         }
81 
82         mOriginalUsers.addAll(getDevice().listUsers());
83     }
84 
85     @After
tearDown()86     public void tearDown() throws Exception {
87         for (Integer userId : getDevice().listUsers()) {
88             if (!mOriginalUsers.contains(userId)) {
89                 getDevice().removeUser(userId);
90             }
91         }
92         mOriginalUsers.clear();
93 
94         // Ensure all apps are not in allowlist.
95         for (String pkg : new String[] {APP_PACKAGE, DEBUGGABLE_APP_PACKAGE}) {
96             getDevice().executeShellV2Command(String.format("cmd deviceidle whitelist -%s", pkg));
97         }
98     }
99 
100     @Test
testStartAndStopSdkSandboxSucceedsForDebuggableApp()101     public void testStartAndStopSdkSandboxSucceedsForDebuggableApp() throws Exception {
102         CommandResult output = getDevice().executeShellV2Command(
103                 String.format("cmd sdk_sandbox start %s", DEBUGGABLE_APP_PACKAGE));
104         assertThat(output.getStderr()).isEmpty();
105         assertThat(output.getStatus()).isEqualTo(CommandStatus.SUCCESS);
106 
107         waitForProcessStart(DEBUGGABLE_APP_SANDBOX_NAME);
108 
109         output = getDevice().executeShellV2Command(
110                 String.format("cmd sdk_sandbox stop %s", DEBUGGABLE_APP_PACKAGE));
111         assertThat(output.getStderr()).isEmpty();
112         assertThat(output.getStatus()).isEqualTo(CommandStatus.SUCCESS);
113 
114         waitForProcessDeath(DEBUGGABLE_APP_SANDBOX_NAME);
115     }
116 
117     @Test
testStartSdkSandboxFailsForNonDebuggableApp()118     public void testStartSdkSandboxFailsForNonDebuggableApp() throws Exception {
119         CommandResult output = getDevice().executeShellV2Command(
120                 String.format("cmd sdk_sandbox start %s", APP_PACKAGE));
121         assertThat(output.getStatus()).isEqualTo(CommandStatus.FAILED);
122 
123         String processDump = getDevice().executeShellCommand("ps -A");
124         assertThat(processDump).doesNotContain(APP_SANDBOX_NAME);
125     }
126 
127     @Test
testStartSdkSandboxFailsForIncorrectUser()128     public void testStartSdkSandboxFailsForIncorrectUser() throws Exception {
129         int otherUserId = getDevice().createUser("TestUser_" + System.currentTimeMillis());
130         CommandResult output = getDevice().executeShellV2Command(
131                 String.format("cmd sdk_sandbox start --user %s %s",
132                         otherUserId, DEBUGGABLE_APP_PACKAGE));
133         assertThat(output.getStatus()).isEqualTo(CommandStatus.FAILED);
134 
135         String processDump = getDevice().executeShellCommand("ps -A");
136         assertThat(processDump).doesNotContain(DEBUGGABLE_APP_SANDBOX_NAME);
137     }
138 
139     @Test
testStopSdkSandboxSucceedsForRunningDebuggableApp()140     public void testStopSdkSandboxSucceedsForRunningDebuggableApp() throws Exception {
141         startActivity(DEBUGGABLE_APP_PACKAGE, DEBUGGABLE_APP_ACTIVITY);
142         waitForProcessStart(DEBUGGABLE_APP_SANDBOX_NAME);
143 
144         CommandResult output =
145                 getDevice()
146                         .executeShellV2Command(
147                                 String.format(
148                                         "cmd sdk_sandbox stop --user %s %s",
149                                         getDevice().getCurrentUser(), DEBUGGABLE_APP_PACKAGE));
150         assertThat(output.getStderr()).isEmpty();
151         assertThat(output.getStatus()).isEqualTo(CommandStatus.SUCCESS);
152 
153         waitForProcessDeath(DEBUGGABLE_APP_SANDBOX_NAME);
154     }
155 
156     @Test
testStartSdkSandboxFailsForInvalidPackage()157     public void testStartSdkSandboxFailsForInvalidPackage() throws Exception {
158         String invalidPackage = "com.android.sdksandbox.nonexistent";
159         CommandResult output = getDevice().executeShellV2Command(
160                 String.format("cmd sdk_sandbox start %s", invalidPackage));
161         assertThat(output.getStatus()).isEqualTo(CommandStatus.FAILED);
162     }
163 
164     @Test
testStopSdkSandboxFailsForNonDebuggableApp()165     public void testStopSdkSandboxFailsForNonDebuggableApp() throws Exception {
166         startActivity(APP_PACKAGE, APP_ACTIVITY);
167         waitForProcessStart(APP_SANDBOX_NAME);
168 
169         CommandResult output = getDevice().executeShellV2Command(
170                 String.format("cmd sdk_sandbox stop %s", APP_PACKAGE));
171         assertThat(output.getStatus()).isEqualTo(CommandStatus.FAILED);
172 
173         String processDump = getDevice().executeShellCommand("ps -A");
174         assertThat(processDump).contains(APP_SANDBOX_NAME);
175     }
176 
177     @Test
testStopSdkSandboxFailsForIncorrectUser()178     public void testStopSdkSandboxFailsForIncorrectUser() throws Exception {
179         startActivity(DEBUGGABLE_APP_PACKAGE, DEBUGGABLE_APP_ACTIVITY);
180         waitForProcessStart(DEBUGGABLE_APP_SANDBOX_NAME);
181 
182         int otherUserId = getDevice().createUser("TestUser_" + System.currentTimeMillis());
183         CommandResult output = getDevice().executeShellV2Command(String.format(
184                 "cmd sdk_sandbox stop --user %s %s", otherUserId, DEBUGGABLE_APP_PACKAGE));
185         assertThat(output.getStatus()).isEqualTo(CommandStatus.FAILED);
186 
187         String processDump = getDevice().executeShellCommand("ps -A");
188         assertThat(processDump).contains(DEBUGGABLE_APP_SANDBOX_NAME);
189     }
190 
clearProcess(String pkg)191     private void clearProcess(String pkg) throws Exception {
192         getDevice().executeShellCommand(String.format("pm clear %s", pkg));
193     }
194 
startActivity(String pkg, String activity)195     private void startActivity(String pkg, String activity) throws Exception {
196         getDevice().executeShellCommand(String.format("am start -W -n %s/.%s", pkg, activity));
197     }
198 
waitForProcessStart(String processName)199     private void waitForProcessStart(String processName) throws Exception {
200         AwaitUtils.waitFor(
201                 () -> {
202                     String processDump = getDevice().executeAdbCommand("shell", "ps", "-A");
203                     return processDump.contains(processName);
204                 },
205                 "Process " + processName + " has not started.");
206     }
207 
waitForProcessDeath(String processName)208     private void waitForProcessDeath(String processName) throws Exception {
209         AwaitUtils.waitFor(
210                 () -> {
211                     String processDump = getDevice().executeAdbCommand("shell", "ps", "-A");
212                     return !processDump.contains(processName);
213                 },
214                 "Process " + processName + " has not died.");
215     }
216 }
217