1 /* 2 * Copyright (C) 2008 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 package android.app.cts; 17 18 import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; 19 import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE; 20 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; 21 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; 22 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; 23 import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; 24 import static android.content.Intent.ACTION_MAIN; 25 import static android.content.Intent.CATEGORY_HOME; 26 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 27 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 28 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 29 import static android.content.pm.PackageManager.DONT_KILL_APP; 30 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; 31 32 import static org.junit.Assert.assertArrayEquals; 33 34 import android.app.Activity; 35 import android.app.ActivityManager; 36 import android.app.ActivityManager.RecentTaskInfo; 37 import android.app.ActivityManager.RunningAppProcessInfo; 38 import android.app.ActivityManager.RunningServiceInfo; 39 import android.app.ActivityManager.RunningTaskInfo; 40 import android.app.ActivityOptions; 41 import android.app.HomeVisibilityListener; 42 import android.app.Instrumentation; 43 import android.app.Instrumentation.ActivityMonitor; 44 import android.app.Instrumentation.ActivityResult; 45 import android.app.PendingIntent; 46 import android.app.TaskInfo; 47 import android.app.cts.android.app.cts.tools.WatchUidRunner; 48 import android.app.stubs.ActivityManagerRecentOneActivity; 49 import android.app.stubs.ActivityManagerRecentTwoActivity; 50 import android.app.stubs.CommandReceiver; 51 import android.app.stubs.LocalForegroundService; 52 import android.app.stubs.MockApplicationActivity; 53 import android.app.stubs.MockService; 54 import android.app.stubs.ScreenOnActivity; 55 import android.app.stubs.TestHomeActivity; 56 import android.app.stubs.TrimMemService; 57 import android.content.BroadcastReceiver; 58 import android.content.ComponentName; 59 import android.content.Context; 60 import android.content.Intent; 61 import android.content.IntentFilter; 62 import android.content.ServiceConnection; 63 import android.content.pm.ApplicationInfo; 64 import android.content.pm.ConfigurationInfo; 65 import android.content.pm.PackageManager; 66 import android.content.pm.ResolveInfo; 67 import android.content.res.Resources; 68 import android.os.Binder; 69 import android.os.Bundle; 70 import android.os.Handler; 71 import android.os.HandlerThread; 72 import android.os.IBinder; 73 import android.os.Message; 74 import android.os.Messenger; 75 import android.os.Parcel; 76 import android.os.RemoteException; 77 import android.os.SystemClock; 78 import android.platform.test.annotations.RestrictedBuildTest; 79 import android.provider.DeviceConfig; 80 import android.provider.Settings; 81 import android.server.wm.settings.SettingsSession; 82 import android.support.test.uiautomator.UiDevice; 83 import android.test.InstrumentationTestCase; 84 import android.util.ArrayMap; 85 import android.util.ArraySet; 86 import android.util.Log; 87 import android.util.Pair; 88 89 import androidx.test.filters.LargeTest; 90 91 import com.android.compatibility.common.util.AmMonitor; 92 import com.android.compatibility.common.util.ShellIdentityUtils; 93 import com.android.compatibility.common.util.SystemUtil; 94 95 import java.io.IOException; 96 import java.util.ArrayList; 97 import java.util.HashSet; 98 import java.util.List; 99 import java.util.Set; 100 import java.util.concurrent.CountDownLatch; 101 import java.util.concurrent.LinkedBlockingQueue; 102 import java.util.concurrent.TimeUnit; 103 import java.util.function.Consumer; 104 import java.util.function.Predicate; 105 import java.util.function.Supplier; 106 107 public class ActivityManagerTest extends InstrumentationTestCase { 108 private static final String TAG = ActivityManagerTest.class.getSimpleName(); 109 private static final String STUB_PACKAGE_NAME = "android.app.stubs"; 110 private static final int WAITFOR_MSEC = 5000; 111 private static final String SERVICE_NAME = "android.app.stubs.MockService"; 112 private static final int WAIT_TIME = 2000; 113 // A secondary test activity from another APK. 114 static final String SIMPLE_PACKAGE_NAME = "com.android.cts.launcherapps.simpleapp"; 115 static final String SIMPLE_ACTIVITY = ".SimpleActivity"; 116 static final String SIMPLE_ACTIVITY_IMMEDIATE_EXIT = ".SimpleActivityImmediateExit"; 117 static final String SIMPLE_ACTIVITY_CHAIN_EXIT = ".SimpleActivityChainExit"; 118 static final String SIMPLE_RECEIVER = ".SimpleReceiver"; 119 static final String SIMPLE_REMOTE_RECEIVER = ".SimpleRemoteReceiver"; 120 // The action sent back by the SIMPLE_APP after a restart. 121 private static final String ACTIVITY_LAUNCHED_ACTION = 122 "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION"; 123 // The action sent back by the SIMPLE_APP_IMMEDIATE_EXIT when it terminates. 124 private static final String ACTIVITY_EXIT_ACTION = 125 "com.android.cts.launchertests.LauncherAppsTests.EXIT_ACTION"; 126 // The action sent back by the SIMPLE_APP_CHAIN_EXIT when the task chain ends. 127 private static final String ACTIVITY_CHAIN_EXIT_ACTION = 128 "com.android.cts.launchertests.LauncherAppsTests.CHAIN_EXIT_ACTION"; 129 // The action sent to identify the time track info. 130 private static final String ACTIVITY_TIME_TRACK_INFO = "com.android.cts.TIME_TRACK_INFO"; 131 132 private static final String PACKAGE_NAME_APP1 = "com.android.app1"; 133 private static final String PACKAGE_NAME_APP2 = "com.android.app2"; 134 private static final String PACKAGE_NAME_APP3 = "com.android.app3"; 135 136 private static final String CANT_SAVE_STATE_1_PACKAGE_NAME = "com.android.test.cantsavestate1"; 137 private static final String ACTION_FINISH = "com.android.test.action.FINISH"; 138 139 private static final String MCC_TO_UPDATE = "987"; 140 private static final String MNC_TO_UPDATE = "654"; 141 private static final String SHELL_COMMAND_GET_CONFIG = "am get-config"; 142 private static final String SHELL_COMMAND_RESULT_CONFIG_NAME_MCC = "mcc"; 143 private static final String SHELL_COMMAND_RESULT_CONFIG_NAME_MNC = "mnc"; 144 145 // Return states of the ActivityReceiverFilter. 146 public static final int RESULT_PASS = 1; 147 public static final int RESULT_FAIL = 2; 148 public static final int RESULT_TIMEOUT = 3; 149 150 private Context mTargetContext; 151 private ActivityManager mActivityManager; 152 private PackageManager mPackageManager; 153 private Intent mIntent; 154 private List<Activity> mStartedActivityList; 155 private int mErrorProcessID; 156 private Instrumentation mInstrumentation; 157 private HomeActivitySession mTestHomeSession; 158 159 @Override setUp()160 protected void setUp() throws Exception { 161 super.setUp(); 162 mInstrumentation = getInstrumentation(); 163 mTargetContext = mInstrumentation.getTargetContext(); 164 mActivityManager = (ActivityManager) mInstrumentation.getContext() 165 .getSystemService(Context.ACTIVITY_SERVICE); 166 mPackageManager = mInstrumentation.getContext().getPackageManager(); 167 mStartedActivityList = new ArrayList<Activity>(); 168 mErrorProcessID = -1; 169 startSubActivity(ScreenOnActivity.class); 170 } 171 172 @Override tearDown()173 protected void tearDown() throws Exception { 174 super.tearDown(); 175 if (mTestHomeSession != null) { 176 mTestHomeSession.close(); 177 } 178 if (mIntent != null) { 179 mInstrumentation.getContext().stopService(mIntent); 180 } 181 for (int i = 0; i < mStartedActivityList.size(); i++) { 182 mStartedActivityList.get(i).finish(); 183 } 184 if (mErrorProcessID != -1) { 185 android.os.Process.killProcess(mErrorProcessID); 186 } 187 } 188 testGetRecentTasks()189 public void testGetRecentTasks() throws Exception { 190 int maxNum = 0; 191 int flags = 0; 192 193 List<RecentTaskInfo> recentTaskList; 194 // Test parameter: maxNum is set to 0 195 recentTaskList = mActivityManager.getRecentTasks(maxNum, flags); 196 assertNotNull(recentTaskList); 197 assertTrue(recentTaskList.size() == 0); 198 // Test parameter: maxNum is set to 50 199 maxNum = 50; 200 recentTaskList = mActivityManager.getRecentTasks(maxNum, flags); 201 assertNotNull(recentTaskList); 202 // start recent1_activity. 203 startSubActivity(ActivityManagerRecentOneActivity.class); 204 Thread.sleep(WAIT_TIME); 205 // start recent2_activity 206 startSubActivity(ActivityManagerRecentTwoActivity.class); 207 Thread.sleep(WAIT_TIME); 208 /* 209 * assert both recent1_activity and recent2_activity exist in the recent 210 * tasks list. Moreover,the index of the recent2_activity is smaller 211 * than the index of recent1_activity 212 */ 213 recentTaskList = mActivityManager.getRecentTasks(maxNum, flags); 214 int indexRecentOne = getTaskInfoIndex(recentTaskList, 215 ActivityManagerRecentOneActivity.class); 216 int indexRecentTwo = getTaskInfoIndex(recentTaskList, 217 ActivityManagerRecentTwoActivity.class); 218 assertTrue(indexRecentOne != -1 && indexRecentTwo != -1); 219 assertTrue(indexRecentTwo < indexRecentOne); 220 221 try { 222 mActivityManager.getRecentTasks(-1, 0); 223 fail("Should throw IllegalArgumentException"); 224 } catch (IllegalArgumentException e) { 225 // expected exception 226 } 227 } 228 229 public void testGetRecentTasksLimitedToCurrentAPK() throws Exception { 230 int maxNum = 0; 231 int flags = 0; 232 233 // Check the number of tasks at this time. 234 List<RecentTaskInfo> recentTaskList; 235 recentTaskList = mActivityManager.getRecentTasks(maxNum, flags); 236 int numberOfEntriesFirstRun = recentTaskList.size(); 237 238 // Start another activity from another APK. 239 Intent intent = new Intent(Intent.ACTION_MAIN); 240 intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY); 241 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 242 ActivityReceiverFilter receiver = new ActivityReceiverFilter(ACTIVITY_LAUNCHED_ACTION); 243 mTargetContext.startActivity(intent); 244 245 // Make sure the activity has really started. 246 assertEquals(RESULT_PASS, receiver.waitForActivity()); 247 receiver.close(); 248 249 // There shouldn't be any more tasks in this list at this time. 250 recentTaskList = mActivityManager.getRecentTasks(maxNum, flags); 251 int numberOfEntriesSecondRun = recentTaskList.size(); 252 assertTrue(numberOfEntriesSecondRun == numberOfEntriesFirstRun); 253 254 // Tell the activity to finalize. 255 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 256 intent.putExtra("finish", true); 257 mTargetContext.startActivity(intent); 258 } 259 260 // The receiver filter needs to be instantiated with the command to filter for before calling 261 // startActivity. 262 private class ActivityReceiverFilter extends BroadcastReceiver { 263 // The activity we want to filter for. 264 private String mActivityToFilter; 265 private int result = RESULT_TIMEOUT; 266 public long mTimeUsed = 0; 267 private static final int TIMEOUT_IN_MS = 5000; 268 269 // Create the filter with the intent to look for. 270 public ActivityReceiverFilter(String activityToFilter) { 271 mActivityToFilter = activityToFilter; 272 IntentFilter filter = new IntentFilter(); 273 filter.addAction(mActivityToFilter); 274 mInstrumentation.getTargetContext().registerReceiver(this, filter); 275 } 276 277 // Turn off the filter. 278 public void close() { 279 mInstrumentation.getTargetContext().unregisterReceiver(this); 280 } 281 282 @Override 283 public void onReceive(Context context, Intent intent) { 284 if (intent.getAction().equals(mActivityToFilter)) { 285 synchronized(this) { 286 result = RESULT_PASS; 287 if (mActivityToFilter.equals(ACTIVITY_TIME_TRACK_INFO)) { 288 mTimeUsed = intent.getExtras().getLong( 289 ActivityOptions.EXTRA_USAGE_TIME_REPORT); 290 } 291 notifyAll(); 292 } 293 } 294 } 295 296 public int waitForActivity() { 297 synchronized(this) { 298 try { 299 wait(TIMEOUT_IN_MS); 300 } catch (InterruptedException e) { 301 } 302 } 303 return result; 304 } 305 } 306 307 private final <T extends Activity> void startSubActivity(Class<T> activityClass) { 308 final Instrumentation.ActivityResult result = new ActivityResult(0, new Intent()); 309 final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), result, false); 310 mInstrumentation.addMonitor(monitor); 311 launchActivity(STUB_PACKAGE_NAME, activityClass, null); 312 mStartedActivityList.add(monitor.waitForActivity()); 313 } 314 315 private <T extends TaskInfo, S extends Activity> int getTaskInfoIndex(List<T> taskList, 316 Class<S> activityClass) { 317 int i = 0; 318 for (TaskInfo ti : taskList) { 319 if (ti.baseActivity.getClassName().equals(activityClass.getName())) { 320 return i; 321 } 322 i++; 323 } 324 return -1; 325 } 326 327 public void testGetRunningTasks() { 328 // Test illegal parameter 329 List<RunningTaskInfo> runningTaskList; 330 runningTaskList = mActivityManager.getRunningTasks(-1); 331 assertTrue(runningTaskList.size() == 0); 332 333 runningTaskList = mActivityManager.getRunningTasks(0); 334 assertTrue(runningTaskList.size() == 0); 335 336 runningTaskList = mActivityManager.getRunningTasks(20); 337 int taskSize = runningTaskList.size(); 338 assertTrue(taskSize >= 0 && taskSize <= 20); 339 340 // start recent1_activity. 341 startSubActivity(ActivityManagerRecentOneActivity.class); 342 343 runningTaskList = mActivityManager.getRunningTasks(20); 344 345 // assert only recent1_activity exists and is visible. 346 int indexRecentOne = getTaskInfoIndex(runningTaskList, 347 ActivityManagerRecentOneActivity.class); 348 int indexRecentTwo = getTaskInfoIndex(runningTaskList, 349 ActivityManagerRecentTwoActivity.class); 350 assertTrue(indexRecentOne != -1 && indexRecentTwo == -1); 351 assertTrue(runningTaskList.get(indexRecentOne).isVisible()); 352 353 // start recent2_activity. 354 startSubActivity(ActivityManagerRecentTwoActivity.class); 355 356 /* 357 * assert both recent1_activity and recent2_activity exist in the 358 * running tasks list. Moreover,the index of the recent2_activity is 359 * smaller than the index of recent1_activity. 360 */ 361 runningTaskList = mActivityManager.getRunningTasks(20); 362 indexRecentOne = getTaskInfoIndex(runningTaskList, 363 ActivityManagerRecentOneActivity.class); 364 indexRecentTwo = getTaskInfoIndex(runningTaskList, 365 ActivityManagerRecentTwoActivity.class); 366 assertTrue(indexRecentOne != -1 && indexRecentTwo != -1); 367 assertTrue(indexRecentTwo < indexRecentOne); 368 369 // assert only recent2_activity is visible. 370 assertFalse(runningTaskList.get(indexRecentOne).isVisible()); 371 assertTrue(runningTaskList.get(indexRecentTwo).isVisible()); 372 } 373 374 public void testGetRunningServices() throws Exception { 375 // Test illegal parameter 376 List<RunningServiceInfo> runningServiceInfo; 377 runningServiceInfo = mActivityManager.getRunningServices(-1); 378 assertTrue(runningServiceInfo.isEmpty()); 379 380 runningServiceInfo = mActivityManager.getRunningServices(0); 381 assertTrue(runningServiceInfo.isEmpty()); 382 383 runningServiceInfo = mActivityManager.getRunningServices(5); 384 assertTrue(runningServiceInfo.size() <= 5); 385 386 Intent intent = new Intent(); 387 intent.setClass(mInstrumentation.getTargetContext(), MockService.class); 388 intent.putExtra(MockService.EXTRA_NO_STOP, true); 389 mInstrumentation.getTargetContext().startService(intent); 390 MockService.waitForStart(WAIT_TIME); 391 392 runningServiceInfo = mActivityManager.getRunningServices(Integer.MAX_VALUE); 393 boolean foundService = false; 394 for (RunningServiceInfo rs : runningServiceInfo) { 395 if (rs.service.getClassName().equals(SERVICE_NAME)) { 396 foundService = true; 397 break; 398 } 399 } 400 assertTrue(foundService); 401 MockService.prepareDestroy(); 402 mTargetContext.stopService(intent); 403 boolean destroyed = MockService.waitForDestroy(WAIT_TIME); 404 assertTrue(destroyed); 405 } 406 407 private void executeAndLogShellCommand(String cmd) throws IOException { 408 final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation); 409 final String output = uiDevice.executeShellCommand(cmd); 410 Log.d(TAG, "executed[" + cmd + "]; output[" + output.trim() + "]"); 411 } 412 413 private String executeShellCommand(String cmd) throws IOException { 414 final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation); 415 return uiDevice.executeShellCommand(cmd).trim(); 416 } 417 418 private void setForcedAppStandby(String packageName, boolean enabled) throws IOException { 419 final StringBuilder cmdBuilder = new StringBuilder("appops set ") 420 .append(packageName) 421 .append(" RUN_ANY_IN_BACKGROUND ") 422 .append(enabled ? "ignore" : "allow"); 423 executeAndLogShellCommand(cmdBuilder.toString()); 424 } 425 426 public void testIsBackgroundRestricted() throws IOException { 427 // This instrumentation runs in the target package's uid. 428 final Context targetContext = mInstrumentation.getTargetContext(); 429 final String targetPackage = targetContext.getPackageName(); 430 final ActivityManager am = targetContext.getSystemService(ActivityManager.class); 431 setForcedAppStandby(targetPackage, true); 432 assertTrue(am.isBackgroundRestricted()); 433 setForcedAppStandby(targetPackage, false); 434 assertFalse(am.isBackgroundRestricted()); 435 } 436 437 public void testGetMemoryInfo() { 438 ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); 439 mActivityManager.getMemoryInfo(outInfo); 440 assertTrue(outInfo.lowMemory == (outInfo.availMem <= outInfo.threshold)); 441 } 442 443 public void testGetRunningAppProcesses() throws Exception { 444 List<RunningAppProcessInfo> list = mActivityManager.getRunningAppProcesses(); 445 assertNotNull(list); 446 final String SYSTEM_PROCESS = "system"; 447 boolean hasSystemProcess = false; 448 // The package name is also the default name for the application process 449 final String TEST_PROCESS = STUB_PACKAGE_NAME; 450 boolean hasTestProcess = false; 451 for (RunningAppProcessInfo ra : list) { 452 if (ra.processName.equals(SYSTEM_PROCESS)) { 453 hasSystemProcess = true; 454 455 // Make sure the importance is a sane value. 456 assertTrue(ra.importance >= RunningAppProcessInfo.IMPORTANCE_FOREGROUND); 457 assertTrue(ra.importance < RunningAppProcessInfo.IMPORTANCE_GONE); 458 } else if (ra.processName.equals(TEST_PROCESS)) { 459 hasTestProcess = true; 460 } 461 } 462 463 // For security reasons the system process is not exposed. 464 assertFalse(hasSystemProcess); 465 assertTrue(hasTestProcess); 466 467 for (RunningAppProcessInfo ra : list) { 468 if (ra.processName.equals("android.app.stubs:remote")) { 469 fail("should be no process named android.app.stubs:remote"); 470 } 471 } 472 // start a new process 473 // XXX would be a lot cleaner to bind instead of start. 474 mIntent = new Intent("android.app.REMOTESERVICE"); 475 mIntent.setPackage("android.app.stubs"); 476 mInstrumentation.getTargetContext().startService(mIntent); 477 Thread.sleep(WAITFOR_MSEC); 478 479 List<RunningAppProcessInfo> listNew = mActivityManager.getRunningAppProcesses(); 480 mInstrumentation.getTargetContext().stopService(mIntent); 481 482 for (RunningAppProcessInfo ra : listNew) { 483 if (ra.processName.equals("android.app.stubs:remote")) { 484 return; 485 } 486 } 487 fail("android.app.stubs:remote process should be available"); 488 } 489 490 public void testGetMyMemoryState() { 491 final RunningAppProcessInfo ra = new RunningAppProcessInfo(); 492 ActivityManager.getMyMemoryState(ra); 493 494 assertEquals(android.os.Process.myUid(), ra.uid); 495 496 // When an instrumentation test is running, the importance is high. 497 assertEquals(RunningAppProcessInfo.IMPORTANCE_FOREGROUND, ra.importance); 498 } 499 500 public void testGetProcessInErrorState() throws Exception { 501 List<ActivityManager.ProcessErrorStateInfo> errList = null; 502 errList = mActivityManager.getProcessesInErrorState(); 503 } 504 505 public void testGetDeviceConfigurationInfo() { 506 ConfigurationInfo conInf = mActivityManager.getDeviceConfigurationInfo(); 507 assertNotNull(conInf); 508 } 509 510 public void testUpdateMccMncConfiguration() throws Exception { 511 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 512 Log.i(TAG, "testUpdateMccMncConfiguration skipped: no telephony available"); 513 return; 514 } 515 516 // Store the original mcc mnc to set back 517 String[] mccMncConfigOriginal = new String[2]; 518 // Store other configs to check they won't be affected 519 Set<String> otherConfigsOriginal = new HashSet<>(); 520 getMccMncConfigsAndOthers(mccMncConfigOriginal, otherConfigsOriginal); 521 522 String[] mccMncConfigToUpdate = new String[] {MCC_TO_UPDATE, MNC_TO_UPDATE}; 523 boolean success = ShellIdentityUtils.invokeMethodWithShellPermissions(mActivityManager, 524 (am) -> am.updateMccMncConfiguration(mccMncConfigToUpdate[0], 525 mccMncConfigToUpdate[1])); 526 527 if (success) { 528 String[] mccMncConfigUpdated = new String[2]; 529 Set<String> otherConfigsUpdated = new HashSet<>(); 530 getMccMncConfigsAndOthers(mccMncConfigUpdated, otherConfigsUpdated); 531 // Check the mcc mnc are updated as expected 532 assertArrayEquals(mccMncConfigToUpdate, mccMncConfigUpdated); 533 // Check other configs are not changed 534 assertEquals(otherConfigsOriginal, otherConfigsUpdated); 535 } 536 537 // Set mcc mnc configs back in the end of the test 538 ShellIdentityUtils.invokeMethodWithShellPermissions(mActivityManager, 539 (am) -> am.updateMccMncConfiguration(mccMncConfigOriginal[0], 540 mccMncConfigOriginal[1])); 541 } 542 543 private void getMccMncConfigsAndOthers(String[] mccMncConfigs, Set<String> otherConfigs) 544 throws Exception { 545 String[] configs = SystemUtil.runShellCommand( 546 mInstrumentation, SHELL_COMMAND_GET_CONFIG).split(" |\\-"); 547 for (String config : configs) { 548 if (config.startsWith(SHELL_COMMAND_RESULT_CONFIG_NAME_MCC)) { 549 mccMncConfigs[0] = config.substring( 550 SHELL_COMMAND_RESULT_CONFIG_NAME_MCC.length()); 551 } else if (config.startsWith(SHELL_COMMAND_RESULT_CONFIG_NAME_MNC)) { 552 mccMncConfigs[1] = config.substring( 553 SHELL_COMMAND_RESULT_CONFIG_NAME_MNC.length()); 554 } else { 555 otherConfigs.add(config); 556 } 557 } 558 } 559 560 /** 561 * Simple test for {@link ActivityManager#isUserAMonkey()} - verifies its false. 562 * 563 * TODO: test positive case 564 */ 565 public void testIsUserAMonkey() { 566 assertFalse(ActivityManager.isUserAMonkey()); 567 } 568 569 /** 570 * Verify that {@link ActivityManager#isRunningInTestHarness()} is false. 571 */ 572 @RestrictedBuildTest 573 public void testIsRunningInTestHarness() { 574 assertFalse("isRunningInTestHarness must be false in production builds", 575 ActivityManager.isRunningInTestHarness()); 576 } 577 578 /** 579 * Go back to the home screen since running applications can interfere with application 580 * lifetime tests. 581 */ 582 private void launchHome() throws Exception { 583 if (!noHomeScreen()) { 584 Intent intent = new Intent(Intent.ACTION_MAIN); 585 intent.addCategory(Intent.CATEGORY_HOME); 586 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 587 mTargetContext.startActivity(intent); 588 Thread.sleep(WAIT_TIME); 589 } 590 } 591 592 /** 593 * Gets the value of com.android.internal.R.bool.config_noHomeScreen. 594 * @return true if no home screen is supported, false otherwise. 595 */ 596 private boolean noHomeScreen() { 597 try { 598 return getInstrumentation().getContext().getResources().getBoolean( 599 Resources.getSystem().getIdentifier("config_noHomeScreen", "bool", "android")); 600 } catch (Resources.NotFoundException e) { 601 // Assume there's a home screen. 602 return false; 603 } 604 } 605 606 /** 607 * Verify that the TimeTrackingAPI works properly when starting and ending an activity. 608 */ 609 public void testTimeTrackingAPI_SimpleStartExit() throws Exception { 610 createManagedHomeActivitySession(); 611 launchHome(); 612 // Prepare to start an activity from another APK. 613 Intent intent = new Intent(Intent.ACTION_MAIN); 614 intent.setClassName(SIMPLE_PACKAGE_NAME, 615 SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_IMMEDIATE_EXIT); 616 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 617 618 // Prepare the time receiver action. 619 Context context = mInstrumentation.getTargetContext(); 620 ActivityOptions options = ActivityOptions.makeBasic(); 621 Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO); 622 options.requestUsageTimeReport(PendingIntent.getBroadcast(context, 0, receiveIntent, 623 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE)); 624 625 // The application finished tracker. 626 ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter(ACTIVITY_EXIT_ACTION); 627 628 // The filter for the time event. 629 ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO); 630 631 // Run the activity. 632 mTargetContext.startActivity(intent, options.toBundle()); 633 634 // Wait until it finishes and end the reciever then. 635 assertEquals(RESULT_PASS, appEndReceiver.waitForActivity()); 636 appEndReceiver.close(); 637 638 if (!noHomeScreen()) { 639 // At this time the timerReceiver should not fire, even though the activity has shut 640 // down, because we are back to the home screen. Going to the home screen does not 641 // qualify as the user leaving the activity's flow. The time tracking is considered 642 // complete only when the user switches to another activity that is not part of the 643 // tracked flow. 644 assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity()); 645 assertTrue(timeReceiver.mTimeUsed == 0); 646 } else { 647 // With platforms that have no home screen, focus is returned to something else that is 648 // considered a completion of the tracked activity flow, and hence time tracking is 649 // triggered. 650 assertEquals(RESULT_PASS, timeReceiver.waitForActivity()); 651 } 652 653 // Issuing now another activity will trigger the timing information release. 654 final Intent dummyIntent = new Intent(context, MockApplicationActivity.class); 655 dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 656 final Activity activity = mInstrumentation.startActivitySync(dummyIntent); 657 658 // Wait until it finishes and end the reciever then. 659 assertEquals(RESULT_PASS, timeReceiver.waitForActivity()); 660 timeReceiver.close(); 661 assertTrue(timeReceiver.mTimeUsed != 0); 662 } 663 664 public void testHomeVisibilityListener() throws Exception { 665 LinkedBlockingQueue<Boolean> currentHomeScreenVisibility = new LinkedBlockingQueue<>(2); 666 HomeVisibilityListener homeVisibilityListener = new HomeVisibilityListener() { 667 @Override 668 public void onHomeVisibilityChanged(boolean isHomeActivityVisible) { 669 currentHomeScreenVisibility.offer(isHomeActivityVisible); 670 } 671 }; 672 launchHome(); 673 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mActivityManager, 674 (am) -> am.addHomeVisibilityListener(Runnable::run, homeVisibilityListener)); 675 676 try { 677 // Make sure we got the first notification that the home screen is visible. 678 assertTrue(currentHomeScreenVisibility.poll(WAIT_TIME, TimeUnit.MILLISECONDS)); 679 // Launch a basic activity to obscure the home screen. 680 Intent intent = new Intent(Intent.ACTION_MAIN); 681 intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY); 682 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 683 mTargetContext.startActivity(intent); 684 685 // Make sure the observer reports the home screen as no longer visible 686 assertFalse(currentHomeScreenVisibility.poll(WAIT_TIME, TimeUnit.MILLISECONDS)); 687 } finally { 688 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mActivityManager, 689 (am) -> am.removeHomeVisibilityListener(homeVisibilityListener)); 690 } 691 } 692 693 /** 694 * Verify that the TimeTrackingAPI works properly when switching away from the monitored task. 695 */ testTimeTrackingAPI_SwitchAwayTriggers()696 public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception { 697 createManagedHomeActivitySession(); 698 launchHome(); 699 700 // Prepare to start an activity from another APK. 701 Intent intent = new Intent(Intent.ACTION_MAIN); 702 intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY); 703 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 704 705 // Prepare the time receiver action. 706 Context context = mInstrumentation.getTargetContext(); 707 ActivityOptions options = ActivityOptions.makeBasic(); 708 Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO); 709 options.requestUsageTimeReport(PendingIntent.getBroadcast(context, 0, receiveIntent, 710 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE)); 711 712 // The application started tracker. 713 ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter( 714 ACTIVITY_LAUNCHED_ACTION); 715 716 // The filter for the time event. 717 ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO); 718 719 // Run the activity. 720 mTargetContext.startActivity(intent, options.toBundle()); 721 722 // Wait until it finishes and end the reciever then. 723 assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity()); 724 appStartedReceiver.close(); 725 726 // At this time the timerReceiver should not fire since our app is running. 727 assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity()); 728 assertTrue(timeReceiver.mTimeUsed == 0); 729 730 // Starting now another activity will put ours into the back hence releasing the timing. 731 final Intent dummyIntent = new Intent(context, MockApplicationActivity.class); 732 dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 733 final Activity activity = mInstrumentation.startActivitySync(dummyIntent); 734 735 // Wait until it finishes and end the reciever then. 736 assertEquals(RESULT_PASS, timeReceiver.waitForActivity()); 737 timeReceiver.close(); 738 assertTrue(timeReceiver.mTimeUsed != 0); 739 } 740 741 /** 742 * Verify that the TimeTrackingAPI works properly when handling an activity chain gets started 743 * and ended. 744 */ testTimeTrackingAPI_ChainedActivityExit()745 public void testTimeTrackingAPI_ChainedActivityExit() throws Exception { 746 createManagedHomeActivitySession(); 747 launchHome(); 748 // Prepare to start an activity from another APK. 749 Intent intent = new Intent(Intent.ACTION_MAIN); 750 intent.setClassName(SIMPLE_PACKAGE_NAME, 751 SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY_CHAIN_EXIT); 752 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 753 754 // Prepare the time receiver action. 755 Context context = mInstrumentation.getTargetContext(); 756 ActivityOptions options = ActivityOptions.makeBasic(); 757 Intent receiveIntent = new Intent(ACTIVITY_TIME_TRACK_INFO); 758 options.requestUsageTimeReport(PendingIntent.getBroadcast(context, 0, receiveIntent, 759 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE)); 760 761 // The application finished tracker. 762 ActivityReceiverFilter appEndReceiver = new ActivityReceiverFilter( 763 ACTIVITY_CHAIN_EXIT_ACTION); 764 765 // The filter for the time event. 766 ActivityReceiverFilter timeReceiver = new ActivityReceiverFilter(ACTIVITY_TIME_TRACK_INFO); 767 768 // Run the activity. 769 mTargetContext.startActivity(intent, options.toBundle()); 770 771 // Wait until it finishes and end the reciever then. 772 assertEquals(RESULT_PASS, appEndReceiver.waitForActivity()); 773 appEndReceiver.close(); 774 775 if (!noHomeScreen()) { 776 // At this time the timerReceiver should not fire, even though the activity has shut 777 // down, because we are back to the home screen. Going to the home screen does not 778 // qualify as the user leaving the activity's flow. The time tracking is considered 779 // complete only when the user switches to another activity that is not part of the 780 // tracked flow. 781 assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity()); 782 assertTrue(timeReceiver.mTimeUsed == 0); 783 } else { 784 // With platforms that have no home screen, focus is returned to something else that is 785 // considered a completion of the tracked activity flow, and hence time tracking is 786 // triggered. 787 assertEquals(RESULT_PASS, timeReceiver.waitForActivity()); 788 } 789 790 // Issue another activity so that the timing information gets released. 791 final Intent dummyIntent = new Intent(context, MockApplicationActivity.class); 792 dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 793 final Activity activity = mInstrumentation.startActivitySync(dummyIntent); 794 795 // Wait until it finishes and end the reciever then. 796 assertEquals(RESULT_PASS, timeReceiver.waitForActivity()); 797 timeReceiver.close(); 798 assertTrue(timeReceiver.mTimeUsed != 0); 799 } 800 801 /** 802 * Verify that after force-stopping a package which has a foreground task contains multiple 803 * activities, the process of the package should not be alive (restarted). 804 */ testForceStopPackageWontRestartProcess()805 public void testForceStopPackageWontRestartProcess() throws Exception { 806 // Ensure that there are no remaining component records of the test app package. 807 SystemUtil.runWithShellPermissionIdentity( 808 () -> mActivityManager.forceStopPackage(SIMPLE_PACKAGE_NAME)); 809 ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter( 810 ACTIVITY_LAUNCHED_ACTION); 811 // Start an activity of another APK. 812 Intent intent = new Intent(); 813 intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY); 814 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 815 mTargetContext.startActivity(intent); 816 assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity()); 817 818 // Start a new activity in the same task. Here adds an action to make a different to intent 819 // filter comparison so another same activity will be created. 820 intent.setAction(Intent.ACTION_MAIN); 821 mTargetContext.startActivity(intent); 822 assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity()); 823 appStartedReceiver.close(); 824 825 // Wait for the first activity to stop so its ActivityRecord.haveState will be true. The 826 // condition is required to keep the activity record when its process is died. 827 Thread.sleep(WAIT_TIME); 828 829 // The package name is also the default name for the activity process. 830 final String testProcess = SIMPLE_PACKAGE_NAME; 831 Predicate<RunningAppProcessInfo> processNamePredicate = 832 runningApp -> testProcess.equals(runningApp.processName); 833 834 List<RunningAppProcessInfo> runningApps = SystemUtil.callWithShellPermissionIdentity( 835 () -> mActivityManager.getRunningAppProcesses()); 836 assertTrue("Process " + testProcess + " should be found in running process list", 837 runningApps.stream().anyMatch(processNamePredicate)); 838 839 runningApps = SystemUtil.callWithShellPermissionIdentity(() -> { 840 mActivityManager.forceStopPackage(SIMPLE_PACKAGE_NAME); 841 // Wait awhile (process starting may be asynchronous) to verify if the process is 842 // started again unexpectedly. 843 Thread.sleep(WAIT_TIME); 844 return mActivityManager.getRunningAppProcesses(); 845 }); 846 847 assertFalse("Process " + testProcess + " should not be alive after force-stop", 848 runningApps.stream().anyMatch(processNamePredicate)); 849 } 850 851 /** 852 * This test is to verify that devices are patched with the fix in b/119327603 for b/115384617. 853 */ testIsAppForegroundRemoved()854 public void testIsAppForegroundRemoved() throws ClassNotFoundException { 855 try { 856 Class.forName("android.app.IActivityManager").getDeclaredMethod( 857 "isAppForeground", int.class); 858 fail("IActivityManager.isAppForeground() API should not be available."); 859 } catch (NoSuchMethodException e) { 860 // Patched devices should throw this exception since isAppForeground is removed. 861 } 862 } 863 864 /** 865 * This test verifies the self-induced ANR by ActivityManager.appNotResponding(). 866 */ testAppNotResponding()867 public void testAppNotResponding() throws Exception { 868 // Setup the ANR monitor 869 AmMonitor monitor = new AmMonitor(mInstrumentation, 870 new String[]{AmMonitor.WAIT_FOR_CRASHED}); 871 872 // Now tell it goto ANR 873 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_SELF_INDUCED_ANR, 874 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 875 876 try { 877 878 // Verify we got the ANR 879 assertTrue(monitor.waitFor(AmMonitor.WAIT_FOR_EARLY_ANR, WAITFOR_MSEC)); 880 881 // Just kill the test app 882 monitor.sendCommand(AmMonitor.CMD_KILL); 883 } finally { 884 // clean up 885 monitor.finish(); 886 SystemUtil.runWithShellPermissionIdentity(() -> { 887 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 888 }); 889 } 890 } 891 892 /* 893 * Verifies the {@link android.app.ActivityManager#killProcessesWhenImperceptible}. 894 */ testKillingPidsOnImperceptible()895 public void testKillingPidsOnImperceptible() throws Exception { 896 // Start remote service process 897 final String remoteProcessName = STUB_PACKAGE_NAME + ":remote"; 898 Intent remoteIntent = new Intent("android.app.REMOTESERVICE"); 899 remoteIntent.setPackage(STUB_PACKAGE_NAME); 900 mTargetContext.startService(remoteIntent); 901 Thread.sleep(WAITFOR_MSEC); 902 903 RunningAppProcessInfo remote = getRunningAppProcessInfo(remoteProcessName); 904 assertNotNull(remote); 905 906 ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter( 907 ACTIVITY_LAUNCHED_ACTION); 908 boolean disabled = "0".equals(executeShellCommand("cmd deviceidle enabled light")); 909 try { 910 if (disabled) { 911 executeAndLogShellCommand("cmd deviceidle enable light"); 912 } 913 final Intent intent = new Intent(Intent.ACTION_MAIN); 914 intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY); 915 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 916 mTargetContext.startActivity(intent); 917 assertEquals(RESULT_PASS, appStartedReceiver.waitForActivity()); 918 919 RunningAppProcessInfo proc = getRunningAppProcessInfo(SIMPLE_PACKAGE_NAME); 920 assertNotNull(proc); 921 922 final String reason = "cts"; 923 924 try { 925 mActivityManager.killProcessesWhenImperceptible(new int[]{proc.pid}, reason); 926 fail("Shouldn't have the permission"); 927 } catch (SecurityException e) { 928 // expected 929 } 930 931 final long defaultWaitForKillTimeout = 5_000; 932 933 // Keep the device awake 934 toggleScreenOn(true); 935 936 // Kill the remote process 937 SystemUtil.runWithShellPermissionIdentity(() -> { 938 mActivityManager.killProcessesWhenImperceptible(new int[]{remote.pid}, reason); 939 }); 940 941 // Kill the activity process 942 SystemUtil.runWithShellPermissionIdentity(() -> { 943 mActivityManager.killProcessesWhenImperceptible(new int[]{proc.pid}, reason); 944 }); 945 946 // The processes should be still alive because device isn't in idle 947 assertFalse(waitUntilTrue(defaultWaitForKillTimeout, () -> isProcessGone( 948 remote.pid, remoteProcessName))); 949 assertFalse(waitUntilTrue(defaultWaitForKillTimeout, () -> isProcessGone( 950 proc.pid, SIMPLE_PACKAGE_NAME))); 951 952 // force device idle 953 toggleScreenOn(false); 954 triggerIdle(true); 955 956 // Now the remote process should have been killed. 957 assertTrue(waitUntilTrue(defaultWaitForKillTimeout, () -> isProcessGone( 958 remote.pid, remoteProcessName))); 959 960 // The activity process should be still alive because it's is on the top (perceptible) 961 assertFalse(waitUntilTrue(defaultWaitForKillTimeout, () -> isProcessGone( 962 proc.pid, SIMPLE_PACKAGE_NAME))); 963 964 triggerIdle(false); 965 // Toogle screen ON 966 toggleScreenOn(true); 967 968 // Now launch home 969 executeAndLogShellCommand("input keyevent KEYCODE_HOME"); 970 971 // force device idle again 972 toggleScreenOn(false); 973 triggerIdle(true); 974 975 // Now the activity process should be gone. 976 assertTrue(waitUntilTrue(defaultWaitForKillTimeout, () -> isProcessGone( 977 proc.pid, SIMPLE_PACKAGE_NAME))); 978 979 } finally { 980 // Clean up code 981 triggerIdle(false); 982 toggleScreenOn(true); 983 appStartedReceiver.close(); 984 mTargetContext.stopService(remoteIntent); 985 986 if (disabled) { 987 executeAndLogShellCommand("cmd deviceidle disable light"); 988 } 989 SystemUtil.runWithShellPermissionIdentity(() -> { 990 mActivityManager.forceStopPackage(SIMPLE_PACKAGE_NAME); 991 }); 992 } 993 } 994 995 /** 996 * Verifies the system will kill app's child processes if they are using excessive cpu 997 */ 998 @LargeTest testKillingAppChildProcess()999 public void testKillingAppChildProcess() throws Exception { 1000 final long powerCheckInterval = 5 * 1000; 1001 final long processGoneTimeout = powerCheckInterval * 4; 1002 final int waitForSec = 5 * 1000; 1003 final String activityManagerConstants = "activity_manager_constants"; 1004 1005 final SettingsSession<String> amSettings = new SettingsSession<>( 1006 Settings.Global.getUriFor(activityManagerConstants), 1007 Settings.Global::getString, Settings.Global::putString); 1008 1009 final ApplicationInfo ai = mTargetContext.getPackageManager() 1010 .getApplicationInfo(PACKAGE_NAME_APP1, 0); 1011 final WatchUidRunner watcher = new WatchUidRunner(mInstrumentation, ai.uid, waitForSec); 1012 1013 try { 1014 // Shorten the power check intervals 1015 amSettings.set("power_check_interval=" + powerCheckInterval); 1016 1017 // Make sure we could start activity from background 1018 SystemUtil.runShellCommand(mInstrumentation, 1019 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP1); 1020 1021 // Keep the device awake 1022 toggleScreenOn(true); 1023 1024 // Start an activity 1025 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1026 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1027 1028 watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1029 1030 // Spawn a light weight child process 1031 CountDownLatch startLatch = startChildProcessInPackage(PACKAGE_NAME_APP1, 1032 new String[] {"/system/bin/sh", "-c", "sleep 1000"}); 1033 1034 // Wait for the start of the child process 1035 assertTrue("Failed to spawn child process", 1036 startLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1037 1038 // Stop the activity 1039 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_STOP_ACTIVITY, 1040 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1041 1042 watcher.waitFor(WatchUidRunner.CMD_CACHED, null); 1043 1044 // Wait for the system to kill that light weight child (it won't happen actually) 1045 CountDownLatch stopLatch = initWaitingForChildProcessGone( 1046 PACKAGE_NAME_APP1, processGoneTimeout); 1047 1048 assertFalse("App's light weight child process shouldn't be gone", 1049 stopLatch.await(processGoneTimeout, TimeUnit.MILLISECONDS)); 1050 1051 // Now kill the light weight child 1052 stopLatch = stopChildProcess(PACKAGE_NAME_APP1, waitForSec); 1053 1054 assertTrue("Failed to kill app's light weight child process", 1055 stopLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1056 1057 // Start an activity again 1058 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1059 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1060 1061 watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1062 1063 // Spawn the cpu intensive child process 1064 startLatch = startChildProcessInPackage(PACKAGE_NAME_APP1, 1065 new String[] {"/system/bin/sh", "-c", "while true; do :; done"}); 1066 1067 // Wait for the start of the child process 1068 assertTrue("Failed to spawn child process", 1069 startLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1070 1071 // Stop the activity 1072 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_STOP_ACTIVITY, 1073 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1074 1075 watcher.waitFor(WatchUidRunner.CMD_CACHED, null); 1076 1077 // Wait for the system to kill that heavy child due to excessive cpu usage, 1078 // as well as the parent process. 1079 watcher.waitFor(WatchUidRunner.CMD_GONE, processGoneTimeout); 1080 1081 } finally { 1082 amSettings.close(); 1083 1084 SystemUtil.runShellCommand(mInstrumentation, 1085 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP1); 1086 1087 SystemUtil.runWithShellPermissionIdentity(() -> { 1088 // force stop test package, where the whole test process group will be killed. 1089 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 1090 }); 1091 1092 watcher.finish(); 1093 } 1094 } 1095 1096 1097 /** 1098 * Verifies the system will trim app's child processes if there are too many 1099 */ 1100 @LargeTest testTrimAppChildProcess()1101 public void testTrimAppChildProcess() throws Exception { 1102 final long powerCheckInterval = 5 * 1000; 1103 final long processGoneTimeout = powerCheckInterval * 4; 1104 final int waitForSec = 5 * 1000; 1105 final int maxPhantomProcessesNum = 2; 1106 final String namespaceActivityManager = "activity_manager"; 1107 final String activityManagerConstants = "activity_manager_constants"; 1108 final String maxPhantomProcesses = "max_phantom_processes"; 1109 1110 final SettingsSession<String> amSettings = new SettingsSession<>( 1111 Settings.Global.getUriFor(activityManagerConstants), 1112 Settings.Global::getString, Settings.Global::putString); 1113 final Bundle currentMax = new Bundle(); 1114 final String keyCurrent = "current"; 1115 1116 ApplicationInfo ai = mTargetContext.getPackageManager() 1117 .getApplicationInfo(PACKAGE_NAME_APP1, 0); 1118 final WatchUidRunner watcher1 = new WatchUidRunner(mInstrumentation, ai.uid, waitForSec); 1119 ai = mTargetContext.getPackageManager().getApplicationInfo(PACKAGE_NAME_APP2, 0); 1120 final WatchUidRunner watcher2 = new WatchUidRunner(mInstrumentation, ai.uid, waitForSec); 1121 ai = mTargetContext.getPackageManager().getApplicationInfo(PACKAGE_NAME_APP3, 0); 1122 final WatchUidRunner watcher3 = new WatchUidRunner(mInstrumentation, ai.uid, waitForSec); 1123 1124 try { 1125 // Shorten the power check intervals 1126 amSettings.set("power_check_interval=" + powerCheckInterval); 1127 1128 // Reduce the maximum phantom processes allowance 1129 SystemUtil.runWithShellPermissionIdentity(() -> { 1130 int current = DeviceConfig.getInt(namespaceActivityManager, 1131 maxPhantomProcesses, -1); 1132 currentMax.putInt(keyCurrent, current); 1133 DeviceConfig.setProperty(namespaceActivityManager, 1134 maxPhantomProcesses, 1135 Integer.toString(maxPhantomProcessesNum), false); 1136 }); 1137 1138 // Make sure we could start activity from background 1139 SystemUtil.runShellCommand(mInstrumentation, 1140 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP1); 1141 SystemUtil.runShellCommand(mInstrumentation, 1142 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP2); 1143 SystemUtil.runShellCommand(mInstrumentation, 1144 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP3); 1145 1146 // Keep the device awake 1147 toggleScreenOn(true); 1148 1149 // Start an activity 1150 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1151 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1152 1153 watcher1.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1154 1155 // Spawn a light weight child process 1156 CountDownLatch startLatch = startChildProcessInPackage(PACKAGE_NAME_APP1, 1157 new String[] {"/system/bin/sh", "-c", "sleep 1000"}); 1158 1159 // Wait for the start of the child process 1160 assertTrue("Failed to spawn child process", 1161 startLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1162 1163 // Start an activity in another package 1164 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1165 PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null); 1166 1167 watcher2.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1168 1169 // Spawn a light weight child process 1170 startLatch = startChildProcessInPackage(PACKAGE_NAME_APP2, 1171 new String[] {"/system/bin/sh", "-c", "sleep 1000"}); 1172 1173 // Wait for the start of the child process 1174 assertTrue("Failed to spawn child process", 1175 startLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1176 1177 // Finish the 1st activity 1178 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_STOP_ACTIVITY, 1179 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null); 1180 1181 watcher1.waitFor(WatchUidRunner.CMD_CACHED, null); 1182 1183 // Wait for the system to kill that light weight child (it won't happen actually) 1184 CountDownLatch stopLatch = initWaitingForChildProcessGone( 1185 PACKAGE_NAME_APP1, processGoneTimeout); 1186 1187 assertFalse("App's light weight child process shouldn't be gone", 1188 stopLatch.await(processGoneTimeout, TimeUnit.MILLISECONDS)); 1189 1190 // Sleep a while 1191 SystemClock.sleep(powerCheckInterval); 1192 1193 // Now start an activity in the 3rd party 1194 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1195 PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null); 1196 1197 watcher3.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1198 1199 // Spawn a light weight child process 1200 startLatch = startChildProcessInPackage(PACKAGE_NAME_APP3, 1201 new String[] {"/system/bin/sh", "-c", "sleep 1000"}); 1202 1203 // Wait for the start of the child process 1204 assertTrue("Failed to spawn child process", 1205 startLatch.await(waitForSec, TimeUnit.MILLISECONDS)); 1206 1207 // Now the 1st child process should have been gone. 1208 stopLatch = initWaitingForChildProcessGone( 1209 PACKAGE_NAME_APP1, processGoneTimeout); 1210 1211 assertTrue("1st App's child process should have been gone", 1212 stopLatch.await(processGoneTimeout, TimeUnit.MILLISECONDS)); 1213 1214 } finally { 1215 amSettings.close(); 1216 1217 SystemUtil.runWithShellPermissionIdentity(() -> { 1218 final int current = currentMax.getInt(keyCurrent); 1219 if (current < 0) { 1220 // Hm, DeviceConfig doesn't have an API to delete a property, 1221 // let's set it empty so the code will use the built-in default value. 1222 DeviceConfig.setProperty(namespaceActivityManager, 1223 maxPhantomProcesses, "", false); 1224 } else { 1225 DeviceConfig.setProperty(namespaceActivityManager, 1226 maxPhantomProcesses, Integer.toString(current), false); 1227 } 1228 }); 1229 1230 SystemUtil.runShellCommand(mInstrumentation, 1231 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP1); 1232 SystemUtil.runShellCommand(mInstrumentation, 1233 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP2); 1234 SystemUtil.runShellCommand(mInstrumentation, 1235 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP3); 1236 1237 SystemUtil.runWithShellPermissionIdentity(() -> { 1238 // force stop test package, where the whole test process group will be killed. 1239 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 1240 mActivityManager.forceStopPackage(PACKAGE_NAME_APP2); 1241 mActivityManager.forceStopPackage(PACKAGE_NAME_APP3); 1242 }); 1243 1244 watcher1.finish(); 1245 watcher2.finish(); 1246 watcher3.finish(); 1247 } 1248 } 1249 startChildProcessInPackage(String pkgName, String[] cmdline)1250 private CountDownLatch startChildProcessInPackage(String pkgName, String[] cmdline) { 1251 final CountDownLatch startLatch = new CountDownLatch(1); 1252 1253 final IBinder binder = new Binder() { 1254 @Override 1255 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 1256 throws RemoteException { 1257 switch (code) { 1258 case CommandReceiver.RESULT_CHILD_PROCESS_STARTED: 1259 startLatch.countDown(); 1260 return true; 1261 default: 1262 return false; 1263 } 1264 } 1265 }; 1266 final Bundle extras = new Bundle(); 1267 extras.putBinder(CommandReceiver.EXTRA_CALLBACK, binder); 1268 extras.putStringArray(CommandReceiver.EXTRA_CHILD_CMDLINE, cmdline); 1269 1270 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_CHILD_PROCESS, 1271 pkgName, pkgName, 0, extras); 1272 1273 return startLatch; 1274 } 1275 stopChildProcess(String pkgName, long timeout)1276 final CountDownLatch stopChildProcess(String pkgName, long timeout) { 1277 final CountDownLatch stopLatch = new CountDownLatch(1); 1278 1279 final IBinder binder = new Binder() { 1280 @Override 1281 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 1282 throws RemoteException { 1283 switch (code) { 1284 case CommandReceiver.RESULT_CHILD_PROCESS_STOPPED: 1285 stopLatch.countDown(); 1286 return true; 1287 default: 1288 return false; 1289 } 1290 } 1291 }; 1292 final Bundle extras = new Bundle(); 1293 extras.putBinder(CommandReceiver.EXTRA_CALLBACK, binder); 1294 extras.putLong(CommandReceiver.EXTRA_TIMEOUT, timeout); 1295 1296 CommandReceiver.sendCommand(mTargetContext, 1297 CommandReceiver.COMMAND_STOP_CHILD_PROCESS, pkgName, pkgName, 0, extras); 1298 1299 return stopLatch; 1300 } 1301 initWaitingForChildProcessGone(String pkgName, long timeout)1302 final CountDownLatch initWaitingForChildProcessGone(String pkgName, long timeout) { 1303 final CountDownLatch stopLatch = new CountDownLatch(1); 1304 1305 final IBinder binder = new Binder() { 1306 @Override 1307 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 1308 throws RemoteException { 1309 switch (code) { 1310 case CommandReceiver.RESULT_CHILD_PROCESS_GONE: 1311 stopLatch.countDown(); 1312 return true; 1313 default: 1314 return false; 1315 } 1316 } 1317 }; 1318 final Bundle extras = new Bundle(); 1319 extras.putBinder(CommandReceiver.EXTRA_CALLBACK, binder); 1320 extras.putLong(CommandReceiver.EXTRA_TIMEOUT, timeout); 1321 1322 CommandReceiver.sendCommand(mTargetContext, 1323 CommandReceiver.COMMAND_WAIT_FOR_CHILD_PROCESS_GONE, pkgName, pkgName, 0, extras); 1324 1325 return stopLatch; 1326 } 1327 testTrimMemActivityFg()1328 public void testTrimMemActivityFg() throws Exception { 1329 final int waitForSec = 5 * 1000; 1330 final ApplicationInfo ai1 = mTargetContext.getPackageManager() 1331 .getApplicationInfo(PACKAGE_NAME_APP1, 0); 1332 final WatchUidRunner watcher1 = new WatchUidRunner(mInstrumentation, ai1.uid, waitForSec); 1333 1334 final ApplicationInfo ai2 = mTargetContext.getPackageManager() 1335 .getApplicationInfo(PACKAGE_NAME_APP2, 0); 1336 final WatchUidRunner watcher2 = new WatchUidRunner(mInstrumentation, ai2.uid, waitForSec); 1337 1338 final ApplicationInfo ai3 = mTargetContext.getPackageManager() 1339 .getApplicationInfo(CANT_SAVE_STATE_1_PACKAGE_NAME, 0); 1340 final WatchUidRunner watcher3 = new WatchUidRunner(mInstrumentation, ai3.uid, waitForSec); 1341 1342 final CountDownLatch[] latchHolder = new CountDownLatch[1]; 1343 final int[] expectedLevel = new int[1]; 1344 final Bundle extras = initWaitingForTrimLevel(level -> { 1345 if (level == expectedLevel[0]) { 1346 latchHolder[0].countDown(); 1347 } 1348 }); 1349 try { 1350 // Make sure we could start activity from background 1351 SystemUtil.runShellCommand(mInstrumentation, 1352 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP1); 1353 1354 // Override the memory pressure level, force it staying at normal. 1355 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set NORMAL"); 1356 1357 // Keep the device awake 1358 toggleScreenOn(true); 1359 1360 latchHolder[0] = new CountDownLatch(1); 1361 expectedLevel[0] = TRIM_MEMORY_RUNNING_MODERATE; 1362 1363 // Start an activity 1364 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1365 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras); 1366 1367 watcher1.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1368 1369 // Force the memory pressure to moderate 1370 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set MODERATE"); 1371 assertTrue("Failed to wait for the trim memory event", 1372 latchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1373 1374 latchHolder[0] = new CountDownLatch(1); 1375 expectedLevel[0] = TRIM_MEMORY_RUNNING_LOW; 1376 // Force the memory pressure to low 1377 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set LOW"); 1378 assertTrue("Failed to wait for the trim memory event", 1379 latchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1380 1381 latchHolder[0] = new CountDownLatch(1); 1382 expectedLevel[0] = TRIM_MEMORY_RUNNING_CRITICAL; 1383 // Force the memory pressure to critical 1384 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set CRITICAL"); 1385 assertTrue("Failed to wait for the trim memory event", 1386 latchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1387 1388 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_SERVICE, 1389 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, LocalForegroundService.newCommand( 1390 LocalForegroundService.COMMAND_START_NO_FOREGROUND)); 1391 1392 // Reset the memory pressure override 1393 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor reset"); 1394 1395 latchHolder[0] = new CountDownLatch(1); 1396 expectedLevel[0] = TRIM_MEMORY_UI_HIDDEN; 1397 // Start another activity in package2 1398 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1399 PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null); 1400 watcher2.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1401 watcher1.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_SERVICE, null); 1402 assertTrue("Failed to wait for the trim memory event", 1403 latchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1404 1405 // Start the heavy weight activity 1406 final Intent intent = new Intent(); 1407 final CountDownLatch[] heavyLatchHolder = new CountDownLatch[1]; 1408 final Predicate[] testFunc = new Predicate[1]; 1409 1410 intent.setPackage(CANT_SAVE_STATE_1_PACKAGE_NAME); 1411 intent.setAction(Intent.ACTION_MAIN); 1412 intent.addCategory(Intent.CATEGORY_LAUNCHER); 1413 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1414 intent.putExtras(initWaitingForTrimLevel(level -> { 1415 if (testFunc[0].test(level)) { 1416 heavyLatchHolder[0].countDown(); 1417 } 1418 })); 1419 1420 mTargetContext.startActivity(intent); 1421 watcher3.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1422 1423 heavyLatchHolder[0] = new CountDownLatch(1); 1424 testFunc[0] = level -> TRIM_MEMORY_RUNNING_MODERATE <= (int) level 1425 && TRIM_MEMORY_RUNNING_CRITICAL >= (int) level; 1426 // Force the memory pressure to moderate 1427 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set MODERATE"); 1428 assertTrue("Failed to wait for the trim memory event", 1429 heavyLatchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1430 1431 // Now go home 1432 final Intent homeIntent = new Intent(); 1433 homeIntent.setAction(Intent.ACTION_MAIN); 1434 homeIntent.addCategory(Intent.CATEGORY_HOME); 1435 homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1436 1437 heavyLatchHolder[0] = new CountDownLatch(1); 1438 testFunc[0] = level -> TRIM_MEMORY_BACKGROUND == (int) level; 1439 mTargetContext.startActivity(homeIntent); 1440 assertTrue("Failed to wait for the trim memory event", 1441 heavyLatchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1442 1443 } finally { 1444 SystemUtil.runShellCommand(mInstrumentation, 1445 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP1); 1446 1447 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor reset"); 1448 1449 SystemUtil.runWithShellPermissionIdentity(() -> { 1450 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 1451 mActivityManager.forceStopPackage(PACKAGE_NAME_APP2); 1452 mActivityManager.forceStopPackage(CANT_SAVE_STATE_1_PACKAGE_NAME); 1453 }); 1454 1455 watcher1.finish(); 1456 watcher2.finish(); 1457 watcher3.finish(); 1458 } 1459 } 1460 testTrimMemActivityBg()1461 public void testTrimMemActivityBg() throws Exception { 1462 final int minLru = 8; 1463 final int waitForSec = 30 * 1000; 1464 final String prefix = "trimmem_"; 1465 final CountDownLatch[] latchHolder = new CountDownLatch[1]; 1466 final String pkgName = PACKAGE_NAME_APP1; 1467 final ArrayMap<String, Pair<int[], ServiceConnection>> procName2Level = new ArrayMap<>(); 1468 int startSeq = 0; 1469 1470 try { 1471 // Kill all background processes 1472 SystemUtil.runShellCommand(mInstrumentation, "am kill-all"); 1473 1474 // Override the memory pressure level, force it staying at normal. 1475 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set NORMAL"); 1476 1477 List<String> lru; 1478 // Start a new isolated service once a time, and then check the lru list 1479 do { 1480 final String instanceName = prefix + startSeq++; 1481 final int[] levelHolder = new int[1]; 1482 1483 // Spawn the new isolated service 1484 final ServiceConnection conn = TrimMemService.bindToTrimMemService( 1485 pkgName, instanceName, latchHolder, levelHolder, mTargetContext); 1486 1487 // Get the list of all cached apps 1488 lru = getCachedAppsLru(); 1489 assertTrue(lru.size() > 0); 1490 1491 for (int i = lru.size() - 1; i >= 0; i--) { 1492 String p = lru.get(i); 1493 if (p.indexOf(instanceName) != -1) { 1494 // This is the new one we just created 1495 procName2Level.put(p, new Pair<>(levelHolder, conn)); 1496 break; 1497 } 1498 } 1499 if (lru.size() < minLru) { 1500 continue; 1501 } 1502 if (lru.get(0).indexOf(pkgName) != -1) { 1503 // Okay now the very least recent used cached process is one of ours 1504 break; 1505 } else { 1506 // Hm, someone dropped below us in the between, let's kill it 1507 ArraySet<String> others = new ArraySet<>(); 1508 for (int i = 0, size = lru.size(); i < size; i++) { 1509 final String name = lru.get(i); 1510 if (name.indexOf(pkgName) != -1) { 1511 break; 1512 } 1513 others.add(name); 1514 } 1515 SystemUtil.runWithShellPermissionIdentity(() -> { 1516 final List<ActivityManager.RunningAppProcessInfo> procs = mActivityManager 1517 .getRunningAppProcesses(); 1518 for (ActivityManager.RunningAppProcessInfo info: procs) { 1519 if (info.importance 1520 == ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED) { 1521 if (others.contains(info.processName)) { 1522 mActivityManager.killBackgroundProcesses(info.pkgList[0]); 1523 } 1524 } 1525 } 1526 }); 1527 } 1528 } while (true); 1529 1530 // Remove all other processes 1531 for (int i = lru.size() - 1; i >= 0; i--) { 1532 if (lru.get(i).indexOf(pkgName) == -1) { 1533 lru.remove(i); 1534 } 1535 } 1536 1537 latchHolder[0] = new CountDownLatch(lru.size()); 1538 // Force the memory pressure to moderate 1539 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor set MODERATE"); 1540 assertTrue("Failed to wait for the trim memory event", 1541 latchHolder[0].await(waitForSec, TimeUnit.MILLISECONDS)); 1542 1543 // Verify the trim levels among the LRU 1544 int level = TRIM_MEMORY_COMPLETE; 1545 assertEquals(level, procName2Level.get(lru.get(0)).first[0]); 1546 for (int i = 1, size = lru.size(); i < size; i++) { 1547 int curLevel = procName2Level.get(lru.get(i)).first[0]; 1548 assertTrue(level >= curLevel); 1549 level = curLevel; 1550 } 1551 1552 // Cleanup: Unbind from them 1553 for (int i = procName2Level.size() - 1; i >= 0; i--) { 1554 mTargetContext.unbindService(procName2Level.valueAt(i).second); 1555 } 1556 } finally { 1557 SystemUtil.runShellCommand(mInstrumentation, "am memory-factor reset"); 1558 1559 SystemUtil.runWithShellPermissionIdentity(() -> { 1560 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 1561 }); 1562 } 1563 } 1564 testServiceDoneLRUPosition()1565 public void testServiceDoneLRUPosition() throws Exception { 1566 ApplicationInfo ai = mTargetContext.getPackageManager() 1567 .getApplicationInfo(PACKAGE_NAME_APP1, 0); 1568 final WatchUidRunner watcher1 = new WatchUidRunner(mInstrumentation, ai.uid, WAITFOR_MSEC); 1569 ai = mTargetContext.getPackageManager().getApplicationInfo(PACKAGE_NAME_APP2, 0); 1570 final WatchUidRunner watcher2 = new WatchUidRunner(mInstrumentation, ai.uid, WAITFOR_MSEC); 1571 ai = mTargetContext.getPackageManager().getApplicationInfo(PACKAGE_NAME_APP3, 0); 1572 final WatchUidRunner watcher3 = new WatchUidRunner(mInstrumentation, ai.uid, WAITFOR_MSEC); 1573 final HandlerThread handlerThread = new HandlerThread("worker"); 1574 final Messenger[] controllerHolder = new Messenger[1]; 1575 final CountDownLatch[] countDownLatchHolder = new CountDownLatch[1]; 1576 handlerThread.start(); 1577 final Messenger messenger = new Messenger(new Handler(handlerThread.getLooper(), msg -> { 1578 final Bundle bundle = (Bundle) msg.obj; 1579 final IBinder binder = bundle.getBinder(CommandReceiver.EXTRA_MESSENGER); 1580 if (binder != null) { 1581 controllerHolder[0] = new Messenger(binder); 1582 countDownLatchHolder[0].countDown(); 1583 } 1584 return true; 1585 })); 1586 1587 try { 1588 // Make sure we could start activity from background 1589 SystemUtil.runShellCommand(mInstrumentation, 1590 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP1); 1591 SystemUtil.runShellCommand(mInstrumentation, 1592 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP2); 1593 SystemUtil.runShellCommand(mInstrumentation, 1594 "cmd deviceidle whitelist +" + PACKAGE_NAME_APP3); 1595 1596 // Keep the device awake 1597 toggleScreenOn(true); 1598 1599 // Start a FGS in app1 1600 final Bundle extras = new Bundle(); 1601 countDownLatchHolder[0] = new CountDownLatch(1); 1602 extras.putBinder(CommandReceiver.EXTRA_MESSENGER, messenger.getBinder()); 1603 CommandReceiver.sendCommand(mTargetContext, 1604 CommandReceiver.COMMAND_START_FOREGROUND_SERVICE, 1605 PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, extras); 1606 1607 watcher1.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE, null); 1608 1609 assertTrue("Failed to get the controller interface", 1610 countDownLatchHolder[0].await(WAITFOR_MSEC, TimeUnit.MILLISECONDS)); 1611 1612 // Start an activity in another package 1613 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1614 PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null); 1615 1616 watcher2.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1617 1618 // Start another activity in another package 1619 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_START_ACTIVITY, 1620 PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null); 1621 1622 watcher3.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP, null); 1623 1624 // Stop both of these activities 1625 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_STOP_ACTIVITY, 1626 PACKAGE_NAME_APP2, PACKAGE_NAME_APP2, 0, null); 1627 watcher2.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY, null); 1628 CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_STOP_ACTIVITY, 1629 PACKAGE_NAME_APP3, PACKAGE_NAME_APP3, 0, null); 1630 watcher3.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY, null); 1631 1632 // Launch home so we'd have cleared these the above test activities from recents. 1633 launchHome(); 1634 1635 // Now stop the foreground service, we'd have to do via the controller interface 1636 final Message msg = Message.obtain(); 1637 try { 1638 msg.what = LocalForegroundService.COMMAND_STOP_SELF; 1639 controllerHolder[0].send(msg); 1640 } catch (RemoteException e) { 1641 fail("Unable to stop test package"); 1642 } 1643 msg.recycle(); 1644 watcher1.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY, null); 1645 1646 final List<String> lru = getCachedAppsLru(); 1647 1648 assertTrue("Failed to get cached app list", lru.size() > 0); 1649 final int app1LruPos = lru.indexOf(PACKAGE_NAME_APP1); 1650 final int app2LruPos = lru.indexOf(PACKAGE_NAME_APP2); 1651 final int app3LruPos = lru.indexOf(PACKAGE_NAME_APP3); 1652 if (app1LruPos != -1) { 1653 assertTrue(PACKAGE_NAME_APP1 + " should be newer than " + PACKAGE_NAME_APP2, 1654 app1LruPos > app2LruPos); 1655 assertTrue(PACKAGE_NAME_APP1 + " should be newer than " + PACKAGE_NAME_APP3, 1656 app1LruPos > app3LruPos); 1657 } else { 1658 assertEquals(PACKAGE_NAME_APP2 + " should have gone", -1, app2LruPos); 1659 assertEquals(PACKAGE_NAME_APP3 + " should have gone", -1, app3LruPos); 1660 } 1661 } finally { 1662 handlerThread.quitSafely(); 1663 1664 SystemUtil.runShellCommand(mInstrumentation, 1665 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP1); 1666 SystemUtil.runShellCommand(mInstrumentation, 1667 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP2); 1668 SystemUtil.runShellCommand(mInstrumentation, 1669 "cmd deviceidle whitelist -" + PACKAGE_NAME_APP3); 1670 1671 SystemUtil.runWithShellPermissionIdentity(() -> { 1672 // force stop test package, where the whole test process group will be killed. 1673 mActivityManager.forceStopPackage(PACKAGE_NAME_APP1); 1674 mActivityManager.forceStopPackage(PACKAGE_NAME_APP2); 1675 mActivityManager.forceStopPackage(PACKAGE_NAME_APP3); 1676 }); 1677 1678 watcher1.finish(); 1679 watcher2.finish(); 1680 watcher3.finish(); 1681 } 1682 } 1683 getCachedAppsLru()1684 private List<String> getCachedAppsLru() throws Exception { 1685 final List<String> lru = new ArrayList<>(); 1686 final String output = SystemUtil.runShellCommand(mInstrumentation, "dumpsys activity lru"); 1687 final String[] lines = output.split("\n"); 1688 for (String line: lines) { 1689 if (line == null || line.indexOf(" cch") == -1) { 1690 continue; 1691 } 1692 final int slash = line.lastIndexOf('/'); 1693 if (slash == -1) { 1694 continue; 1695 } 1696 line = line.substring(0, slash); 1697 final int space = line.lastIndexOf(' '); 1698 if (space == -1) { 1699 continue; 1700 } 1701 line = line.substring(space + 1); 1702 final int colon = line.indexOf(':'); 1703 if (colon == -1) { 1704 continue; 1705 } 1706 lru.add(0, line.substring(colon + 1)); 1707 } 1708 return lru; 1709 } 1710 initWaitingForTrimLevel(final Consumer<Integer> checker)1711 private Bundle initWaitingForTrimLevel(final Consumer<Integer> checker) { 1712 final IBinder binder = new Binder() { 1713 @Override 1714 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 1715 throws RemoteException { 1716 switch (code) { 1717 case IBinder.FIRST_CALL_TRANSACTION: 1718 final int level = data.readInt(); 1719 checker.accept(level); 1720 return true; 1721 default: 1722 return false; 1723 } 1724 } 1725 }; 1726 final Bundle extras = new Bundle(); 1727 extras.putBinder(CommandReceiver.EXTRA_CALLBACK, binder); 1728 return extras; 1729 } 1730 getRunningAppProcessInfo(String processName)1731 private RunningAppProcessInfo getRunningAppProcessInfo(String processName) { 1732 try { 1733 return SystemUtil.callWithShellPermissionIdentity(()-> { 1734 return mActivityManager.getRunningAppProcesses().stream().filter( 1735 (ra) -> processName.equals(ra.processName)).findFirst().orElse(null); 1736 }); 1737 } catch (Exception e) { 1738 } 1739 return null; 1740 } 1741 isProcessGone(int pid, String processName)1742 private boolean isProcessGone(int pid, String processName) { 1743 RunningAppProcessInfo info = getRunningAppProcessInfo(processName); 1744 return info == null || info.pid != pid; 1745 } 1746 1747 // Copied from DeviceStatesTest 1748 /** 1749 * Make sure the screen state. 1750 */ toggleScreenOn(final boolean screenon)1751 private void toggleScreenOn(final boolean screenon) throws Exception { 1752 if (screenon) { 1753 executeAndLogShellCommand("input keyevent KEYCODE_WAKEUP"); 1754 executeAndLogShellCommand("wm dismiss-keyguard"); 1755 } else { 1756 executeAndLogShellCommand("input keyevent KEYCODE_SLEEP"); 1757 } 1758 // Since the screen on/off intent is ordered, they will not be sent right now. 1759 SystemClock.sleep(2_000); 1760 } 1761 1762 /** 1763 * Simulated for idle, and then perform idle maintenance now. 1764 */ triggerIdle(boolean idle)1765 private void triggerIdle(boolean idle) throws Exception { 1766 if (idle) { 1767 executeAndLogShellCommand("cmd deviceidle force-idle light"); 1768 } else { 1769 executeAndLogShellCommand("cmd deviceidle unforce"); 1770 } 1771 // Wait a moment to let that happen before proceeding. 1772 SystemClock.sleep(2_000); 1773 } 1774 1775 /** 1776 * Return true if the given supplier says it's true 1777 */ waitUntilTrue(long maxWait, Supplier<Boolean> supplier)1778 private boolean waitUntilTrue(long maxWait, Supplier<Boolean> supplier) throws Exception { 1779 final long deadLine = SystemClock.uptimeMillis() + maxWait; 1780 boolean result = false; 1781 do { 1782 Thread.sleep(500); 1783 } while (!(result = supplier.get()) && SystemClock.uptimeMillis() < deadLine); 1784 return result; 1785 } 1786 createManagedHomeActivitySession()1787 private void createManagedHomeActivitySession() 1788 throws Exception { 1789 if (noHomeScreen()) return; 1790 ComponentName homeActivity = new ComponentName( 1791 STUB_PACKAGE_NAME, TestHomeActivity.class.getName()); 1792 mTestHomeSession = new HomeActivitySession(homeActivity); 1793 } 1794 1795 /** 1796 * HomeActivitySession is used to replace the default home component, so that you can use 1797 * your preferred home for testing within the session. The original default home will be 1798 * restored automatically afterward. 1799 */ 1800 private class HomeActivitySession { 1801 private PackageManager mPackageManager; 1802 private ComponentName mOrigHome; 1803 private ComponentName mSessionHome; 1804 HomeActivitySession(ComponentName sessionHome)1805 HomeActivitySession(ComponentName sessionHome) throws Exception { 1806 mSessionHome = sessionHome; 1807 mPackageManager = mInstrumentation.getContext().getPackageManager(); 1808 mOrigHome = getDefaultHomeComponent(); 1809 1810 SystemUtil.runWithShellPermissionIdentity( 1811 () -> mPackageManager.setComponentEnabledSetting(mSessionHome, 1812 COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP)); 1813 setDefaultHome(mSessionHome); 1814 } 1815 close()1816 public void close() throws Exception { 1817 SystemUtil.runWithShellPermissionIdentity( 1818 () -> mPackageManager.setComponentEnabledSetting(mSessionHome, 1819 COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP)); 1820 if (mOrigHome != null) { 1821 setDefaultHome(mOrigHome); 1822 mOrigHome = null; 1823 } 1824 } 1825 setDefaultHome(ComponentName componentName)1826 private void setDefaultHome(ComponentName componentName) throws Exception { 1827 executeShellCommand("cmd package set-home-activity --user " 1828 + android.os.Process.myUserHandle().getIdentifier() + " " 1829 + componentName.flattenToString()); 1830 } 1831 getDefaultHomeComponent()1832 private ComponentName getDefaultHomeComponent() { 1833 final Intent intent = new Intent(ACTION_MAIN); 1834 intent.addCategory(CATEGORY_HOME); 1835 intent.addFlags(FLAG_ACTIVITY_NEW_TASK); 1836 final ResolveInfo resolveInfo = mInstrumentation.getContext() 1837 .getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY); 1838 if (resolveInfo == null) { 1839 throw new AssertionError("Home activity not found"); 1840 } 1841 return new ComponentName(resolveInfo.activityInfo.packageName, 1842 resolveInfo.activityInfo.name); 1843 } 1844 } 1845 } 1846