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