1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.am;
18 
19 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
20 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
21 
22 import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_LIMIT;
23 import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_RESET_INTERVAL;
24 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
25 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
26 import static com.android.server.am.ActivityManagerService.MY_PID;
27 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
28 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
29 
30 import android.annotation.Nullable;
31 import android.app.ActivityManager;
32 import android.app.ActivityOptions;
33 import android.app.AnrController;
34 import android.app.ApplicationErrorReport;
35 import android.app.ApplicationExitInfo;
36 import android.app.usage.UsageStatsManager;
37 import android.content.ActivityNotFoundException;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.content.pm.VersionedPackage;
41 import android.net.Uri;
42 import android.os.Binder;
43 import android.os.Build;
44 import android.os.Bundle;
45 import android.os.Message;
46 import android.os.Process;
47 import android.os.SystemClock;
48 import android.os.UserHandle;
49 import android.provider.Settings;
50 import android.util.ArrayMap;
51 import android.util.ArraySet;
52 import android.util.EventLog;
53 import android.util.Pair;
54 import android.util.Slog;
55 import android.util.SparseArray;
56 import android.util.TimeUtils;
57 import android.util.proto.ProtoOutputStream;
58 
59 import com.android.internal.annotations.GuardedBy;
60 import com.android.internal.app.ProcessMap;
61 import com.android.internal.logging.MetricsLogger;
62 import com.android.internal.logging.nano.MetricsProto;
63 import com.android.server.LocalServices;
64 import com.android.server.PackageWatchdog;
65 import com.android.server.usage.AppStandbyInternal;
66 import com.android.server.wm.WindowProcessController;
67 
68 import java.io.FileDescriptor;
69 import java.io.PrintWriter;
70 import java.util.Collections;
71 import java.util.List;
72 
73 /**
74  * Controls error conditions in applications.
75  */
76 class AppErrors {
77 
78     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppErrors" : TAG_AM;
79 
80     private final ActivityManagerService mService;
81     private final ActivityManagerGlobalLock mProcLock;
82     private final Context mContext;
83     private final PackageWatchdog mPackageWatchdog;
84 
85     @GuardedBy("mBadProcessLock")
86     private ArraySet<String> mAppsNotReportingCrashes;
87 
88     /**
89      * The last time that various processes have crashed since they were last explicitly started.
90      */
91     @GuardedBy("mBadProcessLock")
92     private final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<>();
93 
94     /**
95      * The last time that various processes have crashed (not reset even when explicitly started).
96      */
97     @GuardedBy("mBadProcessLock")
98     private final ProcessMap<Long> mProcessCrashTimesPersistent = new ProcessMap<>();
99 
100     /**
101      * The last time that various processes have crashed and shown an error dialog.
102      */
103     @GuardedBy("mBadProcessLock")
104     private final ProcessMap<Long> mProcessCrashShowDialogTimes = new ProcessMap<>();
105 
106     /**
107      * A pairing between how many times various processes have crashed since a given time.
108      * Entry and exit conditions for this map are similar to mProcessCrashTimes.
109      */
110     @GuardedBy("mBadProcessLock")
111     private final ProcessMap<Pair<Long, Integer>> mProcessCrashCounts = new ProcessMap<>();
112 
113     /**
114      * Set of applications that we consider to be bad, and will reject
115      * incoming broadcasts from (which the user has no control over).
116      * Processes are added to this set when they have crashed twice within
117      * a minimum amount of time; they are removed from it when they are
118      * later restarted (hopefully due to some user action).  The value is the
119      * time it was added to the list.
120      *
121      * Read access is UNLOCKED, and must either be based on a single lookup
122      * call on the current mBadProcesses instance, or a local copy of that
123      * reference must be made and the local copy treated as the source of
124      * truth.  Mutations are performed by synchronizing on mBadProcessLock,
125      * cloning the existing mBadProcesses instance, performing the mutation,
126      * then changing the volatile "live" mBadProcesses reference to point to the
127      * mutated version.  These operations are very rare compared to lookups:
128      * we intentionally trade additional cost for mutations for eliminating
129      * lock operations from the simple lookup cases.
130      */
131     private volatile ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
132 
133     /**
134      * Dedicated lock for {@link #mAppsNotReportingCrashes}, {@link #mProcessCrashTimes},
135      * {@link #mProcessCrashTimesPersistent}, {@link #mProcessCrashShowDialogTimes},
136      * {@link #mProcessCrashCounts} and {@link #mBadProcesses}.
137      *
138      * <p>The naming convention of the function with this lock should be "-LBp"</b>
139      *
140      * @See mBadProcesses
141      */
142     private final Object mBadProcessLock = new Object();
143 
AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog)144     AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog) {
145         context.assertRuntimeOverlayThemable();
146         mService = service;
147         mProcLock = service.mProcLock;
148         mContext = context;
149         mPackageWatchdog = watchdog;
150     }
151 
152     /** Resets the current state but leaves the constructor-provided fields unchanged. */
resetState()153     public void resetState() {
154         Slog.i(TAG, "Resetting AppErrors");
155         synchronized (mBadProcessLock) {
156             mAppsNotReportingCrashes.clear();
157             mProcessCrashTimes.clear();
158             mProcessCrashTimesPersistent.clear();
159             mProcessCrashShowDialogTimes.clear();
160             mProcessCrashCounts.clear();
161             mBadProcesses = new ProcessMap<>();
162         }
163     }
164 
165     @GuardedBy("mProcLock")
dumpDebugLPr(ProtoOutputStream proto, long fieldId, String dumpPackage)166     void dumpDebugLPr(ProtoOutputStream proto, long fieldId, String dumpPackage) {
167         final ProcessMap<BadProcessInfo> badProcesses = mBadProcesses;
168         if (mProcessCrashTimes.getMap().isEmpty() && badProcesses.getMap().isEmpty()) {
169             return;
170         }
171 
172         final long token = proto.start(fieldId);
173         final long now = SystemClock.uptimeMillis();
174         proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
175 
176         if (!badProcesses.getMap().isEmpty()) {
177             final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = badProcesses.getMap();
178             final int processCount = pmap.size();
179             for (int ip = 0; ip < processCount; ip++) {
180                 final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
181                 final String pname = pmap.keyAt(ip);
182                 final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
183                 final int uidCount = uids.size();
184 
185                 proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
186                 for (int i = 0; i < uidCount; i++) {
187                     final int puid = uids.keyAt(i);
188                     final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid);
189                     if (dumpPackage != null && (r == null
190                             || !r.getPkgList().containsKey(dumpPackage))) {
191                         continue;
192                     }
193                     final BadProcessInfo info = uids.valueAt(i);
194                     final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
195                     proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
196                     proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
197                     proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
198                     proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
199                     proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
200                     proto.end(etoken);
201                 }
202                 proto.end(btoken);
203             }
204         }
205 
206         synchronized (mBadProcessLock) {
207             if (!mProcessCrashTimes.getMap().isEmpty()) {
208                 final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
209                 final int procCount = pmap.size();
210                 for (int ip = 0; ip < procCount; ip++) {
211                     final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
212                     final String pname = pmap.keyAt(ip);
213                     final SparseArray<Long> uids = pmap.valueAt(ip);
214                     final int uidCount = uids.size();
215 
216                     proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
217                     for (int i = 0; i < uidCount; i++) {
218                         final int puid = uids.keyAt(i);
219                         final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid);
220                         if (dumpPackage != null
221                                 && (r == null || !r.getPkgList().containsKey(dumpPackage))) {
222                             continue;
223                         }
224                         final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
225                         proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
226                         proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
227                                 uids.valueAt(i));
228                         proto.end(etoken);
229                     }
230                     proto.end(ctoken);
231                 }
232             }
233         }
234 
235         proto.end(token);
236     }
237 
238     @GuardedBy("mProcLock")
dumpLPr(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage)239     boolean dumpLPr(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
240         final long now = SystemClock.uptimeMillis();
241         synchronized (mBadProcessLock) {
242             if (!mProcessCrashTimes.getMap().isEmpty()) {
243                 boolean printed = false;
244                 final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
245                 final int processCount = pmap.size();
246                 for (int ip = 0; ip < processCount; ip++) {
247                     final String pname = pmap.keyAt(ip);
248                     final SparseArray<Long> uids = pmap.valueAt(ip);
249                     final int uidCount = uids.size();
250                     for (int i = 0; i < uidCount; i++) {
251                         final int puid = uids.keyAt(i);
252                         final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid);
253                         if (dumpPackage != null
254                                 && (r == null || !r.getPkgList().containsKey(dumpPackage))) {
255                             continue;
256                         }
257                         if (!printed) {
258                             if (needSep) pw.println();
259                             needSep = true;
260                             pw.println("  Time since processes crashed:");
261                             printed = true;
262                         }
263                         pw.print("    Process "); pw.print(pname);
264                         pw.print(" uid "); pw.print(puid);
265                         pw.print(": last crashed ");
266                         TimeUtils.formatDuration(now - uids.valueAt(i), pw);
267                         pw.println(" ago");
268                     }
269                 }
270             }
271 
272             if (!mProcessCrashCounts.getMap().isEmpty()) {
273                 boolean printed = false;
274                 final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pmap =
275                         mProcessCrashCounts.getMap();
276                 final int processCount = pmap.size();
277                 for (int ip = 0; ip < processCount; ip++) {
278                     final String pname = pmap.keyAt(ip);
279                     final SparseArray<Pair<Long, Integer>> uids = pmap.valueAt(ip);
280                     final int uidCount = uids.size();
281                     for (int i = 0; i < uidCount; i++) {
282                         final int puid = uids.keyAt(i);
283                         final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid);
284                         if (dumpPackage != null
285                                 && (r == null || !r.getPkgList().containsKey(dumpPackage))) {
286                             continue;
287                         }
288                         if (!printed) {
289                             if (needSep) pw.println();
290                             needSep = true;
291                             pw.println("  First time processes crashed and counts:");
292                             printed = true;
293                         }
294                         pw.print("    Process "); pw.print(pname);
295                         pw.print(" uid "); pw.print(puid);
296                         pw.print(": first crashed ");
297                         TimeUtils.formatDuration(now - uids.valueAt(i).first, pw);
298                         pw.print(" ago; crashes since then: "); pw.println(uids.valueAt(i).second);
299                     }
300                 }
301             }
302         }
303 
304         final ProcessMap<BadProcessInfo> badProcesses = mBadProcesses;
305         if (!badProcesses.getMap().isEmpty()) {
306             boolean printed = false;
307             final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = badProcesses.getMap();
308             final int processCount = pmap.size();
309             for (int ip = 0; ip < processCount; ip++) {
310                 final String pname = pmap.keyAt(ip);
311                 final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
312                 final int uidCount = uids.size();
313                 for (int i = 0; i < uidCount; i++) {
314                     final int puid = uids.keyAt(i);
315                     final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid);
316                     if (dumpPackage != null && (r == null
317                             || !r.getPkgList().containsKey(dumpPackage))) {
318                         continue;
319                     }
320                     if (!printed) {
321                         if (needSep) pw.println();
322                         needSep = true;
323                         pw.println("  Bad processes:");
324                         printed = true;
325                     }
326                     final BadProcessInfo info = uids.valueAt(i);
327                     pw.print("    Bad process "); pw.print(pname);
328                     pw.print(" uid "); pw.print(puid);
329                     pw.print(": crashed at time "); pw.println(info.time);
330                     if (info.shortMsg != null) {
331                         pw.print("      Short msg: "); pw.println(info.shortMsg);
332                     }
333                     if (info.longMsg != null) {
334                         pw.print("      Long msg: "); pw.println(info.longMsg);
335                     }
336                     if (info.stack != null) {
337                         pw.println("      Stack:");
338                         int lastPos = 0;
339                         for (int pos = 0; pos < info.stack.length(); pos++) {
340                             if (info.stack.charAt(pos) == '\n') {
341                                 pw.print("        ");
342                                 pw.write(info.stack, lastPos, pos - lastPos);
343                                 pw.println();
344                                 lastPos = pos + 1;
345                             }
346                         }
347                         if (lastPos < info.stack.length()) {
348                             pw.print("        ");
349                             pw.write(info.stack, lastPos, info.stack.length() - lastPos);
350                             pw.println();
351                         }
352                     }
353                 }
354             }
355         }
356         return needSep;
357     }
358 
isBadProcess(final String processName, final int uid)359     boolean isBadProcess(final String processName, final int uid) {
360         // NO LOCKING for the simple lookup
361         return mBadProcesses.get(processName, uid) != null;
362     }
363 
clearBadProcess(final String processName, final int uid)364     void clearBadProcess(final String processName, final int uid) {
365         synchronized (mBadProcessLock) {
366             final ProcessMap<BadProcessInfo> badProcesses = new ProcessMap<>();
367             badProcesses.putAll(mBadProcesses);
368             badProcesses.remove(processName, uid);
369             mBadProcesses = badProcesses;
370         }
371     }
372 
markBadProcess(final String processName, final int uid, BadProcessInfo info)373     void markBadProcess(final String processName, final int uid, BadProcessInfo info) {
374         synchronized (mBadProcessLock) {
375             final ProcessMap<BadProcessInfo> badProcesses = new ProcessMap<>();
376             badProcesses.putAll(mBadProcesses);
377             badProcesses.put(processName, uid, info);
378             mBadProcesses = badProcesses;
379         }
380     }
381 
resetProcessCrashTime(final String processName, final int uid)382     void resetProcessCrashTime(final String processName, final int uid) {
383         synchronized (mBadProcessLock) {
384             mProcessCrashTimes.remove(processName, uid);
385             mProcessCrashCounts.remove(processName, uid);
386         }
387     }
388 
resetProcessCrashTime(boolean resetEntireUser, int appId, int userId)389     void resetProcessCrashTime(boolean resetEntireUser, int appId, int userId) {
390         synchronized (mBadProcessLock) {
391             final ArrayMap<String, SparseArray<Long>> pTimeMap = mProcessCrashTimes.getMap();
392             for (int ip = pTimeMap.size() - 1; ip >= 0; ip--) {
393                 SparseArray<Long> ba = pTimeMap.valueAt(ip);
394                 resetProcessCrashMapLBp(ba, resetEntireUser, appId, userId);
395                 if (ba.size() == 0) {
396                     pTimeMap.removeAt(ip);
397                 }
398             }
399 
400             final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pCountMap =
401                     mProcessCrashCounts.getMap();
402             for (int ip = pCountMap.size() - 1; ip >= 0; ip--) {
403                 SparseArray<Pair<Long, Integer>> ba = pCountMap.valueAt(ip);
404                 resetProcessCrashMapLBp(ba, resetEntireUser, appId, userId);
405                 if (ba.size() == 0) {
406                     pCountMap.removeAt(ip);
407                 }
408             }
409         }
410     }
411 
412     @GuardedBy("mBadProcessLock")
resetProcessCrashMapLBp(SparseArray<?> ba, boolean resetEntireUser, int appId, int userId)413     private void resetProcessCrashMapLBp(SparseArray<?> ba, boolean resetEntireUser,
414             int appId, int userId) {
415         for (int i = ba.size() - 1; i >= 0; i--) {
416             boolean remove = false;
417             final int entUid = ba.keyAt(i);
418             if (!resetEntireUser) {
419                 if (userId == UserHandle.USER_ALL) {
420                     if (UserHandle.getAppId(entUid) == appId) {
421                         remove = true;
422                     }
423                 } else {
424                     if (entUid == UserHandle.getUid(userId, appId)) {
425                         remove = true;
426                     }
427                 }
428             } else if (UserHandle.getUserId(entUid) == userId) {
429                 remove = true;
430             }
431             if (remove) {
432                 ba.removeAt(i);
433             }
434         }
435     }
436 
loadAppsNotReportingCrashesFromConfig(String appsNotReportingCrashesConfig)437     void loadAppsNotReportingCrashesFromConfig(String appsNotReportingCrashesConfig) {
438         if (appsNotReportingCrashesConfig != null) {
439             final String[] split = appsNotReportingCrashesConfig.split(",");
440             if (split.length > 0) {
441                 synchronized (mBadProcessLock) {
442                     mAppsNotReportingCrashes = new ArraySet<>();
443                     Collections.addAll(mAppsNotReportingCrashes, split);
444                 }
445             }
446         }
447     }
448 
449     @GuardedBy("mService")
killAppAtUserRequestLocked(ProcessRecord app)450     void killAppAtUserRequestLocked(ProcessRecord app) {
451         ErrorDialogController controller = app.mErrorState.getDialogController();
452 
453         int reasonCode = ApplicationExitInfo.REASON_ANR;
454         int subReason = ApplicationExitInfo.SUBREASON_UNKNOWN;
455         synchronized (mProcLock) {
456             if (controller.hasDebugWaitingDialog()) {
457                 reasonCode = ApplicationExitInfo.REASON_OTHER;
458                 subReason = ApplicationExitInfo.SUBREASON_WAIT_FOR_DEBUGGER;
459             }
460             controller.clearAllErrorDialogs();
461             killAppImmediateLSP(app, reasonCode, subReason,
462                     "user-terminated", "user request after error");
463         }
464     }
465 
466     @GuardedBy({"mService", "mProcLock"})
killAppImmediateLSP(ProcessRecord app, int reasonCode, int subReason, String reason, String killReason)467     private void killAppImmediateLSP(ProcessRecord app, int reasonCode, int subReason,
468             String reason, String killReason) {
469         final ProcessErrorStateRecord errState = app.mErrorState;
470         errState.setCrashing(false);
471         errState.setCrashingReport(null);
472         errState.setNotResponding(false);
473         errState.setNotRespondingReport(null);
474         final int pid = errState.mApp.getPid();
475         if (pid > 0 && pid != MY_PID) {
476             synchronized (mBadProcessLock) {
477                 handleAppCrashLSPB(app, reason,
478                         null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/);
479             }
480             app.killLocked(killReason, reasonCode, subReason, true);
481         }
482     }
483 
484     /**
485      * Induce a crash in the given app.
486      *
487      * @param uid if nonnegative, the required matching uid of the target to crash
488      * @param initialPid fast-path match for the target to crash
489      * @param packageName fallback match if the stated pid is not found or doesn't match uid
490      * @param userId If nonnegative, required to identify a match by package name
491      * @param message
492      */
scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, String message, boolean force, int exceptionTypeId, @Nullable Bundle extras)493     void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
494             String message, boolean force, int exceptionTypeId, @Nullable Bundle extras) {
495         ProcessRecord proc = null;
496 
497         // Figure out which process to kill.  We don't trust that initialPid
498         // still has any relation to current pids, so must scan through the
499         // list.
500 
501         synchronized (mService.mPidsSelfLocked) {
502             for (int i=0; i<mService.mPidsSelfLocked.size(); i++) {
503                 ProcessRecord p = mService.mPidsSelfLocked.valueAt(i);
504                 if (uid >= 0 && p.uid != uid) {
505                     continue;
506                 }
507                 if (p.getPid() == initialPid) {
508                     proc = p;
509                     break;
510                 }
511                 if (p.getPkgList().containsKey(packageName)
512                         && (userId < 0 || p.userId == userId)) {
513                     proc = p;
514                 }
515             }
516         }
517 
518         if (proc == null) {
519             Slog.w(TAG, "crashApplication: nothing for uid=" + uid
520                     + " initialPid=" + initialPid
521                     + " packageName=" + packageName
522                     + " userId=" + userId);
523             return;
524         }
525 
526         proc.scheduleCrashLocked(message, exceptionTypeId, extras);
527         if (force) {
528             // If the app is responsive, the scheduled crash will happen as expected
529             // and then the delayed summary kill will be a no-op.
530             final ProcessRecord p = proc;
531             mService.mHandler.postDelayed(
532                     () -> {
533                         synchronized (mService) {
534                             synchronized (mProcLock) {
535                                 killAppImmediateLSP(p, ApplicationExitInfo.REASON_OTHER,
536                                         ApplicationExitInfo.SUBREASON_INVALID_STATE,
537                                         "forced", "killed for invalid state");
538                             }
539                         }
540                     },
541                     5000L);
542         }
543     }
544 
545     /**
546      * Bring up the "unexpected error" dialog box for a crashing app.
547      * Deal with edge cases (intercepts from instrumented applications,
548      * ActivityController, error intent receivers, that sort of thing).
549      * @param r the application crashing
550      * @param crashInfo describing the failure
551      */
crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo)552     void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
553         final int callingPid = Binder.getCallingPid();
554         final int callingUid = Binder.getCallingUid();
555 
556         final long origId = Binder.clearCallingIdentity();
557         try {
558             crashApplicationInner(r, crashInfo, callingPid, callingUid);
559         } finally {
560             Binder.restoreCallingIdentity(origId);
561         }
562     }
563 
crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo, int callingPid, int callingUid)564     private void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
565             int callingPid, int callingUid) {
566         long timeMillis = System.currentTimeMillis();
567         String shortMsg = crashInfo.exceptionClassName;
568         String longMsg = crashInfo.exceptionMessage;
569         String stackTrace = crashInfo.stackTrace;
570         if (shortMsg != null && longMsg != null) {
571             longMsg = shortMsg + ": " + longMsg;
572         } else if (shortMsg != null) {
573             longMsg = shortMsg;
574         }
575 
576         if (r != null) {
577             mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
578                     PackageWatchdog.FAILURE_REASON_APP_CRASH);
579 
580             mService.mProcessList.noteAppKill(r, (crashInfo != null
581                       && "Native crash".equals(crashInfo.exceptionClassName))
582                       ? ApplicationExitInfo.REASON_CRASH_NATIVE
583                       : ApplicationExitInfo.REASON_CRASH,
584                       ApplicationExitInfo.SUBREASON_UNKNOWN,
585                     "crash");
586         }
587 
588         final int relaunchReason = r != null
589                 ? r.getWindowProcessController().computeRelaunchReason() : RELAUNCH_REASON_NONE;
590 
591         AppErrorResult result = new AppErrorResult();
592         int taskId;
593         synchronized (mService) {
594             /**
595              * If crash is handled by instance of {@link android.app.IActivityController},
596              * finish now and don't show the app error dialog.
597              */
598             if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
599                     timeMillis, callingPid, callingUid)) {
600                 return;
601             }
602 
603             // Suppress crash dialog if the process is being relaunched due to a crash during a free
604             // resize.
605             if (relaunchReason == RELAUNCH_REASON_FREE_RESIZE) {
606                 return;
607             }
608 
609             /**
610              * If this process was running instrumentation, finish now - it will be handled in
611              * {@link ActivityManagerService#handleAppDiedLocked}.
612              */
613             if (r != null && r.getActiveInstrumentation() != null) {
614                 return;
615             }
616 
617             // Log crash in battery stats.
618             if (r != null) {
619                 mService.mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
620             }
621 
622             AppErrorDialog.Data data = new AppErrorDialog.Data();
623             data.result = result;
624             data.proc = r;
625 
626             // If we can't identify the process or it's already exceeded its crash quota,
627             // quit right away without showing a crash dialog.
628             if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
629                 return;
630             }
631 
632             final Message msg = Message.obtain();
633             msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
634 
635             taskId = data.taskId;
636             msg.obj = data;
637             mService.mUiHandler.sendMessage(msg);
638         }
639 
640         int res = result.get();
641 
642         Intent appErrorIntent = null;
643         MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
644         if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
645             res = AppErrorDialog.FORCE_QUIT;
646         }
647         switch (res) {
648             case AppErrorDialog.MUTE:
649                 synchronized (mBadProcessLock) {
650                     stopReportingCrashesLBp(r);
651                 }
652                 break;
653             case AppErrorDialog.RESTART:
654                 synchronized (mService) {
655                     mService.mProcessList.removeProcessLocked(r, false, true,
656                             ApplicationExitInfo.REASON_CRASH, "crash");
657                 }
658                 if (taskId != INVALID_TASK_ID) {
659                     try {
660                         mService.startActivityFromRecents(taskId,
661                                 ActivityOptions.makeBasic().toBundle());
662                     } catch (IllegalArgumentException e) {
663                         // Hmm...that didn't work. Task should either be in recents or associated
664                         // with a stack.
665                         Slog.e(TAG, "Could not restart taskId=" + taskId, e);
666                     }
667                 }
668                 break;
669             case AppErrorDialog.FORCE_QUIT:
670                 final long orig = Binder.clearCallingIdentity();
671                 try {
672                     // Kill it with fire!
673                     mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
674                     if (!r.isPersistent()) {
675                         synchronized (mService) {
676                             mService.mProcessList.removeProcessLocked(r, false, false,
677                                     ApplicationExitInfo.REASON_CRASH, "crash");
678                         }
679                         mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
680                     }
681                 } finally {
682                     Binder.restoreCallingIdentity(orig);
683                 }
684                 break;
685             case AppErrorDialog.APP_INFO:
686                 appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
687                 appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
688                 appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
689                 break;
690             case AppErrorDialog.FORCE_QUIT_AND_REPORT:
691                 synchronized (mProcLock) {
692                     appErrorIntent = createAppErrorIntentLOSP(r, timeMillis, crashInfo);
693                 }
694                 break;
695         }
696 
697         if (appErrorIntent != null) {
698             try {
699                 mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
700             } catch (ActivityNotFoundException e) {
701                 Slog.w(TAG, "bug report receiver dissappeared", e);
702             }
703         }
704     }
705 
706     @GuardedBy("mService")
handleAppCrashInActivityController(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo, String shortMsg, String longMsg, String stackTrace, long timeMillis, int callingPid, int callingUid)707     private boolean handleAppCrashInActivityController(ProcessRecord r,
708                                                        ApplicationErrorReport.CrashInfo crashInfo,
709                                                        String shortMsg, String longMsg,
710                                                        String stackTrace, long timeMillis,
711                                                        int callingPid, int callingUid) {
712         String name = r != null ? r.processName : null;
713         int pid = r != null ? r.getPid() : callingPid;
714         int uid = r != null ? r.info.uid : callingUid;
715 
716         return mService.mAtmInternal.handleAppCrashInActivityController(
717                 name, pid, shortMsg, longMsg, timeMillis, crashInfo.stackTrace, () -> {
718                 if (Build.IS_DEBUGGABLE
719                         && "Native crash".equals(crashInfo.exceptionClassName)) {
720                     Slog.w(TAG, "Skip killing native crashed app " + name
721                             + "(" + pid + ") during testing");
722                 } else {
723                     Slog.w(TAG, "Force-killing crashed app " + name + " at watcher's request");
724                     if (r != null) {
725                         if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)) {
726                             r.killLocked("crash", ApplicationExitInfo.REASON_CRASH, true);
727                         }
728                     } else {
729                         // Huh.
730                         Process.killProcess(pid);
731                         ProcessList.killProcessGroup(uid, pid);
732                         mService.mProcessList.noteAppKill(pid, uid,
733                                 ApplicationExitInfo.REASON_CRASH,
734                                 ApplicationExitInfo.SUBREASON_UNKNOWN,
735                                 "crash");
736                     }
737                 }
738         });
739     }
740 
741     @GuardedBy("mService")
742     private boolean makeAppCrashingLocked(ProcessRecord app,
743             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
744         synchronized (mProcLock) {
745             final ProcessErrorStateRecord errState = app.mErrorState;
746             errState.setCrashing(true);
747             errState.setCrashingReport(generateProcessError(app,
748                     ActivityManager.ProcessErrorStateInfo.CRASHED,
749                     null, shortMsg, longMsg, stackTrace));
750             errState.startAppProblemLSP();
751             app.getWindowProcessController().stopFreezingActivities();
752             synchronized (mBadProcessLock) {
753                 return handleAppCrashLSPB(app, "force-crash" /*reason*/, shortMsg, longMsg,
754                         stackTrace, data);
755             }
756         }
757     }
758 
759     /**
760      * Generate a process error record, suitable for attachment to a ProcessRecord.
761      *
762      * @param app The ProcessRecord in which the error occurred.
763      * @param condition Crashing, Application Not Responding, etc.  Values are defined in
764      *                      ActivityManager.ProcessErrorStateInfo
765      * @param activity The activity associated with the crash, if known.
766      * @param shortMsg Short message describing the crash.
767      * @param longMsg Long message describing the crash.
768      * @param stackTrace Full crash stack trace, may be null.
769      *
770      * @return Returns a fully-formed ProcessErrorStateInfo record.
771      */
772     ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
773             int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
774         ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
775 
776         report.condition = condition;
777         report.processName = app.processName;
778         report.pid = app.getPid();
779         report.uid = app.info.uid;
780         report.tag = activity;
781         report.shortMsg = shortMsg;
782         report.longMsg = longMsg;
783         report.stackTrace = stackTrace;
784 
785         return report;
786     }
787 
788     @GuardedBy(anyOf = {"mService", "mProcLock"})
789     Intent createAppErrorIntentLOSP(ProcessRecord r,
790             long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
791         ApplicationErrorReport report = createAppErrorReportLOSP(r, timeMillis, crashInfo);
792         if (report == null) {
793             return null;
794         }
795         Intent result = new Intent(Intent.ACTION_APP_ERROR);
796         result.setComponent(r.mErrorState.getErrorReportReceiver());
797         result.putExtra(Intent.EXTRA_BUG_REPORT, report);
798         result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
799         return result;
800     }
801 
802     @GuardedBy(anyOf = {"mService", "mProcLock"})
803     private ApplicationErrorReport createAppErrorReportLOSP(ProcessRecord r,
804             long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
805         final ProcessErrorStateRecord errState = r.mErrorState;
806         if (errState.getErrorReportReceiver() == null) {
807             return null;
808         }
809 
810         if (!errState.isCrashing() && !errState.isNotResponding()
811                 && !errState.isForceCrashReport()) {
812             return null;
813         }
814 
815         ApplicationErrorReport report = new ApplicationErrorReport();
816         report.packageName = r.info.packageName;
817         report.installerPackageName = errState.getErrorReportReceiver().getPackageName();
818         report.processName = r.processName;
819         report.time = timeMillis;
820         report.systemApp = (r.info.flags & FLAG_SYSTEM) != 0;
821 
822         if (errState.isCrashing() || errState.isForceCrashReport()) {
823             report.type = ApplicationErrorReport.TYPE_CRASH;
824             report.crashInfo = crashInfo;
825         } else if (errState.isNotResponding()) {
826             report.type = ApplicationErrorReport.TYPE_ANR;
827             report.anrInfo = new ApplicationErrorReport.AnrInfo();
828 
829             report.anrInfo.activity = errState.getNotRespondingReport().tag;
830             report.anrInfo.cause = errState.getNotRespondingReport().shortMsg;
831             report.anrInfo.info = errState.getNotRespondingReport().longMsg;
832         }
833 
834         return report;
835     }
836 
837     @GuardedBy({"mService", "mProcLock", "mBadProcessLock"})
838     private boolean handleAppCrashLSPB(ProcessRecord app, String reason,
839             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
840         final long now = SystemClock.uptimeMillis();
841         final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
842                 Settings.Secure.ANR_SHOW_BACKGROUND, 0,
843                 mService.mUserController.getCurrentUserId()) != 0;
844 
845         Long crashTime;
846         Long crashTimePersistent;
847         final String processName = app.processName;
848         final int uid = app.uid;
849         final int userId = app.userId;
850         final boolean isolated = app.isolated;
851         final boolean persistent = app.isPersistent();
852         final WindowProcessController proc = app.getWindowProcessController();
853         final ProcessErrorStateRecord errState = app.mErrorState;
854 
855         if (!app.isolated) {
856             crashTime = mProcessCrashTimes.get(processName, uid);
857             crashTimePersistent = mProcessCrashTimesPersistent.get(processName, uid);
858         } else {
859             crashTime = crashTimePersistent = null;
860         }
861 
862         // Bump up the crash count of any services currently running in the proc.
863         boolean tryAgain = app.mServices.incServiceCrashCountLocked(now);
864 
865         final boolean quickCrash = crashTime != null
866                 && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
867         if (quickCrash || isProcOverCrashLimitLBp(app, now)) {
868             // The process either crashed again very quickly or has been crashing periodically in
869             // the last few hours. If it was a bound foreground service, let's try to restart again
870             // in a while, otherwise the process loses!
871             Slog.w(TAG, "Process " + processName + " has crashed too many times, killing!"
872                     + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit"));
873             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
874                     userId, processName, uid);
875             mService.mAtmInternal.onHandleAppCrash(proc);
876             if (!persistent) {
877                 // We don't want to start this process again until the user
878                 // explicitly does so...  but for persistent process, we really
879                 // need to keep it running.  If a persistent process is actually
880                 // repeatedly crashing, then badness for everyone.
881                 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, userId, uid,
882                         processName);
883                 if (!isolated) {
884                     // XXX We don't have a way to mark isolated processes
885                     // as bad, since they don't have a persistent identity.
886                     markBadProcess(processName, app.uid,
887                             new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
888                     mProcessCrashTimes.remove(processName, app.uid);
889                     mProcessCrashCounts.remove(processName, app.uid);
890                 }
891                 errState.setBad(true);
892                 app.setRemoved(true);
893                 final AppStandbyInternal appStandbyInternal =
894                         LocalServices.getService(AppStandbyInternal.class);
895                 if (appStandbyInternal != null) {
896                     appStandbyInternal.restrictApp(
897                             // Sometimes the processName is the same as the package name, so use
898                             // that if we don't have the ApplicationInfo object.
899                             // AppStandbyController will just return if it can't find the app.
900                             app.info != null ? app.info.packageName : processName,
901                             userId, UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
902                 }
903                 // Don't let services in this process be restarted and potentially
904                 // annoy the user repeatedly.  Unless it is persistent, since those
905                 // processes run critical code.
906                 mService.mProcessList.removeProcessLocked(app, false, tryAgain,
907                         ApplicationExitInfo.REASON_CRASH, "crash");
908                 mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
909                 if (!showBackground) {
910                     return false;
911                 }
912             }
913             mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
914         } else {
915             final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
916                             proc, reason);
917             if (data != null) {
918                 data.taskId = affectedTaskId;
919             }
920             if (data != null && crashTimePersistent != null
921                     && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
922                 data.repeating = true;
923             }
924         }
925 
926         if (data != null && tryAgain) {
927             data.isRestartableForService = true;
928         }
929 
930         // If the crashing process is what we consider to be the "home process" and it has been
931         // replaced by a third-party app, clear the package preferred activities from packages
932         // with a home activity running in the process to prevent a repeatedly crashing app
933         // from blocking the user to manually clear the list.
934         if (proc.isHomeProcess() && proc.hasActivities() && (app.info.flags & FLAG_SYSTEM) == 0) {
935             proc.clearPackagePreferredForHomeActivities();
936         }
937 
938         if (!isolated) {
939             // XXX Can't keep track of crash times for isolated processes,
940             // because they don't have a persistent identity.
941             mProcessCrashTimes.put(processName, uid, now);
942             mProcessCrashTimesPersistent.put(processName, uid, now);
943             updateProcessCrashCountLBp(processName, uid, now);
944         }
945 
946         if (errState.getCrashHandler() != null) {
947             mService.mHandler.post(errState.getCrashHandler());
948         }
949         return true;
950     }
951 
952     @GuardedBy("mBadProcessLock")
953     private void updateProcessCrashCountLBp(String processName, int uid, long now) {
954         Pair<Long, Integer> count = mProcessCrashCounts.get(processName, uid);
955         if (count == null || (count.first + PROCESS_CRASH_COUNT_RESET_INTERVAL) < now) {
956             count = new Pair<>(now, 1);
957         } else {
958             count = new Pair<>(count.first, count.second + 1);
959         }
960         mProcessCrashCounts.put(processName, uid, count);
961     }
962 
963     @GuardedBy("mBadProcessLock")
964     private boolean isProcOverCrashLimitLBp(ProcessRecord app, long now) {
965         final Pair<Long, Integer> crashCount = mProcessCrashCounts.get(app.processName, app.uid);
966         return !app.isolated && crashCount != null
967                 && now < (crashCount.first + PROCESS_CRASH_COUNT_RESET_INTERVAL)
968                 && crashCount.second >= PROCESS_CRASH_COUNT_LIMIT;
969     }
970 
971     void handleShowAppErrorUi(Message msg) {
972         AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
973         boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
974                 Settings.Secure.ANR_SHOW_BACKGROUND, 0,
975                 mService.mUserController.getCurrentUserId()) != 0;
976 
977         final int userId;
978         synchronized (mProcLock) {
979             final ProcessRecord proc = data.proc;
980             final AppErrorResult res = data.result;
981             if (proc == null) {
982                 Slog.e(TAG, "handleShowAppErrorUi: proc is null");
983                 return;
984             }
985             final ProcessErrorStateRecord errState = proc.mErrorState;
986             userId = proc.userId;
987             if (errState.getDialogController().hasCrashDialogs()) {
988                 Slog.e(TAG, "App already has crash dialog: " + proc);
989                 if (res != null) {
990                     res.set(AppErrorDialog.ALREADY_SHOWING);
991                 }
992                 return;
993             }
994             boolean isBackground = (UserHandle.getAppId(proc.uid)
995                     >= Process.FIRST_APPLICATION_UID
996                     && proc.getPid() != MY_PID);
997             for (int profileId : mService.mUserController.getCurrentProfileIds()) {
998                 isBackground &= (userId != profileId);
999             }
1000             if (isBackground && !showBackground) {
1001                 Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
1002                 if (res != null) {
1003                     res.set(AppErrorDialog.BACKGROUND_USER);
1004                 }
1005                 return;
1006             }
1007             Long crashShowErrorTime = null;
1008             synchronized (mBadProcessLock) {
1009                 if (!proc.isolated) {
1010                     crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.processName,
1011                             proc.uid);
1012                 }
1013                 final boolean showFirstCrash = Settings.Global.getInt(
1014                         mContext.getContentResolver(),
1015                         Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
1016                 final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
1017                         mContext.getContentResolver(),
1018                         Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
1019                         0,
1020                         mService.mUserController.getCurrentUserId()) != 0;
1021                 final boolean crashSilenced = mAppsNotReportingCrashes != null
1022                         && mAppsNotReportingCrashes.contains(proc.info.packageName);
1023                 final long now = SystemClock.uptimeMillis();
1024                 final boolean shouldThottle = crashShowErrorTime != null
1025                         && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
1026                 if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
1027                         && !crashSilenced && !shouldThottle
1028                         && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
1029                     errState.getDialogController().showCrashDialogs(data);
1030                     if (!proc.isolated) {
1031                         mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
1032                     }
1033                 } else {
1034                     // The device is asleep, so just pretend that the user
1035                     // saw a crash dialog and hit "force quit".
1036                     if (res != null) {
1037                         res.set(AppErrorDialog.CANT_SHOW);
1038                     }
1039                 }
1040             }
1041         }
1042     }
1043 
1044     @GuardedBy("mBadProcessLock")
1045     private void stopReportingCrashesLBp(ProcessRecord proc) {
1046         if (mAppsNotReportingCrashes == null) {
1047             mAppsNotReportingCrashes = new ArraySet<>();
1048         }
1049         mAppsNotReportingCrashes.add(proc.info.packageName);
1050     }
1051 
1052     void handleShowAnrUi(Message msg) {
1053         List<VersionedPackage> packageList = null;
1054         boolean doKill = false;
1055         AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
1056         final ProcessRecord proc = data.proc;
1057         if (proc == null) {
1058             Slog.e(TAG, "handleShowAnrUi: proc is null");
1059             return;
1060         }
1061         synchronized (mProcLock) {
1062             final ProcessErrorStateRecord errState = proc.mErrorState;
1063             if (!proc.isPersistent()) {
1064                 packageList = proc.getPackageListWithVersionCode();
1065             }
1066             if (errState.getDialogController().hasAnrDialogs()) {
1067                 Slog.e(TAG, "App already has anr dialog: " + proc);
1068                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
1069                         AppNotRespondingDialog.ALREADY_SHOWING);
1070                 return;
1071             }
1072 
1073             boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
1074                     Settings.Secure.ANR_SHOW_BACKGROUND, 0,
1075                     mService.mUserController.getCurrentUserId()) != 0;
1076             if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
1077                 AnrController anrController = errState.getDialogController().getAnrController();
1078                 if (anrController == null) {
1079                     errState.getDialogController().showAnrDialogs(data);
1080                 } else {
1081                     String packageName = proc.info.packageName;
1082                     int uid = proc.info.uid;
1083                     boolean showDialog = anrController.onAnrDelayCompleted(packageName, uid);
1084 
1085                     if (showDialog) {
1086                         Slog.d(TAG, "ANR delay completed. Showing ANR dialog for package: "
1087                                 + packageName);
1088                         errState.getDialogController().showAnrDialogs(data);
1089                     } else {
1090                         Slog.d(TAG, "ANR delay completed. Cancelling ANR dialog for package: "
1091                                 + packageName);
1092                         errState.setNotResponding(false);
1093                         errState.setNotRespondingReport(null);
1094                         errState.getDialogController().clearAnrDialogs();
1095                     }
1096                 }
1097             } else {
1098                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
1099                         AppNotRespondingDialog.CANT_SHOW);
1100                 // Just kill the app if there is no dialog to be shown.
1101                 doKill = true;
1102             }
1103         }
1104         if (doKill) {
1105             mService.killAppAtUsersRequest(proc);
1106         }
1107         // Notify PackageWatchdog without the lock held
1108         if (packageList != null) {
1109             mPackageWatchdog.onPackageFailure(packageList,
1110                     PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
1111         }
1112     }
1113 
1114     /**
1115      * Information about a process that is currently marked as bad.
1116      */
1117     static final class BadProcessInfo {
1118         BadProcessInfo(long time, String shortMsg, String longMsg, String stack) {
1119             this.time = time;
1120             this.shortMsg = shortMsg;
1121             this.longMsg = longMsg;
1122             this.stack = stack;
1123         }
1124 
1125         final long time;
1126         final String shortMsg;
1127         final String longMsg;
1128         final String stack;
1129     }
1130 
1131 }
1132