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