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