1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import android.app.ActivityManager;
27 import android.app.ActivityManager.OnUidImportanceListener;
28 import android.app.ActivityManager.RecentTaskInfo;
29 import android.app.ActivityManager.RunningAppProcessInfo;
30 import android.app.IActivityManager;
31 import android.content.BroadcastReceiver;
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.ServiceConnection;
37 import android.content.pm.PackageManager;
38 import android.os.Binder;
39 import android.os.Bundle;
40 import android.os.DropBoxManager;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.IRemoteCallback;
44 import android.os.Looper;
45 import android.os.Message;
46 import android.os.Messenger;
47 import android.os.Parcel;
48 import android.os.RemoteException;
49 import android.os.SystemClock;
50 import android.os.UserHandle;
51 import android.platform.test.annotations.Presubmit;
52 import android.provider.DeviceConfig;
53 import android.provider.Settings;
54 import android.server.wm.settings.SettingsSession;
55 import android.text.TextUtils;
56 import android.util.KeyValueListParser;
57 import android.util.Log;
58 import android.util.Pair;
59 
60 import androidx.test.InstrumentationRegistry;
61 import androidx.test.filters.FlakyTest;
62 import androidx.test.filters.LargeTest;
63 import androidx.test.uiautomator.UiDevice;
64 
65 import org.junit.Before;
66 import org.junit.Ignore;
67 import org.junit.Test;
68 
69 import java.io.IOException;
70 import java.util.ArrayList;
71 import java.util.List;
72 import java.util.concurrent.CountDownLatch;
73 import java.util.concurrent.TimeUnit;
74 import java.util.regex.Matcher;
75 import java.util.regex.Pattern;
76 import java.util.stream.Collectors;
77 
78 /**
79  * Tests for {@link ActivityManager}.
80  *
81  * Build/Install/Run:
82  *  atest FrameworksServicesTests:ActivityManagerTest
83  */
84 @FlakyTest(detail = "Promote to presubmit if stable")
85 @Presubmit
86 public class ActivityManagerTest {
87     private static final String TAG = "ActivityManagerTest";
88 
89     private static final String TEST_APP1 = "com.android.servicestests.apps.simpleservicetestapp1";
90     private static final String TEST_APP2 = "com.android.servicestests.apps.simpleservicetestapp2";
91     private static final String TEST_APP3 = "com.android.servicestests.apps.simpleservicetestapp3";
92     private static final String TEST_CLASS =
93             "com.android.servicestests.apps.simpleservicetestapp.SimpleService";
94     private static final int TEST_LOOPS = 100;
95     private static final long AWAIT_TIMEOUT = 2000;
96     private static final long CHECK_INTERVAL = 100;
97 
98     private static final String TEST_FGS_CLASS =
99             "com.android.servicestests.apps.simpleservicetestapp.SimpleFgService";
100     private static final String ACTION_FGS_STATS_TEST =
101             "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
102     private static final String EXTRA_MESSENGER = "extra_messenger";
103     private static final String ACTION_RECEIVER_TEST =
104             "com.android.servicestests.apps.simpleservicetestapp.TEST";
105 
106     private static final String EXTRA_CALLBACK = "callback";
107     private static final String EXTRA_COMMAND = "command";
108     private static final String EXTRA_FLAGS = "flags";
109     private static final String EXTRA_TARGET_PACKAGE = "target_package";
110 
111     private static final int COMMAND_INVALID = 0;
112     private static final int COMMAND_EMPTY = 1;
113     private static final int COMMAND_BIND_SERVICE = 2;
114     private static final int COMMAND_UNBIND_SERVICE = 3;
115     private static final int COMMAND_STOP_SELF = 4;
116 
117     private static final String TEST_ISOLATED_CLASS =
118             "com.android.servicestests.apps.simpleservicetestapp.SimpleIsolatedService";
119 
120     private IActivityManager mService;
121     private IRemoteCallback mCallback;
122     private Context mContext;
123 
124     @Before
setUp()125     public void setUp() throws Exception {
126         mService = ActivityManager.getService();
127         mContext = InstrumentationRegistry.getTargetContext();
128     }
129 
130     @Test
testTaskIdsForRunningUsers()131     public void testTaskIdsForRunningUsers() throws RemoteException {
132         int[] runningUserIds = mService.getRunningUserIds();
133         assertThat(runningUserIds).isNotEmpty();
134         for (int userId : runningUserIds) {
135             testTaskIdsForUser(userId);
136         }
137     }
138 
testTaskIdsForUser(int userId)139     private void testTaskIdsForUser(int userId) throws RemoteException {
140         List<?> recentTasks = mService.getRecentTasks(100, 0, userId).getList();
141         if (recentTasks != null) {
142             for (Object elem : recentTasks) {
143                 assertThat(elem).isInstanceOf(RecentTaskInfo.class);
144                 RecentTaskInfo recentTask = (RecentTaskInfo) elem;
145                 int taskId = recentTask.taskId;
146                 assertEquals("The task id " + taskId + " should not belong to user " + userId,
147                              taskId / UserHandle.PER_USER_RANGE, userId);
148             }
149         }
150     }
151 
152     @Test
testServiceUnbindAndKilling()153     public void testServiceUnbindAndKilling() {
154         for (int i = TEST_LOOPS; i > 0; i--) {
155             runOnce(i);
156         }
157     }
158 
runOnce(long yieldDuration)159     private void runOnce(long yieldDuration) {
160         final PackageManager pm = mContext.getPackageManager();
161         int uid = 0;
162         try {
163             uid = pm.getPackageUid(TEST_APP1, 0);
164         } catch (PackageManager.NameNotFoundException e) {
165             throw new RuntimeException(e);
166         }
167 
168         Intent intent = new Intent();
169         intent.setClassName(TEST_APP1, TEST_CLASS);
170 
171         // Create a service connection with auto creation.
172         CountDownLatch latch = new CountDownLatch(1);
173         final MyServiceConnection autoConnection = new MyServiceConnection(latch);
174         mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE);
175         try {
176             assertTrue("Timeout to bind to service " + intent.getComponent(),
177                     latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
178         } catch (InterruptedException e) {
179             fail("Unable to bind to service " + intent.getComponent());
180         }
181 
182         // Create a service connection without any flags.
183         intent = new Intent();
184         intent.setClassName(TEST_APP1, TEST_CLASS);
185         latch = new CountDownLatch(1);
186         MyServiceConnection otherConnection = new MyServiceConnection(latch);
187         mContext.bindService(intent, otherConnection, 0);
188         try {
189             assertTrue("Timeout to bind to service " + intent.getComponent(),
190                     latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
191         } catch (InterruptedException e) {
192             fail("Unable to bind to service " + intent.getComponent());
193         }
194 
195         // Inform the remote process to kill itself
196         try {
197             mCallback.sendResult(null);
198             // It's basically a test for race condition, we expect the bringDownServiceLocked()
199             // would find out the hosting process is dead - to do this, technically we should
200             // do killing and unbinding simultaneously; but in reality, the killing would take
201             // a little while, before the signal really kills it; so we do it in the same thread,
202             // and even wait a while after sending killing signal.
203             Thread.sleep(yieldDuration);
204         } catch (RemoteException | InterruptedException e) {
205             fail("Unable to kill the process");
206         }
207         // Now unbind that auto connection, this should be equivalent to stopService
208         mContext.unbindService(autoConnection);
209 
210         // Now we don't expect the system_server crashes.
211 
212         // Wait for the target process dies
213         long total = 0;
214         for (; total < AWAIT_TIMEOUT; total += CHECK_INTERVAL) {
215             try {
216                 if (!targetPackageIsRunning(mContext, uid)) {
217                     break;
218                 }
219                 Thread.sleep(CHECK_INTERVAL);
220             } catch (InterruptedException e) {
221             }
222         }
223         assertTrue("Timeout to wait for the target package dies", total < AWAIT_TIMEOUT);
224         mCallback = null;
225     }
226 
targetPackageIsRunning(Context context, int uid)227     private boolean targetPackageIsRunning(Context context, int uid) {
228         final String result = runShellCommand(
229                 String.format("cmd activity get-uid-state %d", uid));
230         return !result.contains("(NONEXISTENT)");
231     }
232 
runShellCommand(String cmd)233     private static String runShellCommand(String cmd) {
234         try {
235             return UiDevice.getInstance(
236                     InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
237         } catch (IOException e) {
238             throw new RuntimeException(e);
239         }
240     }
241 
242     private class MyServiceConnection implements ServiceConnection {
243         private CountDownLatch mLatch;
244 
MyServiceConnection(CountDownLatch latch)245         MyServiceConnection(CountDownLatch latch) {
246             this.mLatch = latch;
247         }
248 
249         @Override
onServiceConnected(ComponentName name, IBinder service)250         public void onServiceConnected(ComponentName name, IBinder service) {
251             mCallback = IRemoteCallback.Stub.asInterface(service);
252             mLatch.countDown();
253         }
254 
255         @Override
onServiceDisconnected(ComponentName name)256         public void onServiceDisconnected(ComponentName name) {
257         }
258     }
259 
260     /**
261      * Note: This test actually only works in eng build. It'll always pass
262      * in user and userdebug build, because the expected exception won't be
263      * thrown in those builds.
264      */
265     @LargeTest
266     @Test
testFgsProcStatsTracker()267     public void testFgsProcStatsTracker() throws Exception {
268         final PackageManager pm = mContext.getPackageManager();
269         final long timeout = 5000;
270         int uid = pm.getPackageUid(TEST_APP1, 0);
271         final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
272         final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
273         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
274         final CountDownLatch[] latchHolder = new CountDownLatch[1];
275         final H handler = new H(Looper.getMainLooper(), latchHolder);
276         final Messenger messenger = new Messenger(handler);
277         final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
278         final CountDownLatch dboxLatch = new CountDownLatch(1);
279         final BroadcastReceiver receiver = new BroadcastReceiver() {
280             @Override
281             public void onReceive(Context context, Intent intent) {
282                 final String tag_wtf = "system_server_wtf";
283                 if (tag_wtf.equals(intent.getStringExtra(DropBoxManager.EXTRA_TAG))) {
284                     final DropBoxManager.Entry e = dbox.getNextEntry(tag_wtf, intent.getLongExtra(
285                             DropBoxManager.EXTRA_TIME, 0) - 1);
286                     final String text = e.getText(8192);
287                     if (TextUtils.isEmpty(text)) {
288                         return;
289                     }
290                     if (text.indexOf("can't store negative values") == -1) {
291                         return;
292                     }
293                     dboxLatch.countDown();
294                 }
295             }
296         };
297         try {
298             mContext.registerReceiver(receiver,
299                     new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED));
300             am.addOnUidImportanceListener(uidListener1,
301                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
302             am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
303             runShellCommand("cmd deviceidle whitelist +" + TEST_APP1);
304             toggleScreenOn(true);
305 
306             final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
307             final ComponentName cn = ComponentName.unflattenFromString(
308                     TEST_APP1 + "/" + TEST_FGS_CLASS);
309             final Bundle bundle = new Bundle();
310             intent.setComponent(cn);
311             bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
312             intent.putExtras(bundle);
313 
314             latchHolder[0] = new CountDownLatch(1);
315             mContext.startForegroundService(intent);
316             assertTrue("Timed out to start fg service", uidListener1.waitFor(
317                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, timeout));
318             assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
319                     timeout, TimeUnit.MILLISECONDS));
320 
321             Thread.sleep(timeout);
322             latchHolder[0] = new CountDownLatch(1);
323             handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
324             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
325                     timeout, TimeUnit.MILLISECONDS));
326 
327             Thread.sleep(timeout);
328             latchHolder[0] = new CountDownLatch(1);
329             handler.sendRemoteMessage(H.MSG_START_FOREGROUND, 0, 0, null);
330             assertTrue("Timed out to wait for start fg", latchHolder[0].await(
331                     timeout, TimeUnit.MILLISECONDS));
332 
333             toggleScreenOn(false);
334             latchHolder[0] = new CountDownLatch(1);
335             handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
336             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
337                     timeout, TimeUnit.MILLISECONDS));
338             assertFalse("There shouldn't be negative values", dboxLatch.await(
339                     timeout * 2, TimeUnit.MILLISECONDS));
340         } finally {
341             toggleScreenOn(true);
342             runShellCommand("cmd deviceidle whitelist -" + TEST_APP1);
343             am.removeOnUidImportanceListener(uidListener1);
344             am.removeOnUidImportanceListener(uidListener2);
345             am.forceStopPackage(TEST_APP1);
346             mContext.unregisterReceiver(receiver);
347         }
348     }
349 
350     @LargeTest
351     @Test
testAppFreezerWithAllowOomAdj()352     public void testAppFreezerWithAllowOomAdj() throws Exception {
353         final long waitFor = 5000;
354         boolean freezerWasEnabled = isFreezerEnabled();
355         SettingsSession<String> freezerEnabled = null;
356         SettingsSession<String> amConstantsSettings = null;
357         DeviceConfigSession<Long> freezerDebounceTimeout = null;
358         MyServiceConnection autoConnection = null;
359         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
360         final PackageManager pm = mContext.getPackageManager();
361         final int uid1 = pm.getPackageUid(TEST_APP1, 0);
362         final int uid2 = pm.getPackageUid(TEST_APP2, 0);
363         final MyUidImportanceListener uid1Listener = new MyUidImportanceListener(uid1);
364         final MyUidImportanceListener uid2Listener = new MyUidImportanceListener(uid2);
365         try {
366             if (!freezerWasEnabled) {
367                 freezerEnabled = new SettingsSession<>(
368                         Settings.Global.getUriFor(Settings.Global.CACHED_APPS_FREEZER_ENABLED),
369                         Settings.Global::getString, Settings.Global::putString);
370                 freezerEnabled.set("enabled");
371                 Thread.sleep(waitFor);
372                 if (!isFreezerEnabled()) {
373                     // Still not enabled? Probably because the device doesn't support it.
374                     return;
375                 }
376             }
377             freezerDebounceTimeout = new DeviceConfigSession<>(
378                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
379                     CachedAppOptimizer.KEY_FREEZER_DEBOUNCE_TIMEOUT,
380                     DeviceConfig::getLong, CachedAppOptimizer.DEFAULT_FREEZER_DEBOUNCE_TIMEOUT);
381             freezerDebounceTimeout.set(waitFor);
382 
383             final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS;
384             amConstantsSettings = new SettingsSession<>(
385                 Settings.Global.getUriFor(activityManagerConstants),
386                 Settings.Global::getString, Settings.Global::putString);
387 
388             amConstantsSettings.set(
389                     ActivityManagerConstants.KEY_MAX_SERVICE_INACTIVITY + "=" + waitFor);
390 
391             runShellCommand("cmd deviceidle whitelist +" + TEST_APP1);
392             runShellCommand("cmd deviceidle whitelist +" + TEST_APP2);
393 
394             am.addOnUidImportanceListener(uid1Listener,
395                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
396             am.addOnUidImportanceListener(uid2Listener, RunningAppProcessInfo.IMPORTANCE_CACHED);
397 
398             final Intent intent = new Intent();
399             intent.setClassName(TEST_APP1, TEST_CLASS);
400 
401             CountDownLatch latch = new CountDownLatch(1);
402             autoConnection = new MyServiceConnection(latch);
403             mContext.bindService(intent, autoConnection,
404                     Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
405             try {
406                 assertTrue("Timeout to bind to service " + intent.getComponent(),
407                         latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
408             } catch (InterruptedException e) {
409                 fail("Unable to bind to service " + intent.getComponent());
410             }
411             assertFalse(TEST_APP1 + " shouldn't be frozen now.", isAppFrozen(TEST_APP1));
412 
413             // Trigger oomAdjUpdate/
414             toggleScreenOn(false);
415             toggleScreenOn(true);
416 
417             // Wait for the freezer kick in if there is any.
418             Thread.sleep(waitFor * 4);
419 
420             // It still shouldn't be frozen, although it's been in cached state.
421             assertFalse(TEST_APP1 + " shouldn't be frozen now.", isAppFrozen(TEST_APP1));
422 
423             final CountDownLatch[] latchHolder = new CountDownLatch[1];
424             final IRemoteCallback callback = new IRemoteCallback.Stub() {
425                 @Override
426                 public void sendResult(Bundle bundle) {
427                     if (bundle != null) {
428                         latchHolder[0].countDown();
429                     }
430                 }
431             };
432 
433             // Bind from app1 to app2 without BIND_WAIVE_PRIORITY.
434             final Bundle extras = new Bundle();
435             extras.putBinder(EXTRA_CALLBACK, callback.asBinder());
436             latchHolder[0] = new CountDownLatch(1);
437             sendCommand(COMMAND_BIND_SERVICE, TEST_APP1, TEST_APP2, extras);
438             assertTrue("Timed out to bind to " + TEST_APP2, latchHolder[0].await(
439                     waitFor, TimeUnit.MILLISECONDS));
440 
441             // Stop service in app1
442             extras.clear();
443             sendCommand(COMMAND_STOP_SELF, TEST_APP1, TEST_APP1, extras);
444 
445             assertTrue(TEST_APP2 + " should be in cached", uid2Listener.waitFor(
446                     RunningAppProcessInfo.IMPORTANCE_CACHED, waitFor));
447 
448             // Wait for the freezer kick in if there is any.
449             Thread.sleep(waitFor * 4);
450 
451             // It still shouldn't be frozen, although it's been in cached state.
452             assertFalse(TEST_APP2 + " shouldn't be frozen now.", isAppFrozen(TEST_APP2));
453         } finally {
454             toggleScreenOn(true);
455             if (amConstantsSettings != null) {
456                 amConstantsSettings.close();
457             }
458             if (freezerEnabled != null) {
459                 freezerEnabled.close();
460             }
461             if (freezerDebounceTimeout != null) {
462                 freezerDebounceTimeout.close();
463             }
464             if (autoConnection != null) {
465                 mContext.unbindService(autoConnection);
466             }
467             am.removeOnUidImportanceListener(uid1Listener);
468             am.removeOnUidImportanceListener(uid2Listener);
469             sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP1, TEST_APP2, null);
470             sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP2, TEST_APP1, null);
471             runShellCommand("cmd deviceidle whitelist -" + TEST_APP1);
472             runShellCommand("cmd deviceidle whitelist -" + TEST_APP2);
473             am.forceStopPackage(TEST_APP1);
474             am.forceStopPackage(TEST_APP2);
475         }
476     }
477 
sendCommand(int command, String sourcePkg, String targetPkg, Bundle extras)478     private void sendCommand(int command, String sourcePkg, String targetPkg, Bundle extras) {
479         final Intent intent = new Intent();
480         intent.setClassName(sourcePkg, TEST_CLASS);
481         intent.putExtra(EXTRA_COMMAND, command);
482         intent.putExtra(EXTRA_TARGET_PACKAGE, targetPkg);
483         if (extras != null) {
484             intent.putExtras(extras);
485         }
486         mContext.startService(intent);
487     }
488 
isFreezerEnabled()489     private boolean isFreezerEnabled() throws Exception {
490         final String output = runShellCommand("dumpsys activity settings");
491         final Matcher matcher = Pattern.compile("\\b" + CachedAppOptimizer.KEY_USE_FREEZER
492                 + "\\b=\\b(true|false)\\b").matcher(output);
493         if (matcher.find()) {
494             return Boolean.parseBoolean(matcher.group(1));
495         }
496         return false;
497     }
498 
isAppFrozen(String packageName)499     private boolean isAppFrozen(String packageName) throws Exception {
500         final String output = runShellCommand("dumpsys activity p " + packageName);
501         final Matcher matcher = Pattern.compile("\\b" + ProcessCachedOptimizerRecord.IS_FROZEN
502                 + "\\b=\\b(true|false)\\b").matcher(output);
503         if (matcher.find()) {
504             return Boolean.parseBoolean(matcher.group(1));
505         }
506         return false;
507     }
508 
509     @LargeTest
510     @Test
testKillAppIfBgRestrictedCachedIdle()511     public void testKillAppIfBgRestrictedCachedIdle() throws Exception {
512         final long shortTimeoutMs = 5_000;
513         final long backgroundSettleMs = 10_000;
514         final PackageManager pm = mContext.getPackageManager();
515         final int uid = pm.getPackageUid(TEST_APP1, 0);
516         final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
517         final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
518         final MyUidImportanceListener uidListener3 = new MyUidImportanceListener(uid);
519         SettingsSession<String> amConstantsSettings = null;
520         DeviceConfigSession<Boolean> killBgRestrictedAndCachedIdle = null;
521         DeviceConfigSession<Long> killBgRestrictedAndCachedIdleSettleTime = null;
522         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
523         final CountDownLatch[] latchHolder = new CountDownLatch[1];
524         final H handler = new H(Looper.getMainLooper(), latchHolder);
525         final Messenger messenger = new Messenger(handler);
526         try {
527             am.addOnUidImportanceListener(uidListener1,
528                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
529             am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
530             am.addOnUidImportanceListener(uidListener3, RunningAppProcessInfo.IMPORTANCE_CACHED);
531             toggleScreenOn(true);
532 
533             killBgRestrictedAndCachedIdle = new DeviceConfigSession<>(
534                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
535                     ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
536                     DeviceConfig::getBoolean,
537                     ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
538             killBgRestrictedAndCachedIdle.set(true);
539             killBgRestrictedAndCachedIdleSettleTime = new DeviceConfigSession<>(
540                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
541                     ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
542                     DeviceConfig::getLong,
543                     ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
544             killBgRestrictedAndCachedIdleSettleTime.set(backgroundSettleMs);
545             amConstantsSettings = new SettingsSession<>(
546                 Settings.Global.getUriFor(Settings.Global.ACTIVITY_MANAGER_CONSTANTS),
547                 Settings.Global::getString, Settings.Global::putString);
548             final KeyValueListParser parser = new KeyValueListParser(',');
549             long currentBackgroundSettleMs =
550                     ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME;
551             try {
552                 parser.setString(amConstantsSettings.get());
553                 currentBackgroundSettleMs = parser.getLong(
554                         ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME,
555                         ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME);
556             } catch (IllegalArgumentException e) {
557             }
558             // Drain queue to make sure the existing UID_IDLE_MSG has been processed.
559             Thread.sleep(currentBackgroundSettleMs);
560             amConstantsSettings.set(
561                     ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME + "=" + backgroundSettleMs);
562 
563             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
564 
565             final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
566             final ComponentName cn = ComponentName.unflattenFromString(
567                     TEST_APP1 + "/" + TEST_FGS_CLASS);
568             final Bundle bundle = new Bundle();
569             intent.setComponent(cn);
570             bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
571             intent.putExtras(bundle);
572 
573             // Start the FGS.
574             latchHolder[0] = new CountDownLatch(1);
575             mContext.startForegroundService(intent);
576             assertTrue("Timed out to start fg service", uidListener1.waitFor(
577                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
578             assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
579                     shortTimeoutMs, TimeUnit.MILLISECONDS));
580             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
581                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
582 
583             // Stop the FGS, it shouldn't be killed because it's not in FAS state.
584             latchHolder[0] = new CountDownLatch(1);
585             handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
586             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
587                     shortTimeoutMs, TimeUnit.MILLISECONDS));
588             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
589                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
590 
591             // Set the FAS state.
592             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
593             // Now it should've been killed.
594             assertTrue("Should have been killed", uidListener2.waitFor(
595                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
596 
597             // Start the FGS.
598             // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
599             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
600             latchHolder[0] = new CountDownLatch(1);
601             mContext.startForegroundService(intent);
602             assertTrue("Timed out to start fg service", uidListener1.waitFor(
603                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
604             assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
605                     shortTimeoutMs, TimeUnit.MILLISECONDS));
606             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
607             // It shouldn't be killed since it's not cached.
608             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
609                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
610 
611             // Stop the FGS, it should get killed because it's cached & uid idle & in FAS state.
612             latchHolder[0] = new CountDownLatch(1);
613             handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
614             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
615                     shortTimeoutMs, TimeUnit.MILLISECONDS));
616             assertTrue("Should have been killed", uidListener2.waitFor(
617                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
618 
619             // Start the FGS.
620             // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
621             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
622             latchHolder[0] = new CountDownLatch(1);
623             mContext.startForegroundService(intent);
624             assertTrue("Timed out to start fg service", uidListener1.waitFor(
625                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
626             assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
627                     shortTimeoutMs, TimeUnit.MILLISECONDS));
628             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
629             // It shouldn't be killed since it's not cached.
630             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
631                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
632 
633             // Stop the FGS.
634             latchHolder[0] = new CountDownLatch(1);
635             handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
636             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
637                     shortTimeoutMs, TimeUnit.MILLISECONDS));
638             assertTrue("Should have been in cached state", uidListener3.waitFor(
639                     RunningAppProcessInfo.IMPORTANCE_CACHED, shortTimeoutMs));
640             final long now = SystemClock.uptimeMillis();
641             // Sleep a while to let the UID idle ticking.
642             Thread.sleep(shortTimeoutMs);
643             // Now send a broadcast, it should bring the app out of cached for a while.
644             final Intent intent2 = new Intent(ACTION_RECEIVER_TEST);
645             final Bundle extras = new Bundle();
646             final IRemoteCallback callback = new IRemoteCallback.Stub() {
647                 @Override
648                 public void sendResult(Bundle data) throws RemoteException {
649                     latchHolder[0].countDown();
650                 }
651             };
652             extras.putBinder(EXTRA_CALLBACK, callback.asBinder());
653             intent2.putExtras(extras);
654             intent2.setPackage(TEST_APP1);
655             latchHolder[0] = new CountDownLatch(1);
656             mContext.sendBroadcast(intent2);
657             assertTrue("Timed out to wait for receiving broadcast", latchHolder[0].await(
658                     shortTimeoutMs, TimeUnit.MILLISECONDS));
659             // Try to wait for the killing, it should be killed after backgroundSettleMs
660             // since receiving the broadcast
661             assertFalse("Shouldn't be killed now", uidListener2.waitFor(
662                     RunningAppProcessInfo.IMPORTANCE_GONE,
663                     backgroundSettleMs + now - SystemClock.uptimeMillis() + 2_000));
664             // Now wait a bit longer, it should be killed.
665             assertTrue("Should have been killed", uidListener2.waitFor(
666                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
667 
668             // Disable this FAS cached idle kill feature.
669             killBgRestrictedAndCachedIdle.set(false);
670 
671             // Start the FGS.
672             // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
673             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
674             latchHolder[0] = new CountDownLatch(1);
675             mContext.startForegroundService(intent);
676             assertTrue("Timed out to start fg service", uidListener1.waitFor(
677                     RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
678             assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
679                     shortTimeoutMs, TimeUnit.MILLISECONDS));
680             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
681             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
682                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
683 
684             // Stop the FGS, it shouldn't be killed because the feature has been turned off.
685             latchHolder[0] = new CountDownLatch(1);
686             handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
687             assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
688                     shortTimeoutMs, TimeUnit.MILLISECONDS));
689             assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
690                     RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
691         } finally {
692             runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND default");
693             if (amConstantsSettings != null) {
694                 amConstantsSettings.close();
695             }
696             if (killBgRestrictedAndCachedIdle != null) {
697                 killBgRestrictedAndCachedIdle.close();
698             }
699             if (killBgRestrictedAndCachedIdleSettleTime != null) {
700                 killBgRestrictedAndCachedIdleSettleTime.close();
701             }
702             am.removeOnUidImportanceListener(uidListener1);
703             am.removeOnUidImportanceListener(uidListener2);
704             am.removeOnUidImportanceListener(uidListener3);
705             am.forceStopPackage(TEST_APP1);
706         }
707     }
708 
709     @Ignore("Need to disable calling uid check in ActivityManagerService.killPids before this test")
710     @Test
testKillPids()711     public void testKillPids() throws Exception {
712         final long timeout = 5000;
713         final long shortTimeout = 2000;
714         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
715         final PackageManager pm = mContext.getPackageManager();
716         final int uid1 = pm.getPackageUid(TEST_APP1, 0);
717         final int uid2 = pm.getPackageUid(TEST_APP2, 0);
718         final int uid3 = pm.getPackageUid(TEST_APP3, 0);
719         final MyUidImportanceListener uid1Listener1 = new MyUidImportanceListener(uid1);
720         final MyUidImportanceListener uid1Listener2 = new MyUidImportanceListener(uid1);
721         final MyUidImportanceListener uid2Listener1 = new MyUidImportanceListener(uid2);
722         final MyUidImportanceListener uid2Listener2 = new MyUidImportanceListener(uid2);
723         final MyUidImportanceListener uid3Listener1 = new MyUidImportanceListener(uid3);
724         final MyUidImportanceListener uid3Listener2 = new MyUidImportanceListener(uid3);
725         try {
726             am.addOnUidImportanceListener(uid1Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
727             am.addOnUidImportanceListener(uid1Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
728             am.addOnUidImportanceListener(uid2Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
729             am.addOnUidImportanceListener(uid2Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
730             am.addOnUidImportanceListener(uid3Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
731             am.addOnUidImportanceListener(uid3Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
732             runShellCommand("cmd deviceidle whitelist +" + TEST_APP1);
733             runShellCommand("cmd deviceidle whitelist +" + TEST_APP2);
734             runShellCommand("cmd deviceidle whitelist +" + TEST_APP3);
735             final int[] pids = new int[3];
736             // Test sync kills
737             pids[0] = startTargetService(am, TEST_APP1, TEST_CLASS, uid1, TEST_APP1,
738                     uid1Listener1, timeout);
739             pids[1] = startTargetService(am, TEST_APP2, TEST_CLASS, uid2, TEST_APP2,
740                     uid2Listener1, timeout);
741             pids[2] = startTargetService(am, TEST_APP3, TEST_CLASS, uid3, TEST_APP3,
742                     uid3Listener1, timeout);
743             Thread.sleep(shortTimeout);
744             mService.killPids(pids, "testKillPids", false);
745             assertTrue("Timed out to kill process", uid1Listener2.waitFor(
746                     RunningAppProcessInfo.IMPORTANCE_GONE, timeout));
747             assertTrue("Timed out to kill process", uid2Listener2.waitFor(
748                     RunningAppProcessInfo.IMPORTANCE_GONE, timeout));
749             assertTrue("Timed out to kill process", uid3Listener2.waitFor(
750                     RunningAppProcessInfo.IMPORTANCE_GONE, timeout));
751         } finally {
752             runShellCommand("cmd deviceidle whitelist -" + TEST_APP1);
753             runShellCommand("cmd deviceidle whitelist -" + TEST_APP2);
754             runShellCommand("cmd deviceidle whitelist -" + TEST_APP3);
755             am.removeOnUidImportanceListener(uid1Listener1);
756             am.removeOnUidImportanceListener(uid1Listener2);
757             am.removeOnUidImportanceListener(uid2Listener1);
758             am.removeOnUidImportanceListener(uid2Listener2);
759             am.removeOnUidImportanceListener(uid3Listener1);
760             am.removeOnUidImportanceListener(uid3Listener2);
761             am.forceStopPackage(TEST_APP1);
762             am.forceStopPackage(TEST_APP2);
763             am.forceStopPackage(TEST_APP3);
764         }
765     }
766 
startTargetService(ActivityManager am, String targetPakage, String targetService, int targetUid, String targetProcessName, MyUidImportanceListener uidListener, long timeout)767     private int startTargetService(ActivityManager am, String targetPakage, String targetService,
768             int targetUid, String targetProcessName, MyUidImportanceListener uidListener,
769             long timeout) throws Exception {
770         final Intent intent = new Intent();
771         intent.setComponent(ComponentName.unflattenFromString(targetPakage + "/" + targetService));
772         mContext.startService(intent);
773         assertTrue("Timed out to start service", uidListener.waitFor(
774                 RunningAppProcessInfo.IMPORTANCE_SERVICE, timeout));
775         final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
776         for (int i = processes.size() - 1; i >= 0; i--) {
777             final RunningAppProcessInfo info = processes.get(i);
778             if (info.uid == targetUid && targetProcessName.equals(info.processName)) {
779                 return info.pid;
780             }
781         }
782         return -1;
783     }
784 
785     @Test
testGetIsolatedProcesses()786     public void testGetIsolatedProcesses() throws Exception {
787         final ActivityManager am = mContext.getSystemService(ActivityManager.class);
788         final PackageManager pm = mContext.getPackageManager();
789         final int uid1 = pm.getPackageUid(TEST_APP1, 0);
790         final int uid2 = pm.getPackageUid(TEST_APP2, 0);
791         final int uid3 = pm.getPackageUid(TEST_APP3, 0);
792         final List<Pair<Integer, ServiceConnection>> uid1Processes = new ArrayList<>();
793         final List<Pair<Integer, ServiceConnection>> uid2Processes = new ArrayList<>();
794         try {
795             assertTrue("There shouldn't be any isolated process for " + TEST_APP1,
796                     getIsolatedProcesses(uid1).isEmpty());
797             assertTrue("There shouldn't be any isolated process for " + TEST_APP2,
798                     getIsolatedProcesses(uid2).isEmpty());
799             assertTrue("There shouldn't be any isolated process for " + TEST_APP3,
800                     getIsolatedProcesses(uid3).isEmpty());
801 
802             // Verify uid1
803             uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
804             uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
805             uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1));
806             verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));
807 
808             // Let one of the processes go
809             final Pair<Integer, ServiceConnection> uid1P2 = uid1Processes.remove(2);
810             mContext.unbindService(uid1P2.second);
811             Thread.sleep(5_000); // Wait for the process gone.
812             verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));
813 
814             // Verify uid2
815             uid2Processes.add(createIsolatedProcessAndVerify(TEST_APP2, uid2));
816             verifyIsolatedProcesses(uid2Processes, getIsolatedProcesses(uid2));
817 
818             // Verify uid1 again
819             verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1));
820 
821             // Verify uid3
822             assertTrue("There shouldn't be any isolated process for " + TEST_APP3,
823                     getIsolatedProcesses(uid3).isEmpty());
824         } finally {
825             for (Pair<Integer, ServiceConnection> p: uid1Processes) {
826                 mContext.unbindService(p.second);
827             }
828             for (Pair<Integer, ServiceConnection> p: uid2Processes) {
829                 mContext.unbindService(p.second);
830             }
831             am.forceStopPackage(TEST_APP1);
832             am.forceStopPackage(TEST_APP2);
833             am.forceStopPackage(TEST_APP3);
834         }
835     }
836 
getIsolatedProcesses(int uid)837     private static List<Integer> getIsolatedProcesses(int uid) throws Exception {
838         final String output = runShellCommand("am get-isolated-pids " + uid);
839         final Matcher matcher = Pattern.compile("(\\d+)").matcher(output);
840         final List<Integer> pids = new ArrayList<>();
841         while (matcher.find()) {
842             pids.add(Integer.parseInt(output.substring(matcher.start(), matcher.end())));
843         }
844         return pids;
845     }
846 
verifyIsolatedProcesses(List<Pair<Integer, ServiceConnection>> processes, List<Integer> pids)847     private void verifyIsolatedProcesses(List<Pair<Integer, ServiceConnection>> processes,
848             List<Integer> pids) {
849         final List<Integer> l = processes.stream().map(p -> p.first).collect(Collectors.toList());
850         assertTrue("Isolated processes don't match", l.containsAll(pids));
851         assertTrue("Isolated processes don't match", pids.containsAll(l));
852     }
853 
createIsolatedProcessAndVerify(String pkgName, int uid)854     private Pair<Integer, ServiceConnection> createIsolatedProcessAndVerify(String pkgName, int uid)
855             throws Exception {
856         final Pair<Integer, ServiceConnection> p = createIsolatedProcess(pkgName);
857         final List<Integer> pids = getIsolatedProcesses(uid);
858         assertTrue("Can't find the isolated pid " + p.first + " for " + pkgName,
859                 pids.contains(p.first));
860         return p;
861     }
862 
createIsolatedProcess(String pkgName)863     private Pair<Integer, ServiceConnection> createIsolatedProcess(String pkgName)
864             throws Exception {
865         final int[] pid = new int[1];
866         final CountDownLatch[] latch = new CountDownLatch[1];
867         final ServiceConnection conn = new ServiceConnection() {
868             @Override
869             public void onServiceConnected(ComponentName name, IBinder service) {
870                 final IRemoteCallback s = IRemoteCallback.Stub.asInterface(service);
871                 final IBinder callback = new Binder() {
872                     @Override
873                     protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
874                             throws RemoteException {
875                         if (code == Binder.FIRST_CALL_TRANSACTION) {
876                             pid[0] = data.readInt();
877                             latch[0].countDown();
878                             return true;
879                         }
880                         return super.onTransact(code, data, reply, flags);
881                     }
882                 };
883                 try {
884                     final Bundle extra = new Bundle();
885                     extra.putBinder(EXTRA_CALLBACK, callback);
886                     s.sendResult(extra);
887                 } catch (RemoteException e) {
888                     fail("Unable to call into isolated process");
889                 }
890             }
891             @Override
892             public void onServiceDisconnected(ComponentName name) {
893             }
894         };
895         final Intent intent = new Intent();
896         intent.setClassName(pkgName, TEST_ISOLATED_CLASS);
897         latch[0] = new CountDownLatch(1);
898         assertTrue("Unable to create isolated process in " + pkgName,
899                 mContext.bindIsolatedService(intent, Context.BIND_AUTO_CREATE,
900                 Long.toString(SystemClock.uptimeMillis()), mContext.getMainExecutor(), conn));
901         assertTrue("Timeout to bind to service " + intent.getComponent(),
902                 latch[0].await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
903         return Pair.create(pid[0], conn);
904     }
905 
906     /**
907      * Make sure the screen state.
908      */
toggleScreenOn(final boolean screenon)909     private void toggleScreenOn(final boolean screenon) throws Exception {
910         if (screenon) {
911             runShellCommand("input keyevent KEYCODE_WAKEUP");
912             runShellCommand("wm dismiss-keyguard");
913         } else {
914             runShellCommand("input keyevent KEYCODE_SLEEP");
915         }
916         // Since the screen on/off intent is ordered, they will not be sent right now.
917         Thread.sleep(2_000);
918     }
919 
920     private class H extends Handler {
921         static final int MSG_INIT = 0;
922         static final int MSG_DONE = 1;
923         static final int MSG_START_FOREGROUND = 2;
924         static final int MSG_STOP_FOREGROUND = 3;
925         static final int MSG_STOP_SERVICE = 4;
926 
927         private Messenger mRemoteMessenger;
928         private CountDownLatch[] mLatchHolder;
929 
H(Looper looper, CountDownLatch[] latchHolder)930         H(Looper looper, CountDownLatch[] latchHolder) {
931             super(looper);
932             mLatchHolder = latchHolder;
933         }
934 
935         @Override
handleMessage(Message msg)936         public void handleMessage(Message msg) {
937             switch (msg.what) {
938                 case MSG_INIT:
939                     mRemoteMessenger = (Messenger) msg.obj;
940                     mLatchHolder[0].countDown();
941                     break;
942                 case MSG_DONE:
943                     mLatchHolder[0].countDown();
944                     break;
945             }
946         }
947 
sendRemoteMessage(int what, int arg1, int arg2, Object obj)948         void sendRemoteMessage(int what, int arg1, int arg2, Object obj) {
949             Message msg = Message.obtain();
950             msg.what = what;
951             msg.arg1 = arg1;
952             msg.arg2 = arg2;
953             msg.obj = obj;
954             try {
955                 mRemoteMessenger.send(msg);
956             } catch (RemoteException e) {
957             }
958             msg.recycle();
959         }
960     }
961 
962     private static class MyUidImportanceListener implements OnUidImportanceListener {
963         final CountDownLatch[] mLatchHolder = new CountDownLatch[1];
964         private final int mExpectedUid;
965         private int mExpectedImportance;
966         private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
967 
MyUidImportanceListener(int uid)968         MyUidImportanceListener(int uid) {
969             mExpectedUid = uid;
970         }
971 
972         @Override
onUidImportance(int uid, int importance)973         public void onUidImportance(int uid, int importance) {
974             if (uid == mExpectedUid) {
975                 synchronized (this) {
976                     if (importance == mExpectedImportance && mLatchHolder[0] != null) {
977                         mLatchHolder[0].countDown();
978                     }
979                     mCurrentImportance = importance;
980                 }
981                 Log.i(TAG, "uid " + uid + " importance: " + importance);
982             }
983         }
984 
waitFor(int expectedImportance, long timeout)985         boolean waitFor(int expectedImportance, long timeout) throws Exception {
986             synchronized (this) {
987                 mExpectedImportance = expectedImportance;
988                 if (mCurrentImportance == expectedImportance) {
989                     return true;
990                 }
991                 mLatchHolder[0] = new CountDownLatch(1);
992             }
993             return mLatchHolder[0].await(timeout, TimeUnit.MILLISECONDS);
994         }
995     }
996 }
997