1 /* 2 * Copyright (C) 2019 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 android.app.cts; 18 19 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 20 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertNotNull; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 import static org.junit.Assume.assumeTrue; 29 30 import android.Manifest; 31 import android.app.Activity; 32 import android.app.ActivityManager; 33 import android.app.ActivityManager.RunningAppProcessInfo; 34 import android.app.ApplicationExitInfo; 35 import android.app.Instrumentation; 36 import android.app.cts.android.app.cts.tools.WatchUidRunner; 37 import android.app.stubs.IHeartbeat; 38 import android.content.BroadcastReceiver; 39 import android.content.ComponentName; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.IntentFilter; 43 import android.content.ServiceConnection; 44 import android.content.pm.PackageManager; 45 import android.externalservice.common.RunningServiceInfo; 46 import android.externalservice.common.ServiceMessages; 47 import android.os.AsyncTask; 48 import android.os.Binder; 49 import android.os.Build; 50 import android.os.Bundle; 51 import android.os.DropBoxManager; 52 import android.os.Handler; 53 import android.os.HandlerThread; 54 import android.os.IBinder; 55 import android.os.Looper; 56 import android.os.Message; 57 import android.os.Messenger; 58 import android.os.Process; 59 import android.os.RemoteException; 60 import android.os.SystemClock; 61 import android.os.SystemProperties; 62 import android.os.UserHandle; 63 import android.os.UserManager; 64 import android.provider.Settings; 65 import android.server.wm.settings.SettingsSession; 66 import android.system.OsConstants; 67 import android.text.TextUtils; 68 import android.util.DebugUtils; 69 import android.util.Log; 70 import android.util.Pair; 71 72 import androidx.test.ext.junit.runners.AndroidJUnit4; 73 import androidx.test.platform.app.InstrumentationRegistry; 74 75 import com.android.compatibility.common.util.AmMonitor; 76 import com.android.compatibility.common.util.ApiLevelUtil; 77 import com.android.compatibility.common.util.CddTest; 78 import com.android.compatibility.common.util.PollingCheck; 79 import com.android.compatibility.common.util.ShellIdentityUtils; 80 import com.android.compatibility.common.util.SystemUtil; 81 import com.android.internal.util.ArrayUtils; 82 import com.android.internal.util.MemInfoReader; 83 import com.android.server.os.TombstoneProtos.Tombstone; 84 85 import org.junit.After; 86 import org.junit.Before; 87 import org.junit.Test; 88 import org.junit.runner.RunWith; 89 90 import java.io.BufferedInputStream; 91 import java.io.IOException; 92 import java.io.InputStream; 93 import java.util.ArrayList; 94 import java.util.List; 95 import java.util.concurrent.CountDownLatch; 96 import java.util.concurrent.TimeUnit; 97 import java.util.regex.Matcher; 98 import java.util.regex.Pattern; 99 100 @RunWith(AndroidJUnit4.class) 101 public final class ActivityManagerAppExitInfoTest { 102 private static final String TAG = ActivityManagerAppExitInfoTest.class.getSimpleName(); 103 104 public static final boolean FIRST_SDK_IS_AT_LEAST_U = 105 ApiLevelUtil.isFirstApiAfter(Build.VERSION_CODES.TIRAMISU); 106 107 private static final String STUB_PACKAGE_NAME = 108 "com.android.cts.launcherapps.simpleapp"; 109 private static final String STUB_SERVICE_NAME = 110 "com.android.cts.launcherapps.simpleapp.SimpleService4"; 111 private static final String STUB_SERVICE_REMOTE_NAME = 112 "com.android.cts.launcherapps.simpleapp.SimpleService5"; 113 private static final String STUB_SERVICE_ISOLATED_NAME = 114 "com.android.cts.launcherapps.simpleapp.SimpleService6"; 115 private static final String STUB_RECEIVER_NAME = 116 "com.android.cts.launcherapps.simpleapp.SimpleReceiver"; 117 private static final String STUB_PROCESS_NAME = STUB_PACKAGE_NAME; 118 private static final String STUB_REMOTE_PROCESS_NAME = STUB_PROCESS_NAME + ":remote"; 119 private static final String SIMPLE_ACTIVITY = ".SimpleActivity"; 120 121 private static final String HEARTBEAT_PACKAGE = "android.app.stubs"; 122 private static final String HEARTBEAT_PROCESS = HEARTBEAT_PACKAGE + ":hbact"; 123 private static final String HEARTBEAT_ACTIVITY = HEARTBEAT_PACKAGE + ".HeartbeatActivity"; 124 private static final String HEARTBEAT_SERVICE = HEARTBEAT_PACKAGE + ".HeartbeatService"; 125 private static final String HEARTBEAT_PROCESS_DEAD = "dead"; 126 private static final String HEARTBEAT_COUNTDOWN_NAME = "countdown"; 127 private static final String HEARTBEAT_INTERVAL_NAME = "interval"; 128 private static final int HEARTBEAT_COUNTDOWN = 15; 129 private static final long HEARTBEAT_INTERVAL = 1000; 130 private static final long HEARTBEAT_FREEZER_LONG = 30000; 131 private static final long HEARTBEAT_FREEZER_SHORT = 5000; 132 private static final long FREEZER_TIMEOUT_FLOOR = 10000; 133 134 private static final String EXIT_ACTION = 135 "com.android.cts.launchertests.simpleapp.EXIT_ACTION"; 136 private static final String EXTRA_ACTION = "action"; 137 private static final String EXTRA_MESSENGER = "messenger"; 138 private static final String EXTRA_PROCESS_NAME = "process"; 139 private static final String EXTRA_COOKIE = "cookie"; 140 141 private static final int ACTION_NONE = 0; 142 private static final int ACTION_FINISH = 1; 143 private static final int ACTION_EXIT = 2; 144 private static final int ACTION_ANR = 3; 145 private static final int ACTION_NATIVE_CRASH = 4; 146 private static final int ACTION_KILL = 5; 147 private static final int ACTION_ACQUIRE_STABLE_PROVIDER = 6; 148 private static final int ACTION_KILL_PROVIDER = 7; 149 private static final int EXIT_CODE = 123; 150 private static final int CRASH_SIGNAL = OsConstants.SIGSEGV; 151 152 private static final long TOMBSTONE_FETCH_TIMEOUT_MS = 10_000; 153 154 private static final long WAITFOR_MSEC = 10000; 155 private static final long WAITFOR_SETTLE_DOWN = 2000; 156 157 private static final int CMD_PID = 1; 158 159 private Context mContext; 160 private Instrumentation mInstrumentation; 161 private int mStubPackageUid; 162 private int mStubPackagePid; 163 private int mStubPackageRemotePid; 164 private int mStubPackageOtherUid; 165 private int mStubPackageOtherUserPid; 166 private int mStubPackageRemoteOtherUserPid; 167 private int mStubPackageIsolatedUid; 168 private int mStubPackageIsolatedPid; 169 private String mStubPackageIsolatedProcessName; 170 private WatchUidRunner mWatcher; 171 private WatchUidRunner mOtherUidWatcher; 172 private ActivityManager mActivityManager; 173 private CountDownLatch mLatch; 174 private UserManager mUserManager; 175 private HandlerThread mHandlerThread; 176 private Handler mHandler; 177 private Messenger mMessenger; 178 private boolean mSupportMultipleUsers; 179 private int mCurrentUserId; 180 private UserHandle mCurrentUserHandle; 181 private int mOtherUserId; 182 private UserHandle mOtherUserHandle; 183 private DropBoxManager.Entry mAnrEntry; 184 private SettingsSession<String> mDataAnrSettings; 185 private SettingsSession<String> mHiddenApiSettings; 186 private int mProcSeqNum; 187 private String mFreezerTimeout; 188 private boolean mHeartbeatDead; 189 190 @Before setUp()191 public void setUp() throws Exception { 192 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 193 mContext = mInstrumentation.getContext(); 194 mStubPackageUid = mContext.getPackageManager().getPackageUid(STUB_PACKAGE_NAME, 0); 195 mWatcher = new WatchUidRunner(mInstrumentation, mStubPackageUid, WAITFOR_MSEC); 196 mActivityManager = mContext.getSystemService(ActivityManager.class); 197 mUserManager = UserManager.get(mContext); 198 mCurrentUserId = UserHandle.getUserId(Process.myUid()); 199 mCurrentUserHandle = Process.myUserHandle(); 200 mSupportMultipleUsers = mUserManager.supportsMultipleUsers(); 201 mHandlerThread = new HandlerThread("receiver"); 202 mHandlerThread.start(); 203 mHandler = new H(mHandlerThread.getLooper()); 204 mMessenger = new Messenger(mHandler); 205 executeShellCmd("cmd deviceidle whitelist +" + STUB_PACKAGE_NAME); 206 executeShellCmd("cmd deviceidle whitelist +" + HEARTBEAT_PACKAGE); 207 mDataAnrSettings = new SettingsSession<>( 208 Settings.Global.getUriFor( 209 Settings.Global.DROPBOX_TAG_PREFIX + "data_app_anr"), 210 Settings.Global::getString, Settings.Global::putString); 211 mDataAnrSettings.set("enabled"); 212 mHiddenApiSettings = new SettingsSession<>( 213 Settings.Global.getUriFor( 214 Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS), 215 Settings.Global::getString, Settings.Global::putString); 216 mHiddenApiSettings.set("*"); 217 mFreezerTimeout = executeShellCmd( 218 "device_config get activity_manager_native_boot freeze_debounce_timeout"); 219 220 mInstrumentation.getUiAutomation().adoptShellPermissionIdentity( 221 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); 222 mContext.getPackageManager().setApplicationEnabledSetting( 223 STUB_PACKAGE_NAME, 224 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 225 0); 226 } 227 handleMessagePid(Message msg)228 private void handleMessagePid(Message msg) { 229 boolean didSomething = false; 230 Bundle b = (Bundle) msg.obj; 231 String processName = b.getString(EXTRA_PROCESS_NAME); 232 233 if (STUB_PROCESS_NAME.equals(processName)) { 234 if (mOtherUserId != 0 && UserHandle.getUserId(msg.arg2) == mOtherUserId) { 235 mStubPackageOtherUserPid = msg.arg1; 236 assertTrue(mStubPackageOtherUserPid > 0); 237 } else { 238 mStubPackagePid = msg.arg1; 239 assertTrue(mStubPackagePid > 0); 240 } 241 } else if (STUB_REMOTE_PROCESS_NAME.equals(processName)) { 242 if (mOtherUserId != 0 && UserHandle.getUserId(msg.arg2) == mOtherUserId) { 243 mStubPackageRemoteOtherUserPid = msg.arg1; 244 assertTrue(mStubPackageRemoteOtherUserPid > 0); 245 } else { 246 mStubPackageRemotePid = msg.arg1; 247 assertTrue(mStubPackageRemotePid > 0); 248 } 249 } else if (HEARTBEAT_PROCESS.equals(processName)) { 250 mStubPackagePid = msg.arg1; 251 mStubPackageUid = msg.arg2; 252 mHeartbeatDead = b.getBoolean(HEARTBEAT_PROCESS_DEAD); 253 assertTrue(mStubPackagePid > 0); 254 assertTrue(mStubPackageUid > 0); 255 } else { // must be isolated process 256 mStubPackageIsolatedPid = msg.arg1; 257 mStubPackageIsolatedUid = msg.arg2; 258 mStubPackageIsolatedProcessName = processName; 259 assertTrue(mStubPackageIsolatedPid > 0); 260 assertTrue(mStubPackageIsolatedUid > 0); 261 assertNotNull(processName); 262 } 263 264 if (mLatch != null) { 265 Log.d(TAG, "Counting down latch on message " + msg + " for process " + processName); 266 mLatch.countDown(); 267 } 268 } 269 270 private class H extends Handler { H(Looper looper)271 H(Looper looper) { 272 super(looper); 273 } 274 275 @Override handleMessage(Message msg)276 public void handleMessage(Message msg) { 277 switch (msg.what) { 278 case CMD_PID: 279 handleMessagePid(msg); 280 break; 281 default: 282 break; 283 } 284 } 285 } 286 287 @After tearDown()288 public void tearDown() throws Exception { 289 mWatcher.finish(); 290 executeShellCmd( 291 "device_config put activity_manager_native_boot freeze_debounce_timeout " 292 + mFreezerTimeout); 293 executeShellCmd("cmd deviceidle whitelist -" + STUB_PACKAGE_NAME); 294 executeShellCmd("cmd deviceidle whitelist -" + HEARTBEAT_PACKAGE); 295 executeShellCmd("am force-stop " + STUB_PACKAGE_NAME); 296 executeShellCmd("am force-stop " + HEARTBEAT_PACKAGE); 297 mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); 298 299 removeTestUserIfNecessary(); 300 mHandlerThread.quitSafely(); 301 if (mDataAnrSettings != null) { 302 mDataAnrSettings.close(); 303 } 304 if (mHiddenApiSettings != null) { 305 mHiddenApiSettings.close(); 306 } 307 } 308 createUser(String name, boolean guest)309 private int createUser(String name, boolean guest) throws Exception { 310 final String output = executeShellCmd( 311 "pm create-user " + (guest ? "--guest " : "") + name); 312 if (output.startsWith("Success")) { 313 int userId = Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()); 314 Log.i(TAG, "Created user with id " + userId); 315 return userId; 316 } 317 throw new IllegalStateException(String.format("Failed to create user: %s", output)); 318 } 319 removeUser(final int userId)320 private boolean removeUser(final int userId) throws Exception { 321 final String output = executeShellCmd("pm remove-user %s", userId); 322 if (output.startsWith("Error")) { 323 Log.w(TAG, "Failed to remove user: " + output); 324 return false; 325 } 326 return true; 327 } 328 startUser(int userId, boolean waitFlag)329 private boolean startUser(int userId, boolean waitFlag) throws Exception { 330 String cmd = "am start-user " + (waitFlag ? "-w " : "") + userId; 331 332 final String output = executeShellCmd(cmd); 333 if (output.startsWith("Error")) { 334 Log.w(TAG, "Failed to start user: " + output); 335 return false; 336 } 337 if (waitFlag) { 338 String state = executeShellCmd("am get-started-user-state " + userId); 339 if (!state.contains("RUNNING_UNLOCKED")) { 340 return false; 341 } 342 } 343 return true; 344 } 345 stopUser(int userId, boolean waitFlag, boolean forceFlag)346 private boolean stopUser(int userId, boolean waitFlag, boolean forceFlag) 347 throws Exception { 348 StringBuilder cmd = new StringBuilder("am stop-user "); 349 if (waitFlag) { 350 cmd.append("-w "); 351 } 352 if (forceFlag) { 353 cmd.append("-f "); 354 } 355 cmd.append(userId); 356 357 final String output = executeShellCmd(cmd.toString()); 358 if (output.contains("Error: Can't stop system user")) { 359 return false; 360 } 361 return true; 362 } 363 installExistingPackageAsUser(String packageName, int userId)364 private void installExistingPackageAsUser(String packageName, int userId) 365 throws Exception { 366 367 // Makes sure package doesn't exist yet, otherwise pm install will hang 368 assertWithMessage("package %s for user %s exists", packageName, userId) 369 .that(isPackageInstalledAsUser(packageName, userId)).isFalse(); 370 371 Log.i(TAG, "installing existing " + packageName + " on user" + userId); 372 executeShellCmd("pm install-existing --user %d --wait %s", userId, packageName); 373 } 374 isPackageInstalledAsUser(String packageName, int userId)375 private boolean isPackageInstalledAsUser(String packageName, int userId) throws Exception { 376 String output = executeShellCmd("pm list packages --user %d %s", userId, packageName); 377 return output.contains("package:" + packageName + "\n"); 378 } 379 executeShellCmd(String cmdFormat, Object... args)380 private String executeShellCmd(String cmdFormat, Object... args) throws Exception { 381 String cmd = String.format(cmdFormat, args); 382 String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 383 Log.d(TAG, String.format("Output for '%s': %s", cmd, result)); 384 return result; 385 } 386 awaitForLatch(CountDownLatch latch, String reasonFormat, Object... reasonArgs)387 private void awaitForLatch(CountDownLatch latch, String reasonFormat, 388 Object... reasonArgs) { 389 awaitForLatch(latch, WAITFOR_MSEC, reasonFormat, reasonArgs); 390 } 391 awaitForLatch(CountDownLatch latch, long timeout, String reasonFormat, Object... reasonArgs)392 private void awaitForLatch(CountDownLatch latch, long timeout, String reasonFormat, 393 Object... reasonArgs) { 394 String reason = String.format(reasonFormat, reasonArgs); 395 Log.d(TAG, "waiting " + WAITFOR_MSEC + " for " + reason); 396 try { 397 assertTrue("Timeout for waiting", latch.await(timeout, TimeUnit.MILLISECONDS)); 398 Log.d(TAG, "latch counted down"); 399 } catch (InterruptedException e) { 400 Thread.currentThread().interrupt(); 401 fail("Interrupted"); 402 } 403 } 404 405 // Start the target package startService(int commandCode, String serviceName, boolean waitForGone, boolean other)406 private void startService(int commandCode, String serviceName, boolean waitForGone, 407 boolean other) { 408 startService(commandCode, serviceName, waitForGone, true, other, false, null); 409 } 410 startService(int commandCode, String serviceName, boolean waitForGone, boolean waitForIdle, boolean other, boolean includeCookie, byte[] cookie)411 private void startService(int commandCode, String serviceName, boolean waitForGone, 412 boolean waitForIdle, boolean other, boolean includeCookie, byte[] cookie) { 413 Intent intent = new Intent(EXIT_ACTION); 414 intent.setClassName(STUB_PACKAGE_NAME, serviceName); 415 intent.putExtra(EXTRA_ACTION, commandCode); 416 intent.putExtra(EXTRA_MESSENGER, mMessenger); 417 if (includeCookie) { 418 intent.putExtra(EXTRA_COOKIE, cookie); 419 } 420 mLatch = new CountDownLatch(1); 421 UserHandle user = other ? mOtherUserHandle : mCurrentUserHandle; 422 WatchUidRunner watcher = other ? mOtherUidWatcher : mWatcher; 423 Log.i(TAG, "Starting service " + serviceName + ": waitForGone=" + waitForGone 424 + ", waitForIdle=" + waitForIdle + ",intent=" + intent + ", user=" + user); 425 mContext.startServiceAsUser(intent, user); 426 if (waitForIdle) { 427 watcher.waitFor(WatchUidRunner.CMD_IDLE, null); 428 } 429 if (waitForGone) { 430 waitForGone(watcher); 431 } 432 awaitForLatch(mLatch, "service %s to start on user %s", serviceName, user); 433 } 434 startIsolatedService(int commandCode, String serviceName)435 private void startIsolatedService(int commandCode, String serviceName) { 436 Intent intent = new Intent(EXIT_ACTION); 437 intent.setClassName(STUB_PACKAGE_NAME, serviceName); 438 intent.putExtra(EXTRA_ACTION, commandCode); 439 intent.putExtra(EXTRA_MESSENGER, mMessenger); 440 mLatch = new CountDownLatch(1); 441 mContext.startServiceAsUser(intent, mCurrentUserHandle); 442 awaitForLatch(mLatch, "service %s to start", serviceName); 443 } 444 waitForGone(WatchUidRunner watcher)445 private void waitForGone(WatchUidRunner watcher) { 446 watcher.waitFor(WatchUidRunner.CMD_GONE, null); 447 // Give a few seconds to generate the exit report. 448 sleep(WAITFOR_SETTLE_DOWN); 449 } 450 clearHistoricalExitInfo()451 private void clearHistoricalExitInfo() throws Exception { 452 executeShellCmd("am clear-exit-info --user all " + STUB_PACKAGE_NAME); 453 } 454 sleep(long timeout)455 private void sleep(long timeout) { 456 try { 457 Thread.sleep(timeout); 458 } catch (InterruptedException e) { 459 } 460 } 461 getHistoricalProcessExitReasonsAsUser( final String packageName, final int pid, final int max, final int userId)462 private List<ApplicationExitInfo> getHistoricalProcessExitReasonsAsUser( 463 final String packageName, final int pid, final int max, final int userId) { 464 Context context = mContext.createContextAsUser(UserHandle.of(userId), 0); 465 ActivityManager am = context.getSystemService(ActivityManager.class); 466 return am.getHistoricalProcessExitReasons(packageName, pid, max); 467 } 468 469 @Test testExitCode()470 public void testExitCode() throws Exception { 471 // Remove old records to avoid interference with the test. 472 clearHistoricalExitInfo(); 473 474 long now = System.currentTimeMillis(); 475 // Start a process and let it call System.exit() right away. 476 startService(ACTION_EXIT, STUB_SERVICE_NAME, true, false); 477 478 long now2 = System.currentTimeMillis(); 479 // Query with the current package name, but the mStubPackagePid belongs to the 480 // target package, so the below call should return an empty result. 481 List<ApplicationExitInfo> list = null; 482 try { 483 list = mActivityManager.getHistoricalProcessExitReasons( 484 STUB_PACKAGE_NAME, mStubPackagePid, 1); 485 fail("Shouldn't be able to query other package"); 486 } catch (SecurityException e) { 487 // expected 488 } 489 490 // Now query with the advanced version 491 try { 492 list = getHistoricalProcessExitReasonsAsUser(STUB_PACKAGE_NAME, 493 mStubPackagePid, 1, mCurrentUserId); 494 fail("Shouldn't be able to query other package"); 495 } catch (SecurityException e) { 496 // expected 497 } 498 499 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 500 STUB_PACKAGE_NAME, mStubPackagePid, 1, mCurrentUserId, 501 this::getHistoricalProcessExitReasonsAsUser, 502 android.Manifest.permission.DUMP); 503 504 assertTrue(list != null && list.size() == 1); 505 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 506 ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2); 507 } 508 fillUpMemoryAndCheck( final MemoryConsumerService.TestFuncInterface testFunc, final List<ApplicationExitInfo> list)509 private List<ServiceConnection> fillUpMemoryAndCheck( 510 final MemoryConsumerService.TestFuncInterface testFunc, 511 final List<ApplicationExitInfo> list) throws Exception { 512 final String procNamePrefix = "memconsumer_"; 513 final ArrayList<ServiceConnection> memConsumers = new ArrayList<>(); 514 Pair<IBinder, ServiceConnection> p = MemoryConsumerService.bindToService( 515 mContext, testFunc, procNamePrefix + mProcSeqNum++); 516 IBinder consumer = p.first; 517 memConsumers.add(p.second); 518 519 while (list.size() == 0) { 520 // Get the meminfo firstly 521 MemInfoReader reader = new MemInfoReader(); 522 reader.readMemInfo(); 523 524 long totalMb = (reader.getFreeSizeKb() + reader.getCachedSizeKb()) >> 10; 525 if (!MemoryConsumerService.runOnce(consumer, totalMb) && list.size() == 0) { 526 // Need to create a new consumer (the present one might be running out of space) 527 p = MemoryConsumerService.bindToService(mContext, testFunc, 528 procNamePrefix + mProcSeqNum++); 529 consumer = p.first; 530 memConsumers.add(p.second); 531 } 532 // make sure we have cached process killed 533 String output = executeShellCmd("dumpsys activity lru"); 534 if (output == null && output.indexOf(" cch+") == -1) { 535 break; 536 } 537 } 538 539 return memConsumers; 540 } 541 542 @Test testLmkdKill()543 public void testLmkdKill() throws Exception { 544 // Remove old records to avoid interference with the test. 545 clearHistoricalExitInfo(); 546 547 long now = System.currentTimeMillis(); 548 boolean lmkdReportSupported = ActivityManager.isLowMemoryKillReportSupported(); 549 550 // Start a process and do nothing 551 startService(ACTION_FINISH, STUB_SERVICE_NAME, false, false); 552 553 final ArrayList<IBinder> memConsumers = new ArrayList<>(); 554 List<ApplicationExitInfo> list = new ArrayList<>(); 555 final MemoryConsumerService.TestFuncInterface testFunc = 556 new MemoryConsumerService.TestFuncInterface(() -> { 557 final long token = Binder.clearCallingIdentity(); 558 try { 559 List<ApplicationExitInfo> result = 560 ShellIdentityUtils.invokeMethodWithShellPermissions( 561 STUB_PACKAGE_NAME, mStubPackagePid, 1, 562 mActivityManager::getHistoricalProcessExitReasons, 563 android.Manifest.permission.DUMP); 564 if (result != null && result.size() == 1) { 565 list.add(result.get(0)); 566 return true; 567 } 568 } finally { 569 Binder.restoreCallingIdentity(token); 570 } 571 return false; 572 }); 573 574 List<ServiceConnection> services = fillUpMemoryAndCheck(testFunc, list); 575 576 // Unbind all the service connections firstly 577 for (int i = services.size() - 1; i >= 0; i--) { 578 mContext.unbindService(services.get(i)); 579 } 580 581 long now2 = System.currentTimeMillis(); 582 assertTrue(list != null && list.size() == 1); 583 ApplicationExitInfo info = list.get(0); 584 assertNotNull(info); 585 if (lmkdReportSupported) { 586 verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 587 ApplicationExitInfo.REASON_LOW_MEMORY, null, null, now, now2); 588 } else { 589 verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 590 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now, now2); 591 } 592 } 593 594 @Test testKillBySignal()595 public void testKillBySignal() throws Exception { 596 // Remove old records to avoid interference with the test. 597 clearHistoricalExitInfo(); 598 599 long now = System.currentTimeMillis(); 600 601 // Start a process and kill itself 602 startService(ACTION_KILL, STUB_SERVICE_NAME, true, false); 603 604 long now2 = System.currentTimeMillis(); 605 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 606 STUB_PACKAGE_NAME, mStubPackagePid, 1, 607 mActivityManager::getHistoricalProcessExitReasons, 608 android.Manifest.permission.DUMP); 609 610 assertTrue(list != null && list.size() == 1); 611 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 612 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now, now2); 613 } 614 615 @Test testAnr()616 public void testAnr() throws Exception { 617 // Remove old records to avoid interference with the test. 618 clearHistoricalExitInfo(); 619 620 final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class); 621 final CountDownLatch dboxLatch = new CountDownLatch(1); 622 final BroadcastReceiver receiver = new BroadcastReceiver() { 623 @Override 624 public void onReceive(Context context, Intent intent) { 625 final String tag_anr = "data_app_anr"; 626 if (tag_anr.equals(intent.getStringExtra(DropBoxManager.EXTRA_TAG))) { 627 mAnrEntry = dbox.getNextEntry(tag_anr, intent.getLongExtra( 628 DropBoxManager.EXTRA_TIME, 0) - 1); 629 Log.d(TAG, "Counting down latch onReceive(" + intent + ")"); 630 dboxLatch.countDown(); 631 } 632 } 633 }; 634 mContext.registerReceiver(receiver, 635 new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED)); 636 final long timeout = Settings.Global.getInt(mContext.getContentResolver(), 637 Settings.Global.BROADCAST_FG_CONSTANTS, 10 * 1000) * 3; 638 639 long now = System.currentTimeMillis(); 640 641 // Start a process and block its main thread 642 startService(ACTION_ANR, STUB_SERVICE_NAME, false, false); 643 644 // Sleep for a while to make sure it's already blocking its main thread. 645 sleep(WAITFOR_MSEC); 646 647 AmMonitor monitor = new AmMonitor(mInstrumentation, 648 new String[]{AmMonitor.WAIT_FOR_CRASHED}); 649 650 Intent intent = new Intent(); 651 intent.setComponent(new ComponentName(STUB_PACKAGE_NAME, STUB_RECEIVER_NAME)); 652 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 653 // This will result an ANR 654 mContext.sendOrderedBroadcast(intent, null); 655 656 // Wait for the early ANR 657 monitor.waitFor(AmMonitor.WAIT_FOR_EARLY_ANR, timeout); 658 // Continue, so we could collect ANR traces 659 monitor.sendCommand(AmMonitor.CMD_CONTINUE); 660 // Wait for the ANR 661 monitor.waitFor(AmMonitor.WAIT_FOR_ANR, timeout); 662 // Kill it 663 monitor.sendCommand(AmMonitor.CMD_KILL); 664 // Wait the process gone 665 waitForGone(mWatcher); 666 long now2 = System.currentTimeMillis(); 667 668 awaitForLatch(dboxLatch, "broadcast for %s be received", 669 DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED); 670 assertTrue(mAnrEntry != null); 671 672 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 673 STUB_PACKAGE_NAME, mStubPackagePid, 1, 674 mActivityManager::getHistoricalProcessExitReasons, 675 android.Manifest.permission.DUMP); 676 677 assertTrue(list != null && list.size() == 1); 678 ApplicationExitInfo info = list.get(0); 679 verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 680 ApplicationExitInfo.REASON_ANR, null, null, now, now2); 681 assertEquals(mStubPackageUid, info.getPackageUid()); 682 assertEquals(mStubPackageUid, info.getDefiningUid()); 683 684 // Verify the traces 685 686 // Read from dropbox 687 final String dboxTrace = mAnrEntry.getText(0x100000 /* 1M */); 688 assertFalse(TextUtils.isEmpty(dboxTrace)); 689 690 // Read the input stream from the ApplicationExitInfo 691 String trace = ShellIdentityUtils.invokeMethodWithShellPermissions(info, (i) -> { 692 try (BufferedInputStream input = new BufferedInputStream(i.getTraceInputStream())) { 693 StringBuilder sb = new StringBuilder(); 694 byte[] buf = new byte[8192]; 695 while (true) { 696 final int len = input.read(buf, 0, buf.length); 697 if (len <= 0) { 698 break; 699 } 700 sb.append(new String(buf, 0, len)); 701 } 702 return sb.toString(); 703 } catch (IOException e) { 704 return null; 705 } 706 }, android.Manifest.permission.DUMP); 707 assertFalse(TextUtils.isEmpty(trace)); 708 assertTrue(trace.indexOf(Integer.toString(info.getPid())) >= 0); 709 assertTrue(trace.indexOf("Cmd line: " + STUB_PACKAGE_NAME) >= 0); 710 assertTrue(dboxTrace.indexOf(trace) >= 0); 711 712 monitor.finish(); 713 mContext.unregisterReceiver(receiver); 714 } 715 716 @Test testOther()717 public void testOther() throws Exception { 718 // Remove old records to avoid interference with the test. 719 clearHistoricalExitInfo(); 720 721 final String servicePackage = "android.externalservice.service"; 722 final String keyIBinder = "ibinder"; 723 final CountDownLatch latch = new CountDownLatch(1); 724 final Bundle holder = new Bundle(); 725 final ServiceConnection connection = new ServiceConnection() { 726 @Override 727 public void onServiceConnected(ComponentName name, IBinder service) { 728 holder.putBinder(keyIBinder, service); 729 Log.d(TAG, "Counting down latch onServiceConnected(" + name + ")"); 730 latch.countDown(); 731 } 732 733 @Override 734 public void onServiceDisconnected(ComponentName name) { 735 } 736 }; 737 738 final Intent intent = new Intent(); 739 ComponentName serviceComponent = new ComponentName(servicePackage, 740 servicePackage + ".ExternalServiceWithZygote"); 741 intent.setComponent(serviceComponent); 742 743 // Bind to that external service, which will become an isolated process 744 // running in the current package user id. 745 assertTrue(mContext.bindService(intent, 746 Context.BIND_AUTO_CREATE | Context.BIND_EXTERNAL_SERVICE, 747 AsyncTask.THREAD_POOL_EXECUTOR, connection)); 748 749 awaitForLatch(latch, "service %s to bind", serviceComponent.flattenToShortString()); 750 751 final IBinder service = holder.getBinder(keyIBinder); 752 assertNotNull(service); 753 754 // Retrieve its uid/pd/package name info. 755 Messenger remote = new Messenger(service); 756 RunningServiceInfo id = identifyService(remote); 757 assertNotNull(id); 758 759 assertFalse(id.uid == 0 || id.pid == 0); 760 assertFalse(Process.myUid() == id.uid); 761 assertFalse(Process.myPid() == id.pid); 762 assertEquals(mContext.getPackageName(), id.packageName); 763 764 final WatchUidRunner watcher = new WatchUidRunner(mInstrumentation, 765 id.uid, WAITFOR_MSEC); 766 767 long now = System.currentTimeMillis(); 768 769 // Remove the service connection 770 mContext.unbindService(connection); 771 772 try { 773 // Isolated process should have been killed as long as its service is done. 774 waitForGone(watcher); 775 } finally { 776 watcher.finish(); 777 } 778 779 long now2 = System.currentTimeMillis(); 780 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 781 final List<ApplicationExitInfo> list = am.getHistoricalProcessExitReasons(null, id.pid, 1); 782 assertTrue(list != null && list.size() == 1); 783 784 ApplicationExitInfo info = list.get(0); 785 verify(info, id.pid, id.uid, null, ApplicationExitInfo.REASON_OTHER, null, 786 "isolated not needed", now, now2); 787 assertEquals(Process.myUid(), info.getPackageUid()); 788 assertEquals(mContext.getPackageManager().getPackageUid(servicePackage, 0), 789 info.getDefiningUid()); 790 assertEquals(ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE, 791 info.getImportance()); 792 } 793 extractMemString(String dump, String prefix, char nextSep)794 private String extractMemString(String dump, String prefix, char nextSep) { 795 int start = dump.indexOf(prefix); 796 assertTrue(start >= 0); 797 start += prefix.length(); 798 int end = dump.indexOf(nextSep, start); 799 assertTrue(end > start); 800 return dump.substring(start, end); 801 } 802 803 @Test testPermissionChange()804 public void testPermissionChange() throws Exception { 805 // Remove old records to avoid interference with the test. 806 clearHistoricalExitInfo(); 807 808 // Grant the read calendar permission 809 mInstrumentation.getUiAutomation().grantRuntimePermission( 810 STUB_PACKAGE_NAME, android.Manifest.permission.READ_CALENDAR); 811 long now = System.currentTimeMillis(); 812 813 // Start a process and do nothing 814 startService(ACTION_FINISH, STUB_SERVICE_NAME, false, false); 815 816 // Enable high frequency memory sampling 817 executeShellCmd("dumpsys procstats --start-testing"); 818 // Sleep for a while to wait for the sampling of memory info 819 sleep(10000); 820 // Stop the high frequency memory sampling 821 executeShellCmd("dumpsys procstats --stop-testing"); 822 // Get the memory info from it. 823 String dump = executeShellCmd("dumpsys activity processes " + STUB_PACKAGE_NAME); 824 assertNotNull(dump); 825 final String lastPss = extractMemString(dump, " lastPss=", ' '); 826 final String lastRss = extractMemString(dump, " lastRss=", '\n'); 827 828 // Revoke the read calendar permission 829 mInstrumentation.getUiAutomation().revokeRuntimePermission( 830 STUB_PACKAGE_NAME, android.Manifest.permission.READ_CALENDAR); 831 waitForGone(mWatcher); 832 long now2 = System.currentTimeMillis(); 833 834 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 835 STUB_PACKAGE_NAME, mStubPackagePid, 1, 836 mActivityManager::getHistoricalProcessExitReasons, 837 android.Manifest.permission.DUMP); 838 839 assertTrue(list != null && list.size() == 1); 840 841 ApplicationExitInfo info = list.get(0); 842 verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 843 ApplicationExitInfo.REASON_PERMISSION_CHANGE, null, null, now, now2); 844 845 // Also verify that we get the expected meminfo 846 assertEquals(lastPss, DebugUtils.sizeValueToString( 847 info.getPss() * 1024, new StringBuilder())); 848 assertEquals(lastRss, DebugUtils.sizeValueToString( 849 info.getRss() * 1024, new StringBuilder())); 850 } 851 852 // A clone of testPermissionChange using a different revoke api 853 @Test testPermissionChangeWithReason()854 public void testPermissionChangeWithReason() throws Exception { 855 String revokeReason = "test reason"; 856 // Remove old records to avoid interference with the test. 857 clearHistoricalExitInfo(); 858 859 // Grant the read calendar permission 860 mInstrumentation.getUiAutomation().grantRuntimePermission( 861 STUB_PACKAGE_NAME, android.Manifest.permission.READ_CALENDAR); 862 long now = System.currentTimeMillis(); 863 864 // Start a process and do nothing 865 startService(ACTION_FINISH, STUB_SERVICE_NAME, false, false); 866 867 // Enable high frequency memory sampling 868 executeShellCmd("dumpsys procstats --start-testing"); 869 // Sleep for a while to wait for the sampling of memory info 870 sleep(10000); 871 // Stop the high frequency memory sampling 872 executeShellCmd("dumpsys procstats --stop-testing"); 873 // Get the memory info from it. 874 String dump = executeShellCmd("dumpsys activity processes " + STUB_PACKAGE_NAME); 875 assertNotNull(dump); 876 final String lastPss = extractMemString(dump, " lastPss=", ' '); 877 final String lastRss = extractMemString(dump, " lastRss=", '\n'); 878 879 // Revoke the read calendar permission 880 runWithShellPermissionIdentity(() -> { 881 mContext.getPackageManager().revokeRuntimePermission(STUB_PACKAGE_NAME, 882 android.Manifest.permission.READ_CALENDAR, Process.myUserHandle(), 883 revokeReason); 884 }); 885 waitForGone(mWatcher); 886 long now2 = System.currentTimeMillis(); 887 888 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 889 STUB_PACKAGE_NAME, mStubPackagePid, 1, 890 mActivityManager::getHistoricalProcessExitReasons, 891 android.Manifest.permission.DUMP); 892 893 assertTrue(list != null && list.size() == 1); 894 895 ApplicationExitInfo info = list.get(0); 896 verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 897 ApplicationExitInfo.REASON_PERMISSION_CHANGE, null, null, now, now2); 898 assertEquals(revokeReason, info.getDescription()); 899 900 // Also verify that we get the expected meminfo 901 assertEquals(lastPss, DebugUtils.sizeValueToString( 902 info.getPss() * 1024, new StringBuilder())); 903 assertEquals(lastRss, DebugUtils.sizeValueToString( 904 info.getRss() * 1024, new StringBuilder())); 905 } 906 907 @Test testCrash()908 public void testCrash() throws Exception { 909 // Remove old records to avoid interference with the test. 910 clearHistoricalExitInfo(); 911 912 long now = System.currentTimeMillis(); 913 914 // Start a process and do nothing 915 startService(ACTION_NONE, STUB_SERVICE_NAME, false, false); 916 917 // Induce a crash 918 executeShellCmd("am crash " + STUB_PACKAGE_NAME); 919 waitForGone(mWatcher); 920 long now2 = System.currentTimeMillis(); 921 922 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 923 STUB_PACKAGE_NAME, mStubPackagePid, 1, 924 mActivityManager::getHistoricalProcessExitReasons, 925 android.Manifest.permission.DUMP); 926 927 assertTrue(list != null && list.size() == 1); 928 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 929 ApplicationExitInfo.REASON_CRASH, null, null, now, now2); 930 } 931 932 @Test testNativeCrash()933 public void testNativeCrash() throws Exception { 934 // Remove old records to avoid interference with the test. 935 clearHistoricalExitInfo(); 936 937 long now = System.currentTimeMillis(); 938 939 // Start a process and crash it 940 startService(ACTION_NATIVE_CRASH, STUB_SERVICE_NAME, true, false); 941 942 // Native crashes are handled asynchronously from the actual crash, so 943 // it's possible for us to notice that the process crashed before an 944 // actual tombstone exists. 945 Thread.sleep(1000); 946 947 long now2 = System.currentTimeMillis(); 948 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 949 STUB_PACKAGE_NAME, mStubPackagePid, 1, 950 mActivityManager::getHistoricalProcessExitReasons, 951 android.Manifest.permission.DUMP); 952 953 assertTrue(list != null && list.size() == 1); 954 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 955 ApplicationExitInfo.REASON_CRASH_NATIVE, null, null, now, now2); 956 957 TombstoneFetcher tombstoneFetcher = new TombstoneFetcher(list.get(0)); 958 PollingCheck.check("not able to get tombstone", TOMBSTONE_FETCH_TIMEOUT_MS, 959 () -> tombstoneFetcher.fetchTrace()); 960 961 InputStream trace = tombstoneFetcher.getTrace(); 962 assertNotNull(trace); 963 Tombstone tombstone = Tombstone.parseFrom(trace); 964 assertEquals(tombstone.getPid(), mStubPackagePid); 965 } 966 967 @Test testUserRequested()968 public void testUserRequested() throws Exception { 969 // Remove old records to avoid interference with the test. 970 clearHistoricalExitInfo(); 971 972 long now = System.currentTimeMillis(); 973 974 // Start a process and do nothing 975 startService(ACTION_NONE, STUB_SERVICE_NAME, false, false); 976 977 // Force stop the test package 978 executeShellCmd("am force-stop " + STUB_PACKAGE_NAME); 979 980 // Wait the process gone 981 waitForGone(mWatcher); 982 983 long now2 = System.currentTimeMillis(); 984 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 985 STUB_PACKAGE_NAME, mStubPackagePid, 1, 986 mActivityManager::getHistoricalProcessExitReasons, 987 android.Manifest.permission.DUMP); 988 989 assertTrue(list != null && list.size() == 1); 990 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 991 ApplicationExitInfo.REASON_USER_REQUESTED, null, null, now, now2); 992 } 993 994 @Test testPackageDisabled()995 public void testPackageDisabled() throws Exception { 996 // Remove old records to avoid interference with the test. 997 clearHistoricalExitInfo(); 998 999 // Start a process and do nothing 1000 startService(ACTION_NONE, STUB_SERVICE_NAME, false, false); 1001 1002 //disable the app and kill it 1003 mInstrumentation.getUiAutomation().adoptShellPermissionIdentity( 1004 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); 1005 PackageManager packageManager = mContext.getPackageManager(); 1006 packageManager.setApplicationEnabledSetting( 1007 STUB_PACKAGE_NAME, 1008 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 1009 0); 1010 1011 waitForGone(mWatcher); 1012 1013 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1014 STUB_PACKAGE_NAME, mStubPackagePid, 1, 1015 mActivityManager::getHistoricalProcessExitReasons, 1016 android.Manifest.permission.DUMP); 1017 1018 assertTrue(list != null && list.size() == 1); 1019 assertEquals(ApplicationExitInfo.REASON_PACKAGE_STATE_CHANGE, list.get(0).getReason()); 1020 assertEquals(ApplicationExitInfo.SUBREASON_UNKNOWN, list.get(0).getSubReason()); 1021 } 1022 1023 @Test testPackageUpdated()1024 public void testPackageUpdated() throws Exception { 1025 // Remove old records to avoid interference with the test. 1026 clearHistoricalExitInfo(); 1027 1028 // Start a process and do nothing 1029 startService(ACTION_NONE, STUB_SERVICE_NAME, false, false); 1030 1031 // Update the package 1032 executeShellCmd("pm install -r /data/local/tmp/cts/content/CtsSimpleApp.apk"); 1033 1034 waitForGone(mWatcher); 1035 1036 List<ApplicationExitInfo> list = 1037 ShellIdentityUtils.invokeMethodWithShellPermissions( 1038 STUB_PACKAGE_NAME, mStubPackagePid, 1, 1039 mActivityManager::getHistoricalProcessExitReasons, 1040 Manifest.permission.DUMP); 1041 1042 assertTrue(list != null && list.size() == 1); 1043 assertEquals(ApplicationExitInfo.REASON_PACKAGE_UPDATED, list.get(0).getReason()); 1044 assertEquals(ApplicationExitInfo.SUBREASON_UNKNOWN, list.get(0).getSubReason()); 1045 } 1046 1047 @Test testDependencyDied()1048 public void testDependencyDied() throws Exception { 1049 // Remove old records to avoid interference with the test. 1050 clearHistoricalExitInfo(); 1051 1052 // Start a process and acquire the provider 1053 startService(ACTION_ACQUIRE_STABLE_PROVIDER, STUB_SERVICE_NAME, false, false); 1054 1055 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 1056 long now = System.currentTimeMillis(); 1057 final long timeout = now + WAITFOR_MSEC; 1058 int providerPid = -1; 1059 while (now < timeout && providerPid < 0) { 1060 sleep(1000); 1061 List<RunningAppProcessInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1062 am, ActivityManager::getRunningAppProcesses, 1063 android.Manifest.permission.REAL_GET_TASKS); 1064 for (RunningAppProcessInfo info: list) { 1065 if (info.processName.equals(STUB_REMOTE_PROCESS_NAME)) { 1066 providerPid = info.pid; 1067 break; 1068 } 1069 } 1070 now = System.currentTimeMillis(); 1071 } 1072 assertTrue(providerPid > 0); 1073 1074 now = System.currentTimeMillis(); 1075 // Now let the provider exit itself 1076 startService(ACTION_KILL_PROVIDER, STUB_SERVICE_NAME, false, false, false, false, null); 1077 1078 // Wait for both of the processes gone 1079 waitForGone(mWatcher); 1080 final long now2 = System.currentTimeMillis(); 1081 1082 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1083 STUB_PACKAGE_NAME, mStubPackagePid, 1, 1084 mActivityManager::getHistoricalProcessExitReasons, 1085 android.Manifest.permission.DUMP); 1086 1087 assertTrue(list != null && list.size() == 1); 1088 verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME, 1089 ApplicationExitInfo.REASON_DEPENDENCY_DIED, null, null, now, now2); 1090 } 1091 1092 @Test testMultipleProcess()1093 public void testMultipleProcess() throws Exception { 1094 // Remove old records to avoid interference with the test. 1095 clearHistoricalExitInfo(); 1096 1097 long now = System.currentTimeMillis(); 1098 1099 // Start a process and kill itself 1100 startService(ACTION_KILL, STUB_SERVICE_NAME, true, false); 1101 1102 long now2 = System.currentTimeMillis(); 1103 1104 // Start a remote process and exit 1105 startService(ACTION_EXIT, STUB_SERVICE_REMOTE_NAME, true, false); 1106 1107 long now3 = System.currentTimeMillis(); 1108 // Now to get the two reports 1109 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1110 STUB_PACKAGE_NAME, 0, 2, 1111 mActivityManager::getHistoricalProcessExitReasons, 1112 android.Manifest.permission.DUMP); 1113 1114 assertTrue(list != null && list.size() == 2); 1115 verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_PROCESS_NAME, 1116 ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now2, now3); 1117 verify(list.get(1), mStubPackagePid, mStubPackageUid, STUB_PROCESS_NAME, 1118 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now, now2); 1119 1120 // If we only retrieve one report 1121 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1122 STUB_PACKAGE_NAME, 0, 1, 1123 mActivityManager::getHistoricalProcessExitReasons, 1124 android.Manifest.permission.DUMP); 1125 1126 assertTrue(list != null && list.size() == 1); 1127 verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_PROCESS_NAME, 1128 ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now2, now3); 1129 } 1130 identifyService(Messenger service)1131 private RunningServiceInfo identifyService(Messenger service) throws Exception { 1132 final CountDownLatch latch = new CountDownLatch(1); 1133 class IdentifyHandler extends Handler { 1134 IdentifyHandler() { 1135 super(Looper.getMainLooper()); 1136 } 1137 1138 RunningServiceInfo mInfo; 1139 1140 @Override 1141 public void handleMessage(Message msg) { 1142 Log.d(TAG, "Received message: " + msg); 1143 switch (msg.what) { 1144 case ServiceMessages.MSG_IDENTIFY_RESPONSE: 1145 msg.getData().setClassLoader(RunningServiceInfo.class.getClassLoader()); 1146 mInfo = msg.getData().getParcelable(ServiceMessages.IDENTIFY_INFO); 1147 Log.d(TAG, "Counting down latch on IdentifyHandler msg: " + msg); 1148 latch.countDown(); 1149 break; 1150 } 1151 super.handleMessage(msg); 1152 } 1153 } 1154 1155 IdentifyHandler handler = new IdentifyHandler(); 1156 Messenger local = new Messenger(handler); 1157 1158 Message msg = Message.obtain(null, ServiceMessages.MSG_IDENTIFY); 1159 msg.replyTo = local; 1160 service.send(msg); 1161 awaitForLatch(latch, "service to receive message"); 1162 1163 return handler.mInfo; 1164 } 1165 prepareTestUser()1166 private void prepareTestUser() throws Exception { 1167 Log.d(TAG, "prepareTestUser()"); 1168 // Create the test user 1169 mOtherUserId = createUser("TestUser_" + SystemClock.uptimeMillis(), false); 1170 Log.d(TAG, "user created: " + mOtherUserId); 1171 mOtherUserHandle = UserHandle.of(mOtherUserId); 1172 // Start the other user 1173 assertTrue(startUser(mOtherUserId, true)); 1174 Log.d(TAG, "user started"); 1175 // Install the test helper APK into the other user 1176 installExistingPackageAsUser(STUB_PACKAGE_NAME, mOtherUserId); 1177 installExistingPackageAsUser(mContext.getPackageName(), mOtherUserId); 1178 mStubPackageOtherUid = mContext.getPackageManager().getPackageUidAsUser( 1179 STUB_PACKAGE_NAME, 0, mOtherUserId); 1180 Log.d(TAG, "UID of " + STUB_PACKAGE_NAME + ": " + mStubPackageOtherUid); 1181 mOtherUidWatcher = new WatchUidRunner(mInstrumentation, mStubPackageOtherUid, 1182 WAITFOR_MSEC); 1183 } 1184 removeTestUserIfNecessary()1185 private void removeTestUserIfNecessary() throws Exception { 1186 if (mSupportMultipleUsers && mOtherUserId > 0) { 1187 // Stop the test user 1188 assertTrue(stopUser(mOtherUserId, true, true)); 1189 // Remove the test user 1190 removeUser(mOtherUserId); 1191 if (mOtherUidWatcher != null) { 1192 mOtherUidWatcher.finish(); 1193 } 1194 } 1195 } 1196 1197 @Test testSecondaryUser()1198 public void testSecondaryUser() throws Exception { 1199 if (!mSupportMultipleUsers) { 1200 return; 1201 } 1202 1203 // Remove old records to avoid interference with the test. 1204 clearHistoricalExitInfo(); 1205 1206 // Get the full user permission in order to start service as other user 1207 mInstrumentation.getUiAutomation().adoptShellPermissionIdentity( 1208 android.Manifest.permission.INTERACT_ACROSS_USERS, 1209 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1210 1211 // Create the test user, we'll remove it during tearDown 1212 prepareTestUser(); 1213 1214 final byte[] cookie0 = {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, 1215 (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07}; 1216 final byte[] cookie1 = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, 1217 (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08}; 1218 final byte[] cookie2 = {(byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, 1219 (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x01}; 1220 final byte[] cookie3 = {(byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, 1221 (byte) 0x07, (byte) 0x08, (byte) 0x01, (byte) 0x02}; 1222 final byte[] cookie4 = {(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, 1223 (byte) 0x08, (byte) 0x01, (byte) 0x02, (byte) 0x03}; 1224 final byte[] cookie5 = null; 1225 1226 long now = System.currentTimeMillis(); 1227 1228 // Start a process and do nothing 1229 startService(ACTION_NONE, STUB_SERVICE_NAME, false, true, false, true, cookie0); 1230 // request to exit by itself with a different cookie 1231 startService(ACTION_EXIT, STUB_SERVICE_NAME, true, false, false, true, cookie1); 1232 1233 long now2 = System.currentTimeMillis(); 1234 1235 // Start the process in a secondary user and kill itself 1236 startService(ACTION_KILL, STUB_SERVICE_NAME, true, true, true, true, cookie2); 1237 1238 long now3 = System.currentTimeMillis(); 1239 1240 // Start a remote process in a secondary user and exit 1241 startService(ACTION_EXIT, STUB_SERVICE_REMOTE_NAME, true, true, true, true, cookie3); 1242 1243 long now4 = System.currentTimeMillis(); 1244 1245 // Start a remote process and kill itself 1246 startService(ACTION_KILL, STUB_SERVICE_REMOTE_NAME, true, true, false, true, cookie4); 1247 1248 long now5 = System.currentTimeMillis(); 1249 // drop the permissions 1250 mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); 1251 1252 List<ApplicationExitInfo> list = null; 1253 1254 // Now try to query for all users 1255 try { 1256 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1257 STUB_PACKAGE_NAME, 0, 0, UserHandle.USER_ALL, 1258 this::getHistoricalProcessExitReasonsAsUser, 1259 android.Manifest.permission.DUMP); 1260 fail("Shouldn't be able to query all users"); 1261 } catch (IllegalArgumentException e) { 1262 // expected 1263 } 1264 1265 // Now try to query for "current" user 1266 try { 1267 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1268 STUB_PACKAGE_NAME, 0, 0, UserHandle.USER_CURRENT, 1269 this::getHistoricalProcessExitReasonsAsUser, 1270 android.Manifest.permission.DUMP); 1271 fail("Shouldn't be able to query current user, explicit user-Id is expected"); 1272 } catch (IllegalArgumentException e) { 1273 // expected 1274 } 1275 1276 // Now only try the current user 1277 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1278 STUB_PACKAGE_NAME, 0, 0, mCurrentUserId, 1279 this::getHistoricalProcessExitReasonsAsUser, 1280 android.Manifest.permission.DUMP); 1281 1282 assertTrue(list != null && list.size() == 2); 1283 verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_PROCESS_NAME, 1284 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5, 1285 cookie4); 1286 verify(list.get(1), mStubPackagePid, mStubPackageUid, STUB_PROCESS_NAME, 1287 ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2, cookie1); 1288 1289 // Now try the other user 1290 try { 1291 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1292 STUB_PACKAGE_NAME, 0, 0, mOtherUserId, 1293 this::getHistoricalProcessExitReasonsAsUser, 1294 android.Manifest.permission.DUMP); 1295 fail("Shouldn't be able to query other users"); 1296 } catch (SecurityException e) { 1297 // expected 1298 } 1299 1300 // Now try the other user with proper permissions 1301 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1302 STUB_PACKAGE_NAME, 0, 0, mOtherUserId, 1303 this::getHistoricalProcessExitReasonsAsUser, 1304 android.Manifest.permission.DUMP, 1305 android.Manifest.permission.INTERACT_ACROSS_USERS); 1306 1307 assertTrue(list != null && list.size() == 2); 1308 verify(list.get(0), mStubPackageRemoteOtherUserPid, mStubPackageOtherUid, 1309 STUB_REMOTE_PROCESS_NAME, ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, 1310 null, now3, now4, cookie3); 1311 verify(list.get(1), mStubPackageOtherUserPid, mStubPackageOtherUid, STUB_PROCESS_NAME, 1312 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, 1313 now2, now3, cookie2); 1314 1315 // Get the full user permission in order to start service as other user 1316 mInstrumentation.getUiAutomation().adoptShellPermissionIdentity( 1317 android.Manifest.permission.INTERACT_ACROSS_USERS, 1318 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1319 // Start the process in a secondary user and do nothing 1320 startService(ACTION_NONE, STUB_SERVICE_NAME, false, true, true, true, cookie5); 1321 // drop the permissions 1322 mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); 1323 1324 long now6 = System.currentTimeMillis(); 1325 // Stop the test user 1326 assertTrue(stopUser(mOtherUserId, true, true)); 1327 // Wait for being killed 1328 waitForGone(mOtherUidWatcher); 1329 1330 long now7 = System.currentTimeMillis(); 1331 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1332 STUB_PACKAGE_NAME, 0, 1, mOtherUserId, 1333 this::getHistoricalProcessExitReasonsAsUser, 1334 android.Manifest.permission.DUMP, 1335 android.Manifest.permission.INTERACT_ACROSS_USERS); 1336 verify(list.get(0), mStubPackageOtherUserPid, mStubPackageOtherUid, STUB_PROCESS_NAME, 1337 ApplicationExitInfo.REASON_USER_STOPPED, null, null, now6, now7, cookie5); 1338 1339 int otherUserId = mOtherUserId; 1340 // Now remove the other user 1341 removeUser(mOtherUserId); 1342 mOtherUidWatcher.finish(); 1343 mOtherUserId = 0; 1344 1345 // Poll userInfo to check if the user has been removed, wait up to 10 mins 1346 for (int i = 0; i < 600; i++) { 1347 if (ShellIdentityUtils.invokeMethodWithShellPermissions(otherUserId, 1348 mUserManager::getUserInfo, 1349 android.Manifest.permission.CREATE_USERS) != null) { 1350 // We can still get the userInfo, sleep 1 second and try again 1351 sleep(1000); 1352 } else { 1353 Log.d(TAG, "User " + otherUserId + " has been removed"); 1354 break; 1355 } 1356 } 1357 // For now the ACTION_USER_REMOVED should have been sent to all receives, 1358 // we take an extra nap to make sure we've had the broadcast handling settled. 1359 sleep(15 * 1000); 1360 1361 // Now query the other userId, and it should return nothing. 1362 final Context context = mContext.createPackageContextAsUser("android", 0, 1363 UserHandle.of(otherUserId)); 1364 final ActivityManager am = context.getSystemService(ActivityManager.class); 1365 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1366 STUB_PACKAGE_NAME, 0, 0, 1367 am::getHistoricalProcessExitReasons, 1368 android.Manifest.permission.DUMP, 1369 android.Manifest.permission.INTERACT_ACROSS_USERS); 1370 assertTrue(list == null || list.size() == 0); 1371 1372 // The current user shouldn't be impacted. 1373 list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1374 STUB_PACKAGE_NAME, 0, 0, mCurrentUserId, 1375 this::getHistoricalProcessExitReasonsAsUser, 1376 android.Manifest.permission.DUMP, 1377 android.Manifest.permission.INTERACT_ACROSS_USERS); 1378 1379 assertTrue(list != null && list.size() == 2); 1380 verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_PROCESS_NAME, 1381 ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5, 1382 cookie4); 1383 verify(list.get(1), mStubPackagePid, mStubPackageUid, STUB_PROCESS_NAME, 1384 ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2, cookie1); 1385 } 1386 1387 /** 1388 * By design, an app's process in cached state is subject to being killed due 1389 * to system memory pressure. Any work in this state, e.g. an {@link Activity} 1390 * trying to execute extra code after the {@link Activity#onStop()} method has 1391 * been called and returned, is unreliable and strongly discouraged. For more 1392 * details see <a 1393 * href="https://developer.android.com/guide/components/activities/process-lifecycle"> 1394 * Processes and app lifecycle</a>. 1395 * <p> 1396 * Starting in {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, OS 1397 * enforces cached-app resource usage. This test checks whether the Freezer 1398 * has been correctly enabled to be consistent with the documented developer 1399 * expectations. 1400 */ 1401 @CddTest(requirements = {"3.5/C-0-2"}) 1402 @Test testFreezerEnabled()1403 public void testFreezerEnabled() throws Exception { 1404 if (FIRST_SDK_IS_AT_LEAST_U 1405 && SystemProperties.get("ro.kernel.version").compareTo("5") >= 0) { 1406 // We expect all devices with kernel 5.x that first shipped with U to support Freezer 1407 assertTrue(ActivityManager.getService().isAppFreezerSupported()); 1408 } else { 1409 // For old devices OTA'ed to U, check if Linux kernel and vendor partition is too old 1410 assumeTrue(ActivityManager.getService().isAppFreezerSupported()); 1411 } 1412 1413 // Freezer must be enabled as long as it's supported 1414 assertTrue(ActivityManager.getService().isAppFreezerEnabled()); 1415 1416 // Check dumpsys to verify the Freezer configurations in use 1417 final String output = executeShellCmd("dumpsys activity"); 1418 Pattern pattern = Pattern.compile("freeze_debounce_timeout=(\\d+)"); 1419 Matcher matcher = pattern.matcher(output); 1420 assertTrue(matcher.find()); 1421 final long timeout = Long.parseLong(matcher.group(1)); 1422 assertTrue(timeout >= FREEZER_TIMEOUT_FLOOR); 1423 } 1424 1425 @Test testFreezerNormalExitCode()1426 public void testFreezerNormalExitCode() throws Exception { 1427 // The app should NOT be frozen with 30s freeze timeout configuration 1428 runFreezerTest(HEARTBEAT_FREEZER_LONG, false, ApplicationExitInfo.REASON_SIGNALED); 1429 } 1430 1431 @Test testFreezerKillExitCode()1432 public void testFreezerKillExitCode() throws Exception { 1433 // The app should be frozen and killed with 5s freeze timeout configuration 1434 assumeTrue(ActivityManager.getService().isAppFreezerEnabled()); 1435 runFreezerTest(HEARTBEAT_FREEZER_SHORT, true, ApplicationExitInfo.REASON_FREEZER); 1436 } 1437 runFreezerTest(long freezerTimeout, boolean dead, int reason)1438 public void runFreezerTest(long freezerTimeout, boolean dead, int reason) throws Exception { 1439 // Remove old records to avoid interference with the test. 1440 clearHistoricalExitInfo(); 1441 1442 executeShellCmd( 1443 "device_config put activity_manager_native_boot freeze_debounce_timeout " 1444 + freezerTimeout); 1445 1446 long now = System.currentTimeMillis(); 1447 1448 mLatch = new CountDownLatch(1); 1449 1450 // Start the HeartbeatService to wait for HeartbeatActivity 1451 Intent serviceIntent = new Intent(HEARTBEAT_SERVICE); 1452 serviceIntent.setPackage(HEARTBEAT_PACKAGE); 1453 ServiceConnection connection = new ServiceConnection() { 1454 @Override 1455 public void onServiceConnected(ComponentName name, IBinder service) { 1456 Log.d(TAG, "onServiceConnected(" + name + "): " + service); 1457 IHeartbeat heartbeat = IHeartbeat.Stub.asInterface(service); 1458 try { 1459 heartbeat.monitor(mMessenger); 1460 } catch (RemoteException e) { 1461 fail("Failed to monitor Heartbeat service"); 1462 } 1463 } 1464 1465 @Override 1466 public void onServiceDisconnected(ComponentName name) { 1467 } 1468 }; 1469 mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE); 1470 1471 // Launch the HeartbeatActivity to talk to the HeartbeatService 1472 Intent clientIntent = new Intent(Intent.ACTION_MAIN); 1473 clientIntent.setClassName(HEARTBEAT_PACKAGE, HEARTBEAT_ACTIVITY); 1474 clientIntent.putExtra(HEARTBEAT_COUNTDOWN_NAME, HEARTBEAT_COUNTDOWN); 1475 clientIntent.putExtra(HEARTBEAT_INTERVAL_NAME, HEARTBEAT_INTERVAL); 1476 clientIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1477 mContext.startActivity(clientIntent); 1478 sleep(1000); 1479 1480 // Launch another app to bring the HeartbeatActivity to background 1481 Intent intent1 = new Intent(Intent.ACTION_MAIN); 1482 intent1.setClassName(STUB_PACKAGE_NAME, STUB_PACKAGE_NAME + SIMPLE_ACTIVITY); 1483 intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1484 mContext.startActivity(intent1); 1485 sleep(1000); 1486 1487 // Launch Home to make sure the HeartbeatActivity is in cached mode 1488 Intent intentHome = new Intent(Intent.ACTION_MAIN); 1489 intentHome.addCategory(Intent.CATEGORY_HOME); 1490 intentHome.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1491 mContext.startActivity(intentHome); 1492 1493 // Wait until the HeartbeatService finishes 1494 awaitForLatch(mLatch, HEARTBEAT_COUNTDOWN * HEARTBEAT_INTERVAL, "heartbeat"); 1495 mContext.unbindService(connection); 1496 sleep(1000); 1497 1498 // Check if the frozen app is killed 1499 assertEquals(dead, mHeartbeatDead); 1500 int uid = mContext.getPackageManager().getPackageUid(HEARTBEAT_PACKAGE, 1501 PackageManager.PackageInfoFlags.of(0)); 1502 assertEquals(uid, mStubPackageUid); 1503 1504 long now2 = System.currentTimeMillis(); 1505 1506 List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions( 1507 HEARTBEAT_PACKAGE, mStubPackagePid, 1, mCurrentUserId, 1508 this::getHistoricalProcessExitReasonsAsUser, 1509 android.Manifest.permission.DUMP); 1510 1511 assertNotNull(list); 1512 assertEquals(1, list.size()); 1513 verify(list.get(0), mStubPackagePid, uid, HEARTBEAT_PROCESS, 1514 reason, null, null, now, now2); 1515 } 1516 verify(ApplicationExitInfo info, int pid, int uid, String processName, int reason, Integer status, String description, long before, long after)1517 private void verify(ApplicationExitInfo info, int pid, int uid, String processName, 1518 int reason, Integer status, String description, long before, long after) { 1519 verify(info, pid, uid, processName, reason, status, description, before, after, null); 1520 } 1521 verify(ApplicationExitInfo info, int pid, int uid, String processName, int reason, Integer status, String description, long before, long after, byte[] cookie)1522 private void verify(ApplicationExitInfo info, int pid, int uid, String processName, 1523 int reason, Integer status, String description, long before, long after, 1524 byte[] cookie) { 1525 assertNotNull(info); 1526 assertEquals(pid, info.getPid()); 1527 assertEquals(uid, info.getRealUid()); 1528 assertEquals(UserHandle.of(UserHandle.getUserId(uid)), info.getUserHandle()); 1529 if (processName != null) { 1530 assertEquals(processName, info.getProcessName()); 1531 } 1532 assertEquals(reason, info.getReason()); 1533 if (status != null) { 1534 assertEquals(status.intValue(), info.getStatus()); 1535 } 1536 1537 if (description != null) { 1538 assertTrue(info.getDescription().contains(description)); 1539 } 1540 1541 assertTrue(before <= info.getTimestamp()); 1542 assertTrue(after >= info.getTimestamp()); 1543 assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), cookie, 1544 cookie == null ? 0 : cookie.length)); 1545 } 1546 1547 private static class TombstoneFetcher { 1548 private InputStream mTrace = null; 1549 private final ApplicationExitInfo mExitInfo; 1550 TombstoneFetcher(ApplicationExitInfo exitInfo)1551 TombstoneFetcher(ApplicationExitInfo exitInfo) { 1552 mExitInfo = exitInfo; 1553 } 1554 getTrace()1555 public InputStream getTrace() { 1556 return mTrace; 1557 } 1558 fetchTrace()1559 public boolean fetchTrace() throws Exception { 1560 mTrace = ShellIdentityUtils.invokeMethodWithShellPermissions( 1561 mExitInfo, 1562 (i) -> { 1563 try { 1564 return i.getTraceInputStream(); 1565 } catch (IOException ex) { 1566 return null; 1567 } 1568 }, 1569 android.Manifest.permission.DUMP); 1570 return (mTrace != null); 1571 } 1572 } 1573 } 1574