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