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 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assume.assumeTrue; 22 23 import android.app.sdksandbox.hosttestutils.AwaitUtils; 24 import android.app.sdksandbox.hosttestutils.DeviceSupportHostUtils; 25 import android.app.sdksandbox.hosttestutils.SecondaryUserUtils; 26 27 import com.android.modules.utils.build.testing.DeviceSdkLevel; 28 import com.android.tradefed.device.DeviceNotAvailableException; 29 import com.android.tradefed.invoker.TestInformation; 30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 31 import com.android.tradefed.testtype.junit4.AfterClassWithInfo; 32 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 33 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo; 34 35 import org.junit.After; 36 import org.junit.Before; 37 import org.junit.Ignore; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 @RunWith(DeviceJUnit4ClassRunner.class) 42 public final class SdkSandboxLifecycleHostTest extends BaseHostJUnit4Test { 43 44 private static final String APP_PACKAGE = "com.android.sdksandbox.app"; 45 private static final String APP_APK = "SdkSandboxTestApp.apk"; 46 private static final String APP_2_PACKAGE = "com.android.sdksandbox.app2"; 47 48 private static final String APP_SHARED_PACKAGE = "com.android.sdksandbox.shared.app1"; 49 private static final String APP_SHARED_ACTIVITY = "SdkSandboxTestSharedActivity"; 50 private static final String APP_SHARED_2_PACKAGE = "com.android.sdksandbox.shared.app2"; 51 52 private static final String APP_ACTIVITY = "SdkSandboxTestActivity"; 53 private static final String APP_2_ACTIVITY = "SdkSandboxTestActivity2"; 54 private static final String APP_2_EMPTY_ACTIVITY = "SdkSandboxEmptyActivity"; 55 56 private static final String CODE_APK = "TestCodeProvider.apk"; 57 private static final String CODE_APK_2 = "TestCodeProvider2.apk"; 58 59 private static final String APP_2_PROCESS_NAME = "com.android.sdksandbox.processname"; 60 private static final String APP_2_PROCESS_NAME_2 = "com.android.sdksandbox.emptyactivity"; 61 private static final String SANDBOX_2_PROCESS_NAME = APP_2_PROCESS_NAME 62 + "_sdk_sandbox"; 63 /** 64 * process name for app1 is not defined and it takes the package name by default 65 */ 66 private static final String SANDBOX_1_PROCESS_NAME = APP_PACKAGE + "_sdk_sandbox"; 67 68 private static final String SANDBOX_SHARED_1_PROCESS_NAME = APP_SHARED_PACKAGE + "_sdk_sandbox"; 69 private static final String SANDBOX_SHARED_2_PROCESS_NAME = 70 APP_SHARED_2_PACKAGE + "_sdk_sandbox"; 71 72 private final SecondaryUserUtils mUserUtils = new SecondaryUserUtils(this); 73 private final DeviceSupportHostUtils mDeviceSupportUtils = new DeviceSupportHostUtils(this); 74 75 private DeviceSdkLevel mDeviceSdkLevel; 76 77 /** Root device for all tests. */ 78 @BeforeClassWithInfo beforeClassWithDevice(TestInformation testInfo)79 public static void beforeClassWithDevice(TestInformation testInfo) throws Exception { 80 assertThat(testInfo.getDevice().enableAdbRoot()).isTrue(); 81 } 82 83 /** UnRoot device after all tests. */ 84 @AfterClassWithInfo afterClassWithDevice(TestInformation testInfo)85 public static void afterClassWithDevice(TestInformation testInfo) throws Exception { 86 testInfo.getDevice().disableAdbRoot(); 87 } 88 89 @Before setUp()90 public void setUp() throws Exception { 91 assumeTrue("Device supports SdkSandbox", mDeviceSupportUtils.isSdkSandboxSupported()); 92 93 assertThat(getBuild()).isNotNull(); 94 assertThat(getDevice()).isNotNull(); 95 96 mDeviceSdkLevel = new DeviceSdkLevel(getDevice()); 97 98 if (!getDevice().isPackageInstalled(APP_PACKAGE)) { 99 installPackage(APP_APK); 100 } 101 } 102 103 @After tearDown()104 public void tearDown() throws Exception { 105 mUserUtils.removeSecondaryUserIfNecessary(); 106 cleanUpAppAndSandboxProcesses(); 107 } 108 109 @Test testSdkSandboxIsDestroyedOnAppDestroy()110 public void testSdkSandboxIsDestroyedOnAppDestroy() throws Exception { 111 startActivity(APP_PACKAGE, APP_ACTIVITY); 112 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 113 assertThat(processDump).contains(APP_PACKAGE + '\n'); 114 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 115 116 killApp(APP_PACKAGE); 117 waitForProcessDeath(SANDBOX_1_PROCESS_NAME); 118 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 119 assertThat(processDump).doesNotContain(APP_PACKAGE + '\n'); 120 assertThat(processDump).doesNotContain(SANDBOX_1_PROCESS_NAME); 121 122 // Wait 5 seconds to ensure that the sandbox has not restarted dying. 123 Thread.sleep(5000); 124 waitForProcessDeath(SANDBOX_1_PROCESS_NAME); 125 } 126 127 @Test testSdkSandboxIsCreatedPerApp()128 public void testSdkSandboxIsCreatedPerApp() throws Exception { 129 startActivity(APP_PACKAGE, APP_ACTIVITY); 130 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 131 assertThat(processDump).contains(APP_PACKAGE + '\n'); 132 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 133 134 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 135 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 136 assertThat(processDump).contains(APP_2_PROCESS_NAME + '\n'); 137 assertThat(processDump).contains(SANDBOX_2_PROCESS_NAME); 138 assertThat(processDump).contains(APP_PACKAGE + '\n'); 139 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 140 141 killApp(APP_2_PACKAGE); 142 // Wait a bit to allow sandbox death 143 waitForProcessDeath(SANDBOX_2_PROCESS_NAME); 144 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 145 assertThat(processDump).doesNotContain(APP_2_PROCESS_NAME + '\n'); 146 assertThat(processDump).doesNotContain(SANDBOX_2_PROCESS_NAME); 147 assertThat(processDump).contains(APP_PACKAGE + '\n'); 148 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 149 } 150 151 @Test testSdkSandboxIsKilledOnAppUninstall()152 public void testSdkSandboxIsKilledOnAppUninstall() throws Exception { 153 startActivity(APP_PACKAGE, APP_ACTIVITY); 154 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 155 assertThat(processDump).contains(APP_PACKAGE + '\n'); 156 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 157 158 uninstallPackage(APP_PACKAGE); 159 waitForProcessDeath(SANDBOX_1_PROCESS_NAME); 160 // Should no longer see app/sdk sandbox running 161 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 162 assertThat(processDump).doesNotContain(APP_PACKAGE + '\n'); 163 assertThat(processDump).doesNotContain(SANDBOX_1_PROCESS_NAME); 164 } 165 166 @Ignore("b/275299487") 167 @Test testSandboxIsCreatedPerUser()168 public void testSandboxIsCreatedPerUser() throws Exception { 169 assumeTrue(getDevice().isMultiUserSupported()); 170 171 int secondaryUserId = mUserUtils.createAndStartSecondaryUser(); 172 installPackageAsUser(APP_APK, false, secondaryUserId); 173 174 // Start app for the primary user 175 startActivity(APP_PACKAGE, APP_ACTIVITY); 176 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 177 assertThat(processDump).contains(APP_PACKAGE + '\n'); 178 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 179 180 mUserUtils.switchToSecondaryUser(); 181 182 // Should still see an app/sdk sandbox running. 183 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 184 assertThat(processDump).contains(APP_PACKAGE + '\n'); 185 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 186 187 // Start the app for the secondary user. 188 startActivity(APP_PACKAGE, APP_ACTIVITY); 189 // There should be two instances of app and sandbox processes - one for each user. 190 assertThat(getProcessOccurrenceCount(APP_PACKAGE + '\n')).isEqualTo(2); 191 assertThat(getProcessOccurrenceCount(SANDBOX_1_PROCESS_NAME)).isEqualTo(2); 192 193 // Kill the app process for the secondary user. 194 killApp(APP_PACKAGE + '\n'); 195 // There should be one instance of app and sandbox process after kill 196 assertThat(getProcessOccurrenceCount(APP_PACKAGE + '\n')).isEqualTo(1); 197 assertThat(getProcessOccurrenceCount(SANDBOX_1_PROCESS_NAME)).isEqualTo(1); 198 } 199 200 @Test testSdkSandboxIsKilledOnLoadedSdkUpdate()201 public void testSdkSandboxIsKilledOnLoadedSdkUpdate() throws Exception { 202 startActivity(APP_PACKAGE, APP_ACTIVITY); 203 204 // Should see app/sdk sandbox running 205 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 206 assertThat(processDump).contains(APP_PACKAGE + '\n'); 207 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 208 209 // Update package loaded by app 210 installPackage(CODE_APK, "-d"); 211 212 // SDK sandbox should be killed 213 waitForProcessDeath(SANDBOX_1_PROCESS_NAME); 214 } 215 216 @Test testSdkSandboxIsKilledForNonLoadedSdkUpdate()217 public void testSdkSandboxIsKilledForNonLoadedSdkUpdate() throws Exception { 218 // Have the app load the first SDK. 219 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 220 221 // Should see app/sdk sandbox running 222 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 223 assertThat(processDump).contains(APP_2_PROCESS_NAME + '\n'); 224 assertThat(processDump).contains(SANDBOX_2_PROCESS_NAME); 225 226 // Update package consumed by the app, but not loaded into the sandbox. 227 installPackage(CODE_APK_2, "-d"); 228 229 // SDK sandbox should be killed 230 waitForProcessDeath(SANDBOX_2_PROCESS_NAME); 231 } 232 233 @Test testAppsWithSharedUidCanLoadSameSdk()234 public void testAppsWithSharedUidCanLoadSameSdk() throws Exception { 235 startActivity(APP_SHARED_PACKAGE, APP_SHARED_ACTIVITY); 236 assertThat(runDeviceTests(APP_SHARED_2_PACKAGE, 237 "com.android.sdksandbox.shared.app2.SdkSandboxTestSharedApp2", 238 "testLoadSdkIsSuccessful")).isTrue(); 239 } 240 241 @Test testAppsWithSharedUid_OneAppDies()242 public void testAppsWithSharedUid_OneAppDies() throws Exception { 243 startActivity(APP_SHARED_PACKAGE, APP_SHARED_ACTIVITY); 244 assertThat(runDeviceTests(APP_SHARED_2_PACKAGE, 245 "com.android.sdksandbox.shared.app2.SdkSandboxTestSharedApp2", 246 "testLoadSdkIsSuccessful")).isTrue(); 247 248 // APP_SHARED_2_PACKAGE dies after running device-side tests. 249 waitForProcessDeath(SANDBOX_SHARED_2_PROCESS_NAME); 250 251 // For U+, the other sandbox should still be alive. 252 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 253 assertThat(processDump).contains(SANDBOX_SHARED_1_PROCESS_NAME); 254 } 255 256 @Test testAppOwnedSdkSandboxInterfaceRemoval_AppDies()257 public void testAppOwnedSdkSandboxInterfaceRemoval_AppDies() throws Exception { 258 startActivity(APP_SHARED_PACKAGE, APP_SHARED_ACTIVITY); 259 assertThat( 260 runDeviceTests( 261 APP_SHARED_2_PACKAGE, 262 "com.android.sdksandbox.shared.app2.SdkSandboxTestSharedApp2", 263 "testRegisterAppOwedSdkSandboxInterfacesBeforeAppDeath")) 264 .isTrue(); 265 266 // APP_SHARED_2_PACKAGE dies after running device-side tests. 267 waitForProcessDeath(SANDBOX_SHARED_2_PROCESS_NAME); 268 assertThat( 269 runDeviceTests( 270 APP_SHARED_2_PACKAGE, 271 "com.android.sdksandbox.shared.app2.SdkSandboxTestSharedApp2", 272 "testGetAppOwedSdkSandboxInterfacesOnAppDeath")) 273 .isTrue(); 274 } 275 276 @Test testSandboxIsKilledWhenKillswitchEnabled()277 public void testSandboxIsKilledWhenKillswitchEnabled() throws Exception { 278 try { 279 getDevice() 280 .executeShellCommand("device_config put adservices disable_sdk_sandbox false"); 281 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 282 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 283 assertThat(processDump).contains(APP_2_PROCESS_NAME + '\n'); 284 assertThat(processDump).contains(SANDBOX_2_PROCESS_NAME); 285 286 getDevice() 287 .executeShellCommand("device_config put adservices disable_sdk_sandbox true"); 288 waitForProcessDeath(SANDBOX_2_PROCESS_NAME); 289 waitForProcessDeath(APP_2_PROCESS_NAME); 290 291 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 292 // In U+ the app should be killed when the sandbox is killed. 293 assertThat(processDump).doesNotContain(APP_2_PROCESS_NAME + '\n'); 294 assertThat(processDump).doesNotContain(SANDBOX_2_PROCESS_NAME); 295 } finally { 296 getDevice().executeShellCommand("cmd sdk_sandbox set-state --enabled"); 297 } 298 } 299 300 @Test testSpecificAppProcessIsKilledOnSandboxDeath()301 public void testSpecificAppProcessIsKilledOnSandboxDeath() throws Exception { 302 try { 303 getDevice() 304 .executeShellCommand("device_config put adservices disable_sdk_sandbox false"); 305 306 // Start two activities running in two different processes for the same app. One 307 // activity loads an SDK while the other does nothing. 308 startActivity(APP_2_PACKAGE, APP_2_EMPTY_ACTIVITY); 309 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 310 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 311 assertThat(processDump).contains(APP_2_PROCESS_NAME + '\n'); 312 assertThat(processDump).contains(APP_2_PROCESS_NAME_2 + '\n'); 313 assertThat(processDump).contains(SANDBOX_2_PROCESS_NAME); 314 315 final String initialAppProcessPid = getDevice().getProcessPid(APP_2_PROCESS_NAME); 316 317 // Kill the sandbox. 318 getDevice() 319 .executeShellCommand("device_config put adservices disable_sdk_sandbox true"); 320 waitForProcessDeath(SANDBOX_2_PROCESS_NAME); 321 try { 322 waitForProcessDeath(APP_2_PROCESS_NAME + '\n'); 323 } catch (Exception e) { 324 // If the app process has not died, it could have restarted as it was the top 325 // activity. Verify that it is not the same process by checking the PID. 326 final String finalAppProcessPid = getDevice().getProcessPid(APP_2_PROCESS_NAME); 327 assertThat(finalAppProcessPid).isNotEqualTo(initialAppProcessPid); 328 } 329 330 // Only the app process which loaded the SDK should die. The other app process should 331 // still be alive. 332 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 333 assertThat(processDump).doesNotContain(APP_2_PROCESS_NAME + '\n'); 334 assertThat(processDump).doesNotContain(SANDBOX_2_PROCESS_NAME); 335 assertThat(processDump).contains(APP_2_PROCESS_NAME_2 + '\n'); 336 337 } finally { 338 getDevice().executeShellCommand("cmd sdk_sandbox set-state --enabled"); 339 } 340 } 341 342 @Test testBackgroundingAppReducesSandboxPriority()343 public void testBackgroundingAppReducesSandboxPriority() throws Exception { 344 startActivity(APP_PACKAGE, APP_ACTIVITY); 345 346 // Should see app/sdk sandbox running 347 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 348 assertThat(processDump).contains(APP_PACKAGE + '\n'); 349 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 350 351 int sandboxOomScoreAdj1 = getOomScoreAdj(SANDBOX_1_PROCESS_NAME); 352 int appOomScoreAdj1 = getOomScoreAdj(APP_PACKAGE); 353 // Verify that the sandbox process has lower priority than the app process. 354 assertThat(sandboxOomScoreAdj1).isAtLeast(appOomScoreAdj1); 355 356 // Navigate to home screen to send both apps to the background. 357 getDevice().executeShellCommand("input keyevent KEYCODE_HOME"); 358 359 // Wait for app to be backgrounded and unbinding of sandbox to complete. 360 Thread.sleep(5000); 361 362 // Should see app/sdk sandbox running 363 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 364 assertThat(processDump).contains(APP_PACKAGE + '\n'); 365 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 366 367 int sandboxOomScoreAdj2 = getOomScoreAdj(SANDBOX_1_PROCESS_NAME); 368 int appOomScoreAdj2 = getOomScoreAdj(APP_PACKAGE); 369 // The higher the oom adj score, the lower the priority of the process. 370 assertThat(sandboxOomScoreAdj2).isGreaterThan(sandboxOomScoreAdj1); 371 assertThat(appOomScoreAdj2).isGreaterThan(appOomScoreAdj1); 372 373 if (mDeviceSdkLevel.isDeviceAtLeastV()) { 374 assertThat(sandboxOomScoreAdj2).isAtLeast(appOomScoreAdj2); 375 376 // Start other apps to try to reduce the priority of the app. 377 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 378 startActivity(APP_SHARED_PACKAGE, APP_SHARED_ACTIVITY); 379 Thread.sleep(2000); 380 381 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 382 assertThat(processDump).contains(APP_PACKAGE + '\n'); 383 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 384 385 int sandboxOomScoreAdj3 = getOomScoreAdj(SANDBOX_1_PROCESS_NAME); 386 int appOomScoreAdj3 = getOomScoreAdj(APP_PACKAGE); 387 assertThat(appOomScoreAdj3).isAtLeast(appOomScoreAdj2); 388 assertThat(sandboxOomScoreAdj3).isAtLeast(sandboxOomScoreAdj2); 389 assertThat(sandboxOomScoreAdj3).isAtLeast(appOomScoreAdj3); 390 } 391 } 392 393 @Test testSandboxReconnectionAfterDeath()394 public void testSandboxReconnectionAfterDeath() throws Exception { 395 startActivity(APP_PACKAGE, APP_ACTIVITY); 396 397 // Should see app/sdk sandbox running 398 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 399 assertThat(processDump).contains(APP_PACKAGE + '\n'); 400 assertThat(processDump).contains(SANDBOX_1_PROCESS_NAME); 401 402 String initialSandboxPid = getDevice().getProcessPid(SANDBOX_1_PROCESS_NAME); 403 getDevice().executeShellCommand("kill -9 " + initialSandboxPid); 404 405 Thread.sleep(5000); 406 407 processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 408 assertThat(processDump).contains(APP_PACKAGE + '\n'); 409 // The sandbox should not restart in U+. 410 assertThat(processDump).doesNotContain(SANDBOX_1_PROCESS_NAME); 411 } 412 413 @Ignore("b/310160187") 414 @Test testSdkSandboxProcessNameForSecondaryUser()415 public void testSdkSandboxProcessNameForSecondaryUser() throws Exception { 416 assumeTrue(getDevice().isMultiUserSupported()); 417 String appApk2 = "SdkSandboxTestApp2.apk"; 418 419 int secondaryUserId = mUserUtils.createAndStartSecondaryUser(); 420 mUserUtils.switchToSecondaryUser(); 421 installPackageAsUser(appApk2, false, secondaryUserId); 422 startActivity(APP_2_PACKAGE, APP_2_ACTIVITY); 423 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 424 assertThat(processDump).contains(APP_2_PROCESS_NAME + '\n'); 425 assertThat(processDump).contains(SANDBOX_2_PROCESS_NAME); 426 } 427 startActivity(String pkg, String activity)428 private void startActivity(String pkg, String activity) throws Exception { 429 getDevice() 430 .executeShellCommand( 431 String.format( 432 "am start -W -n %s/.%s --user %d", 433 pkg, activity, getDevice().getCurrentUser())); 434 435 // Check that the activity has started correctly by checking that its process has started. 436 // Depending on the test package configuration, the package may differ from the process 437 // name. 438 String expectedProcessName = pkg; 439 if (pkg.equals(APP_2_PACKAGE)) { 440 if (activity.equals(APP_2_ACTIVITY)) { 441 expectedProcessName = APP_2_PROCESS_NAME; 442 } else { 443 expectedProcessName = APP_2_PROCESS_NAME_2; 444 } 445 } 446 assertThat( 447 getDevice() 448 .executeShellCommand( 449 String.format("ps -A | grep %s", expectedProcessName))) 450 .isNotEmpty(); 451 } 452 killApp(String pkg)453 private void killApp(String pkg) throws Exception { 454 getDevice().executeShellCommand(String.format("am force-stop --user current %s", pkg)); 455 waitForProcessDeath(pkg + '\n'); 456 } 457 458 // Get the number of running processes with the given process name. getProcessOccurrenceCount(String processName)459 private int getProcessOccurrenceCount(String processName) throws Exception { 460 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 461 462 int count = 0; 463 int processOccurrenceIndex = processDump.indexOf(processName); 464 while (processOccurrenceIndex >= 0) { 465 count++; 466 processOccurrenceIndex = processDump.indexOf(processName, processOccurrenceIndex + 1); 467 } 468 return count; 469 } 470 cleanUpAppAndSandboxProcesses()471 private void cleanUpAppAndSandboxProcesses() throws Exception { 472 for (String pkg : 473 new String[] { 474 APP_PACKAGE, APP_2_PACKAGE, APP_SHARED_PACKAGE, APP_SHARED_2_PACKAGE 475 }) { 476 killApp(pkg); 477 } 478 479 // Ensure no sandbox is currently running 480 for (String sandbox : 481 new String[] { 482 SANDBOX_1_PROCESS_NAME, 483 SANDBOX_2_PROCESS_NAME, 484 SANDBOX_SHARED_1_PROCESS_NAME, 485 SANDBOX_SHARED_2_PROCESS_NAME 486 }) { 487 waitForProcessDeath(sandbox); 488 } 489 } 490 getOomScoreAdj(String processName)491 private int getOomScoreAdj(String processName) throws DeviceNotAvailableException { 492 String pid = getDevice().getProcessPid(processName); 493 String oomScoreAdj = 494 getDevice().executeShellCommand("cat /proc/" + pid + "/oom_score_adj").trim(); 495 return Integer.parseInt(oomScoreAdj); 496 } 497 waitForProcessDeath(String processName)498 private void waitForProcessDeath(String processName) throws Exception { 499 AwaitUtils.waitFor( 500 () -> { 501 String processDump = getDevice().executeAdbCommand("shell", "ps", "-A"); 502 return !processDump.contains(processName); 503 }, 504 "Process " + processName + " has not died."); 505 } 506 } 507