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.support.test.uiautomator.UiDevice; 56 import android.test.suitebuilder.annotation.LargeTest; 57 import android.text.TextUtils; 58 import android.util.Log; 59 import android.util.Pair; 60 61 import androidx.test.InstrumentationRegistry; 62 import androidx.test.filters.FlakyTest; 63 64 import org.junit.Before; 65 import org.junit.Ignore; 66 import org.junit.Test; 67 68 import java.io.IOException; 69 import java.util.ArrayList; 70 import java.util.List; 71 import java.util.concurrent.CountDownLatch; 72 import java.util.concurrent.TimeUnit; 73 import java.util.regex.Matcher; 74 import java.util.regex.Pattern; 75 import java.util.stream.Collectors; 76 77 /** 78 * Tests for {@link ActivityManager}. 79 * 80 * Build/Install/Run: 81 * atest FrameworksServicesTests:ActivityManagerTest 82 */ 83 @FlakyTest(detail = "Promote to presubmit if stable") 84 @Presubmit 85 public class ActivityManagerTest { 86 private static final String TAG = "ActivityManagerTest"; 87 88 private static final String TEST_APP1 = "com.android.servicestests.apps.simpleservicetestapp1"; 89 private static final String TEST_APP2 = "com.android.servicestests.apps.simpleservicetestapp2"; 90 private static final String TEST_APP3 = "com.android.servicestests.apps.simpleservicetestapp3"; 91 private static final String TEST_CLASS = 92 "com.android.servicestests.apps.simpleservicetestapp.SimpleService"; 93 private static final int TEST_LOOPS = 100; 94 private static final long AWAIT_TIMEOUT = 2000; 95 private static final long CHECK_INTERVAL = 100; 96 97 private static final String TEST_FGS_CLASS = 98 "com.android.servicestests.apps.simpleservicetestapp.SimpleFgService"; 99 private static final String ACTION_FGS_STATS_TEST = 100 "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST"; 101 private static final String EXTRA_MESSENGER = "extra_messenger"; 102 103 private static final String EXTRA_CALLBACK = "callback"; 104 private static final String EXTRA_COMMAND = "command"; 105 private static final String EXTRA_FLAGS = "flags"; 106 private static final String EXTRA_TARGET_PACKAGE = "target_package"; 107 108 private static final int COMMAND_INVALID = 0; 109 private static final int COMMAND_EMPTY = 1; 110 private static final int COMMAND_BIND_SERVICE = 2; 111 private static final int COMMAND_UNBIND_SERVICE = 3; 112 private static final int COMMAND_STOP_SELF = 4; 113 114 private static final String TEST_ISOLATED_CLASS = 115 "com.android.servicestests.apps.simpleservicetestapp.SimpleIsolatedService"; 116 117 private IActivityManager mService; 118 private IRemoteCallback mCallback; 119 private Context mContext; 120 121 @Before setUp()122 public void setUp() throws Exception { 123 mService = ActivityManager.getService(); 124 mContext = InstrumentationRegistry.getTargetContext(); 125 } 126 127 @Test testTaskIdsForRunningUsers()128 public void testTaskIdsForRunningUsers() throws RemoteException { 129 int[] runningUserIds = mService.getRunningUserIds(); 130 assertThat(runningUserIds).isNotEmpty(); 131 for (int userId : runningUserIds) { 132 testTaskIdsForUser(userId); 133 } 134 } 135 testTaskIdsForUser(int userId)136 private void testTaskIdsForUser(int userId) throws RemoteException { 137 List<?> recentTasks = mService.getRecentTasks(100, 0, userId).getList(); 138 if (recentTasks != null) { 139 for (Object elem : recentTasks) { 140 assertThat(elem).isInstanceOf(RecentTaskInfo.class); 141 RecentTaskInfo recentTask = (RecentTaskInfo) elem; 142 int taskId = recentTask.taskId; 143 assertEquals("The task id " + taskId + " should not belong to user " + userId, 144 taskId / UserHandle.PER_USER_RANGE, userId); 145 } 146 } 147 } 148 149 @Test testServiceUnbindAndKilling()150 public void testServiceUnbindAndKilling() { 151 for (int i = TEST_LOOPS; i > 0; i--) { 152 runOnce(i); 153 } 154 } 155 runOnce(long yieldDuration)156 private void runOnce(long yieldDuration) { 157 final PackageManager pm = mContext.getPackageManager(); 158 int uid = 0; 159 try { 160 uid = pm.getPackageUid(TEST_APP1, 0); 161 } catch (PackageManager.NameNotFoundException e) { 162 throw new RuntimeException(e); 163 } 164 165 Intent intent = new Intent(); 166 intent.setClassName(TEST_APP1, TEST_CLASS); 167 168 // Create a service connection with auto creation. 169 CountDownLatch latch = new CountDownLatch(1); 170 final MyServiceConnection autoConnection = new MyServiceConnection(latch); 171 mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE); 172 try { 173 assertTrue("Timeout to bind to service " + intent.getComponent(), 174 latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); 175 } catch (InterruptedException e) { 176 fail("Unable to bind to service " + intent.getComponent()); 177 } 178 179 // Create a service connection without any flags. 180 intent = new Intent(); 181 intent.setClassName(TEST_APP1, TEST_CLASS); 182 latch = new CountDownLatch(1); 183 MyServiceConnection otherConnection = new MyServiceConnection(latch); 184 mContext.bindService(intent, otherConnection, 0); 185 try { 186 assertTrue("Timeout to bind to service " + intent.getComponent(), 187 latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); 188 } catch (InterruptedException e) { 189 fail("Unable to bind to service " + intent.getComponent()); 190 } 191 192 // Inform the remote process to kill itself 193 try { 194 mCallback.sendResult(null); 195 // It's basically a test for race condition, we expect the bringDownServiceLocked() 196 // would find out the hosting process is dead - to do this, technically we should 197 // do killing and unbinding simultaneously; but in reality, the killing would take 198 // a little while, before the signal really kills it; so we do it in the same thread, 199 // and even wait a while after sending killing signal. 200 Thread.sleep(yieldDuration); 201 } catch (RemoteException | InterruptedException e) { 202 fail("Unable to kill the process"); 203 } 204 // Now unbind that auto connection, this should be equivalent to stopService 205 mContext.unbindService(autoConnection); 206 207 // Now we don't expect the system_server crashes. 208 209 // Wait for the target process dies 210 long total = 0; 211 for (; total < AWAIT_TIMEOUT; total += CHECK_INTERVAL) { 212 try { 213 if (!targetPackageIsRunning(mContext, uid)) { 214 break; 215 } 216 Thread.sleep(CHECK_INTERVAL); 217 } catch (InterruptedException e) { 218 } 219 } 220 assertTrue("Timeout to wait for the target package dies", total < AWAIT_TIMEOUT); 221 mCallback = null; 222 } 223 targetPackageIsRunning(Context context, int uid)224 private boolean targetPackageIsRunning(Context context, int uid) { 225 final String result = runShellCommand( 226 String.format("cmd activity get-uid-state %d", uid)); 227 return !result.contains("(NONEXISTENT)"); 228 } 229 runShellCommand(String cmd)230 private static String runShellCommand(String cmd) { 231 try { 232 return UiDevice.getInstance( 233 InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd); 234 } catch (IOException e) { 235 throw new RuntimeException(e); 236 } 237 } 238 239 private class MyServiceConnection implements ServiceConnection { 240 private CountDownLatch mLatch; 241 MyServiceConnection(CountDownLatch latch)242 MyServiceConnection(CountDownLatch latch) { 243 this.mLatch = latch; 244 } 245 246 @Override onServiceConnected(ComponentName name, IBinder service)247 public void onServiceConnected(ComponentName name, IBinder service) { 248 mCallback = IRemoteCallback.Stub.asInterface(service); 249 mLatch.countDown(); 250 } 251 252 @Override onServiceDisconnected(ComponentName name)253 public void onServiceDisconnected(ComponentName name) { 254 } 255 } 256 257 /** 258 * Note: This test actually only works in eng build. It'll always pass 259 * in user and userdebug build, because the expected exception won't be 260 * thrown in those builds. 261 */ 262 @LargeTest 263 @Test testFgsProcStatsTracker()264 public void testFgsProcStatsTracker() throws Exception { 265 final PackageManager pm = mContext.getPackageManager(); 266 final long timeout = 5000; 267 int uid = pm.getPackageUid(TEST_APP1, 0); 268 final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid); 269 final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid); 270 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 271 final CountDownLatch[] latchHolder = new CountDownLatch[1]; 272 final H handler = new H(Looper.getMainLooper(), latchHolder); 273 final Messenger messenger = new Messenger(handler); 274 final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class); 275 final CountDownLatch dboxLatch = new CountDownLatch(1); 276 final BroadcastReceiver receiver = new BroadcastReceiver() { 277 @Override 278 public void onReceive(Context context, Intent intent) { 279 final String tag_wtf = "system_server_wtf"; 280 if (tag_wtf.equals(intent.getStringExtra(DropBoxManager.EXTRA_TAG))) { 281 final DropBoxManager.Entry e = dbox.getNextEntry(tag_wtf, intent.getLongExtra( 282 DropBoxManager.EXTRA_TIME, 0) - 1); 283 final String text = e.getText(8192); 284 if (TextUtils.isEmpty(text)) { 285 return; 286 } 287 if (text.indexOf("can't store negative values") == -1) { 288 return; 289 } 290 dboxLatch.countDown(); 291 } 292 } 293 }; 294 try { 295 mContext.registerReceiver(receiver, 296 new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED)); 297 am.addOnUidImportanceListener(uidListener1, 298 RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE); 299 am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE); 300 runShellCommand("cmd deviceidle whitelist +" + TEST_APP1); 301 toggleScreenOn(true); 302 303 final Intent intent = new Intent(ACTION_FGS_STATS_TEST); 304 final ComponentName cn = ComponentName.unflattenFromString( 305 TEST_APP1 + "/" + TEST_FGS_CLASS); 306 final Bundle bundle = new Bundle(); 307 intent.setComponent(cn); 308 bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder()); 309 intent.putExtras(bundle); 310 311 latchHolder[0] = new CountDownLatch(1); 312 mContext.startForegroundService(intent); 313 assertTrue("Timed out to start fg service", uidListener1.waitFor( 314 RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, timeout)); 315 assertTrue("Timed out to get the remote messenger", latchHolder[0].await( 316 timeout, TimeUnit.MILLISECONDS)); 317 318 Thread.sleep(timeout); 319 latchHolder[0] = new CountDownLatch(1); 320 handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null); 321 assertTrue("Timed out to wait for stop fg", latchHolder[0].await( 322 timeout, TimeUnit.MILLISECONDS)); 323 324 Thread.sleep(timeout); 325 latchHolder[0] = new CountDownLatch(1); 326 handler.sendRemoteMessage(H.MSG_START_FOREGROUND, 0, 0, null); 327 assertTrue("Timed out to wait for start fg", latchHolder[0].await( 328 timeout, TimeUnit.MILLISECONDS)); 329 330 toggleScreenOn(false); 331 latchHolder[0] = new CountDownLatch(1); 332 handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null); 333 assertTrue("Timed out to wait for stop fg", latchHolder[0].await( 334 timeout, TimeUnit.MILLISECONDS)); 335 assertFalse("There shouldn't be negative values", dboxLatch.await( 336 timeout * 2, TimeUnit.MILLISECONDS)); 337 } finally { 338 toggleScreenOn(true); 339 runShellCommand("cmd deviceidle whitelist -" + TEST_APP1); 340 am.removeOnUidImportanceListener(uidListener1); 341 am.removeOnUidImportanceListener(uidListener2); 342 am.forceStopPackage(TEST_APP1); 343 mContext.unregisterReceiver(receiver); 344 } 345 } 346 347 @LargeTest 348 @Test testAppFreezerWithAllowOomAdj()349 public void testAppFreezerWithAllowOomAdj() throws Exception { 350 final long waitFor = 5000; 351 boolean freezerWasEnabled = isFreezerEnabled(); 352 SettingsSession<String> freezerEnabled = null; 353 SettingsSession<String> amConstantsSettings = null; 354 DeviceConfigSession<Long> freezerDebounceTimeout = null; 355 MyServiceConnection autoConnection = null; 356 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 357 final PackageManager pm = mContext.getPackageManager(); 358 final int uid1 = pm.getPackageUid(TEST_APP1, 0); 359 final int uid2 = pm.getPackageUid(TEST_APP2, 0); 360 final MyUidImportanceListener uid1Listener = new MyUidImportanceListener(uid1); 361 final MyUidImportanceListener uid2Listener = new MyUidImportanceListener(uid2); 362 try { 363 if (!freezerWasEnabled) { 364 freezerEnabled = new SettingsSession<>( 365 Settings.Global.getUriFor(Settings.Global.CACHED_APPS_FREEZER_ENABLED), 366 Settings.Global::getString, Settings.Global::putString); 367 freezerEnabled.set("enabled"); 368 Thread.sleep(waitFor); 369 if (!isFreezerEnabled()) { 370 // Still not enabled? Probably because the device doesn't support it. 371 return; 372 } 373 } 374 freezerDebounceTimeout = new DeviceConfigSession<>( 375 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 376 CachedAppOptimizer.KEY_FREEZER_DEBOUNCE_TIMEOUT, 377 DeviceConfig::getLong, CachedAppOptimizer.DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); 378 freezerDebounceTimeout.set(waitFor); 379 380 final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS; 381 amConstantsSettings = new SettingsSession<>( 382 Settings.Global.getUriFor(activityManagerConstants), 383 Settings.Global::getString, Settings.Global::putString); 384 385 amConstantsSettings.set( 386 ActivityManagerConstants.KEY_MAX_SERVICE_INACTIVITY + "=" + waitFor); 387 388 runShellCommand("cmd deviceidle whitelist +" + TEST_APP1); 389 runShellCommand("cmd deviceidle whitelist +" + TEST_APP2); 390 391 am.addOnUidImportanceListener(uid1Listener, 392 RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE); 393 am.addOnUidImportanceListener(uid2Listener, RunningAppProcessInfo.IMPORTANCE_CACHED); 394 395 final Intent intent = new Intent(); 396 intent.setClassName(TEST_APP1, TEST_CLASS); 397 398 CountDownLatch latch = new CountDownLatch(1); 399 autoConnection = new MyServiceConnection(latch); 400 mContext.bindService(intent, autoConnection, 401 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY); 402 try { 403 assertTrue("Timeout to bind to service " + intent.getComponent(), 404 latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); 405 } catch (InterruptedException e) { 406 fail("Unable to bind to service " + intent.getComponent()); 407 } 408 assertFalse(TEST_APP1 + " shouldn't be frozen now.", isAppFrozen(TEST_APP1)); 409 410 // Trigger oomAdjUpdate/ 411 toggleScreenOn(false); 412 toggleScreenOn(true); 413 414 // Wait for the freezer kick in if there is any. 415 Thread.sleep(waitFor * 4); 416 417 // It still shouldn't be frozen, although it's been in cached state. 418 assertFalse(TEST_APP1 + " shouldn't be frozen now.", isAppFrozen(TEST_APP1)); 419 420 final CountDownLatch[] latchHolder = new CountDownLatch[1]; 421 final IRemoteCallback callback = new IRemoteCallback.Stub() { 422 @Override 423 public void sendResult(Bundle bundle) { 424 if (bundle != null) { 425 latchHolder[0].countDown(); 426 } 427 } 428 }; 429 430 // Bind from app1 to app2 without BIND_WAIVE_PRIORITY. 431 final Bundle extras = new Bundle(); 432 extras.putBinder(EXTRA_CALLBACK, callback.asBinder()); 433 latchHolder[0] = new CountDownLatch(1); 434 sendCommand(COMMAND_BIND_SERVICE, TEST_APP1, TEST_APP2, extras); 435 assertTrue("Timed out to bind to " + TEST_APP2, latchHolder[0].await( 436 waitFor, TimeUnit.MILLISECONDS)); 437 438 // Stop service in app1 439 extras.clear(); 440 sendCommand(COMMAND_STOP_SELF, TEST_APP1, TEST_APP1, extras); 441 442 assertTrue(TEST_APP2 + " should be in cached", uid2Listener.waitFor( 443 RunningAppProcessInfo.IMPORTANCE_CACHED, waitFor)); 444 445 // Wait for the freezer kick in if there is any. 446 Thread.sleep(waitFor * 4); 447 448 // It still shouldn't be frozen, although it's been in cached state. 449 assertFalse(TEST_APP2 + " shouldn't be frozen now.", isAppFrozen(TEST_APP2)); 450 } finally { 451 toggleScreenOn(true); 452 if (amConstantsSettings != null) { 453 amConstantsSettings.close(); 454 } 455 if (freezerEnabled != null) { 456 freezerEnabled.close(); 457 } 458 if (freezerDebounceTimeout != null) { 459 freezerDebounceTimeout.close(); 460 } 461 if (autoConnection != null) { 462 mContext.unbindService(autoConnection); 463 } 464 am.removeOnUidImportanceListener(uid1Listener); 465 am.removeOnUidImportanceListener(uid2Listener); 466 sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP1, TEST_APP2, null); 467 sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP2, TEST_APP1, null); 468 runShellCommand("cmd deviceidle whitelist -" + TEST_APP1); 469 runShellCommand("cmd deviceidle whitelist -" + TEST_APP2); 470 } 471 } 472 sendCommand(int command, String sourcePkg, String targetPkg, Bundle extras)473 private void sendCommand(int command, String sourcePkg, String targetPkg, Bundle extras) { 474 final Intent intent = new Intent(); 475 intent.setClassName(sourcePkg, TEST_CLASS); 476 intent.putExtra(EXTRA_COMMAND, command); 477 intent.putExtra(EXTRA_TARGET_PACKAGE, targetPkg); 478 if (extras != null) { 479 intent.putExtras(extras); 480 } 481 mContext.startService(intent); 482 } 483 isFreezerEnabled()484 private boolean isFreezerEnabled() throws Exception { 485 final String output = runShellCommand("dumpsys activity settings"); 486 final Matcher matcher = Pattern.compile("\\b" + CachedAppOptimizer.KEY_USE_FREEZER 487 + "\\b=\\b(true|false)\\b").matcher(output); 488 if (matcher.find()) { 489 return Boolean.parseBoolean(matcher.group(1)); 490 } 491 return false; 492 } 493 isAppFrozen(String packageName)494 private boolean isAppFrozen(String packageName) throws Exception { 495 final String output = runShellCommand("dumpsys activity p " + packageName); 496 final Matcher matcher = Pattern.compile("\\b" + ProcessCachedOptimizerRecord.IS_FROZEN 497 + "\\b=\\b(true|false)\\b").matcher(output); 498 if (matcher.find()) { 499 return Boolean.parseBoolean(matcher.group(1)); 500 } 501 return false; 502 } 503 504 @Ignore("Need to disable calling uid check in ActivityManagerService.killPids before this test") 505 @Test testKillPids()506 public void testKillPids() throws Exception { 507 final long timeout = 5000; 508 final long shortTimeout = 2000; 509 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 510 final PackageManager pm = mContext.getPackageManager(); 511 final int uid1 = pm.getPackageUid(TEST_APP1, 0); 512 final int uid2 = pm.getPackageUid(TEST_APP2, 0); 513 final int uid3 = pm.getPackageUid(TEST_APP3, 0); 514 final MyUidImportanceListener uid1Listener1 = new MyUidImportanceListener(uid1); 515 final MyUidImportanceListener uid1Listener2 = new MyUidImportanceListener(uid1); 516 final MyUidImportanceListener uid2Listener1 = new MyUidImportanceListener(uid2); 517 final MyUidImportanceListener uid2Listener2 = new MyUidImportanceListener(uid2); 518 final MyUidImportanceListener uid3Listener1 = new MyUidImportanceListener(uid3); 519 final MyUidImportanceListener uid3Listener2 = new MyUidImportanceListener(uid3); 520 try { 521 am.addOnUidImportanceListener(uid1Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 522 am.addOnUidImportanceListener(uid1Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 523 am.addOnUidImportanceListener(uid2Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 524 am.addOnUidImportanceListener(uid2Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 525 am.addOnUidImportanceListener(uid3Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 526 am.addOnUidImportanceListener(uid3Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 527 runShellCommand("cmd deviceidle whitelist +" + TEST_APP1); 528 runShellCommand("cmd deviceidle whitelist +" + TEST_APP2); 529 runShellCommand("cmd deviceidle whitelist +" + TEST_APP3); 530 final int[] pids = new int[3]; 531 // Test sync kills 532 pids[0] = startTargetService(am, TEST_APP1, TEST_CLASS, uid1, TEST_APP1, 533 uid1Listener1, timeout); 534 pids[1] = startTargetService(am, TEST_APP2, TEST_CLASS, uid2, TEST_APP2, 535 uid2Listener1, timeout); 536 pids[2] = startTargetService(am, TEST_APP3, TEST_CLASS, uid3, TEST_APP3, 537 uid3Listener1, timeout); 538 Thread.sleep(shortTimeout); 539 mService.killPids(pids, "testKillPids", false); 540 assertTrue("Timed out to kill process", uid1Listener2.waitFor( 541 RunningAppProcessInfo.IMPORTANCE_GONE, timeout)); 542 assertTrue("Timed out to kill process", uid2Listener2.waitFor( 543 RunningAppProcessInfo.IMPORTANCE_GONE, timeout)); 544 assertTrue("Timed out to kill process", uid3Listener2.waitFor( 545 RunningAppProcessInfo.IMPORTANCE_GONE, timeout)); 546 } finally { 547 runShellCommand("cmd deviceidle whitelist -" + TEST_APP1); 548 runShellCommand("cmd deviceidle whitelist -" + TEST_APP2); 549 runShellCommand("cmd deviceidle whitelist -" + TEST_APP3); 550 am.removeOnUidImportanceListener(uid1Listener1); 551 am.removeOnUidImportanceListener(uid1Listener2); 552 am.removeOnUidImportanceListener(uid2Listener1); 553 am.removeOnUidImportanceListener(uid2Listener2); 554 am.removeOnUidImportanceListener(uid3Listener1); 555 am.removeOnUidImportanceListener(uid3Listener2); 556 am.forceStopPackage(TEST_APP1); 557 am.forceStopPackage(TEST_APP2); 558 am.forceStopPackage(TEST_APP3); 559 } 560 } 561 startTargetService(ActivityManager am, String targetPakage, String targetService, int targetUid, String targetProcessName, MyUidImportanceListener uidListener, long timeout)562 private int startTargetService(ActivityManager am, String targetPakage, String targetService, 563 int targetUid, String targetProcessName, MyUidImportanceListener uidListener, 564 long timeout) throws Exception { 565 final Intent intent = new Intent(); 566 intent.setComponent(ComponentName.unflattenFromString(targetPakage + "/" + targetService)); 567 mContext.startService(intent); 568 assertTrue("Timed out to start service", uidListener.waitFor( 569 RunningAppProcessInfo.IMPORTANCE_SERVICE, timeout)); 570 final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); 571 for (int i = processes.size() - 1; i >= 0; i--) { 572 final RunningAppProcessInfo info = processes.get(i); 573 if (info.uid == targetUid && targetProcessName.equals(info.processName)) { 574 return info.pid; 575 } 576 } 577 return -1; 578 } 579 580 @Test testGetIsolatedProcesses()581 public void testGetIsolatedProcesses() throws Exception { 582 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 583 final PackageManager pm = mContext.getPackageManager(); 584 final int uid1 = pm.getPackageUid(TEST_APP1, 0); 585 final int uid2 = pm.getPackageUid(TEST_APP2, 0); 586 final int uid3 = pm.getPackageUid(TEST_APP3, 0); 587 final List<Pair<Integer, ServiceConnection>> uid1Processes = new ArrayList<>(); 588 final List<Pair<Integer, ServiceConnection>> uid2Processes = new ArrayList<>(); 589 try { 590 assertTrue("There shouldn't be any isolated process for " + TEST_APP1, 591 getIsolatedProcesses(uid1).isEmpty()); 592 assertTrue("There shouldn't be any isolated process for " + TEST_APP2, 593 getIsolatedProcesses(uid2).isEmpty()); 594 assertTrue("There shouldn't be any isolated process for " + TEST_APP3, 595 getIsolatedProcesses(uid3).isEmpty()); 596 597 // Verify uid1 598 uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1)); 599 uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1)); 600 uid1Processes.add(createIsolatedProcessAndVerify(TEST_APP1, uid1)); 601 verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1)); 602 603 // Let one of the processes go 604 final Pair<Integer, ServiceConnection> uid1P2 = uid1Processes.remove(2); 605 mContext.unbindService(uid1P2.second); 606 Thread.sleep(5_000); // Wait for the process gone. 607 verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1)); 608 609 // Verify uid2 610 uid2Processes.add(createIsolatedProcessAndVerify(TEST_APP2, uid2)); 611 verifyIsolatedProcesses(uid2Processes, getIsolatedProcesses(uid2)); 612 613 // Verify uid1 again 614 verifyIsolatedProcesses(uid1Processes, getIsolatedProcesses(uid1)); 615 616 // Verify uid3 617 assertTrue("There shouldn't be any isolated process for " + TEST_APP3, 618 getIsolatedProcesses(uid3).isEmpty()); 619 } finally { 620 for (Pair<Integer, ServiceConnection> p: uid1Processes) { 621 mContext.unbindService(p.second); 622 } 623 for (Pair<Integer, ServiceConnection> p: uid2Processes) { 624 mContext.unbindService(p.second); 625 } 626 am.forceStopPackage(TEST_APP1); 627 am.forceStopPackage(TEST_APP2); 628 am.forceStopPackage(TEST_APP3); 629 } 630 } 631 getIsolatedProcesses(int uid)632 private static List<Integer> getIsolatedProcesses(int uid) throws Exception { 633 final String output = runShellCommand("am get-isolated-pids " + uid); 634 final Matcher matcher = Pattern.compile("(\\d+)").matcher(output); 635 final List<Integer> pids = new ArrayList<>(); 636 while (matcher.find()) { 637 pids.add(Integer.parseInt(output.substring(matcher.start(), matcher.end()))); 638 } 639 return pids; 640 } 641 verifyIsolatedProcesses(List<Pair<Integer, ServiceConnection>> processes, List<Integer> pids)642 private void verifyIsolatedProcesses(List<Pair<Integer, ServiceConnection>> processes, 643 List<Integer> pids) { 644 final List<Integer> l = processes.stream().map(p -> p.first).collect(Collectors.toList()); 645 assertTrue("Isolated processes don't match", l.containsAll(pids)); 646 assertTrue("Isolated processes don't match", pids.containsAll(l)); 647 } 648 createIsolatedProcessAndVerify(String pkgName, int uid)649 private Pair<Integer, ServiceConnection> createIsolatedProcessAndVerify(String pkgName, int uid) 650 throws Exception { 651 final Pair<Integer, ServiceConnection> p = createIsolatedProcess(pkgName); 652 final List<Integer> pids = getIsolatedProcesses(uid); 653 assertTrue("Can't find the isolated pid " + p.first + " for " + pkgName, 654 pids.contains(p.first)); 655 return p; 656 } 657 createIsolatedProcess(String pkgName)658 private Pair<Integer, ServiceConnection> createIsolatedProcess(String pkgName) 659 throws Exception { 660 final int[] pid = new int[1]; 661 final CountDownLatch[] latch = new CountDownLatch[1]; 662 final ServiceConnection conn = new ServiceConnection() { 663 @Override 664 public void onServiceConnected(ComponentName name, IBinder service) { 665 final IRemoteCallback s = IRemoteCallback.Stub.asInterface(service); 666 final IBinder callback = new Binder() { 667 @Override 668 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 669 throws RemoteException { 670 if (code == Binder.FIRST_CALL_TRANSACTION) { 671 pid[0] = data.readInt(); 672 latch[0].countDown(); 673 return true; 674 } 675 return super.onTransact(code, data, reply, flags); 676 } 677 }; 678 try { 679 final Bundle extra = new Bundle(); 680 extra.putBinder(EXTRA_CALLBACK, callback); 681 s.sendResult(extra); 682 } catch (RemoteException e) { 683 fail("Unable to call into isolated process"); 684 } 685 } 686 @Override 687 public void onServiceDisconnected(ComponentName name) { 688 } 689 }; 690 final Intent intent = new Intent(); 691 intent.setClassName(pkgName, TEST_ISOLATED_CLASS); 692 latch[0] = new CountDownLatch(1); 693 assertTrue("Unable to create isolated process in " + pkgName, 694 mContext.bindIsolatedService(intent, Context.BIND_AUTO_CREATE, 695 Long.toString(SystemClock.uptimeMillis()), mContext.getMainExecutor(), conn)); 696 assertTrue("Timeout to bind to service " + intent.getComponent(), 697 latch[0].await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); 698 return Pair.create(pid[0], conn); 699 } 700 701 /** 702 * Make sure the screen state. 703 */ toggleScreenOn(final boolean screenon)704 private void toggleScreenOn(final boolean screenon) throws Exception { 705 if (screenon) { 706 runShellCommand("input keyevent KEYCODE_WAKEUP"); 707 runShellCommand("wm dismiss-keyguard"); 708 } else { 709 runShellCommand("input keyevent KEYCODE_SLEEP"); 710 } 711 // Since the screen on/off intent is ordered, they will not be sent right now. 712 Thread.sleep(2_000); 713 } 714 715 private class H extends Handler { 716 static final int MSG_INIT = 0; 717 static final int MSG_DONE = 1; 718 static final int MSG_START_FOREGROUND = 2; 719 static final int MSG_STOP_FOREGROUND = 3; 720 721 private Messenger mRemoteMessenger; 722 private CountDownLatch[] mLatchHolder; 723 H(Looper looper, CountDownLatch[] latchHolder)724 H(Looper looper, CountDownLatch[] latchHolder) { 725 super(looper); 726 mLatchHolder = latchHolder; 727 } 728 729 @Override handleMessage(Message msg)730 public void handleMessage(Message msg) { 731 switch (msg.what) { 732 case MSG_INIT: 733 mRemoteMessenger = (Messenger) msg.obj; 734 mLatchHolder[0].countDown(); 735 break; 736 case MSG_DONE: 737 mLatchHolder[0].countDown(); 738 break; 739 } 740 } 741 sendRemoteMessage(int what, int arg1, int arg2, Object obj)742 void sendRemoteMessage(int what, int arg1, int arg2, Object obj) { 743 Message msg = Message.obtain(); 744 msg.what = what; 745 msg.arg1 = arg1; 746 msg.arg2 = arg2; 747 msg.obj = obj; 748 try { 749 mRemoteMessenger.send(msg); 750 } catch (RemoteException e) { 751 } 752 msg.recycle(); 753 } 754 } 755 756 private static class MyUidImportanceListener implements OnUidImportanceListener { 757 final CountDownLatch[] mLatchHolder = new CountDownLatch[1]; 758 private final int mExpectedUid; 759 private int mExpectedImportance; 760 private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE; 761 MyUidImportanceListener(int uid)762 MyUidImportanceListener(int uid) { 763 mExpectedUid = uid; 764 } 765 766 @Override onUidImportance(int uid, int importance)767 public void onUidImportance(int uid, int importance) { 768 if (uid == mExpectedUid) { 769 synchronized (this) { 770 if (importance == mExpectedImportance && mLatchHolder[0] != null) { 771 mLatchHolder[0].countDown(); 772 } 773 mCurrentImportance = importance; 774 } 775 Log.i(TAG, "uid " + uid + " importance: " + importance); 776 } 777 } 778 waitFor(int expectedImportance, long timeout)779 boolean waitFor(int expectedImportance, long timeout) throws Exception { 780 synchronized (this) { 781 mExpectedImportance = expectedImportance; 782 if (mCurrentImportance == expectedImportance) { 783 return true; 784 } 785 mLatchHolder[0] = new CountDownLatch(1); 786 } 787 return mLatchHolder[0].await(timeout, TimeUnit.MILLISECONDS); 788 } 789 } 790 } 791