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