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