• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
21 
22 import android.content.pm.ApplicationInfo;
23 import android.os.SystemClock;
24 import android.util.Slog;
25 
26 import com.android.internal.annotations.GuardedBy;
27 import com.android.server.wm.WindowProcessController;
28 
29 import java.util.ArrayList;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 
33 /**
34  * The helper class to handle no response process. An independent thread will be created on demand
35  * so the caller can report the ANR without worrying about taking long time.
36  */
37 class AnrHelper {
38     private static final String TAG = TAG_WITH_CLASS_NAME ? "AnrHelper" : TAG_AM;
39 
40     /**
41      * If the system is extremely slow somehow that the ANR has been pending too long for more than
42      * this time, the information might be outdated. So we only the dump the unresponsive process
43      * instead of including other processes to avoid making the system more busy.
44      */
45     private static final long EXPIRED_REPORT_TIME_MS = TimeUnit.MINUTES.toMillis(1);
46 
47     @GuardedBy("mAnrRecords")
48     private final ArrayList<AnrRecord> mAnrRecords = new ArrayList<>();
49     private final AtomicBoolean mRunning = new AtomicBoolean(false);
50 
appNotResponding(ProcessRecord anrProcess, String annotation)51     void appNotResponding(ProcessRecord anrProcess, String annotation) {
52         appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
53                 null /* parentShortComponentName */, null /* parentProcess */,
54                 false /* aboveSystem */, annotation);
55     }
56 
appNotResponding(ProcessRecord anrProcess, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation)57     void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
58             ApplicationInfo aInfo, String parentShortComponentName,
59             WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
60         synchronized (mAnrRecords) {
61             mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
62                     parentShortComponentName, parentProcess, aboveSystem, annotation));
63         }
64         startAnrConsumerIfNeeded();
65     }
66 
startAnrConsumerIfNeeded()67     private void startAnrConsumerIfNeeded() {
68         if (mRunning.compareAndSet(false, true)) {
69             new AnrConsumerThread().start();
70         }
71     }
72 
73     /**
74      * The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
75      * records are handled.
76      */
77     private class AnrConsumerThread extends Thread {
AnrConsumerThread()78         AnrConsumerThread() {
79             super("AnrConsumer");
80         }
81 
next()82         private AnrRecord next() {
83             synchronized (mAnrRecords) {
84                 return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
85             }
86         }
87 
88         @Override
run()89         public void run() {
90             AnrRecord r;
91             while ((r = next()) != null) {
92                 final long startTime = SystemClock.uptimeMillis();
93                 // If there are many ANR at the same time, the latency may be larger. If the latency
94                 // is too large, the stack trace might not be meaningful.
95                 final long reportLatency = startTime - r.mTimestamp;
96                 final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
97                 r.appNotResponding(onlyDumpSelf);
98                 final long endTime = SystemClock.uptimeMillis();
99                 Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
100                         + (endTime - startTime) + "ms, latency " + reportLatency
101                         + (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
102             }
103 
104             mRunning.set(false);
105             synchronized (mAnrRecords) {
106                 // The race should be unlikely to happen. Just to make sure we don't miss.
107                 if (!mAnrRecords.isEmpty()) {
108                     startAnrConsumerIfNeeded();
109                 }
110             }
111         }
112     }
113 
114     private static class AnrRecord {
115         final ProcessRecord mApp;
116         final String mActivityShortComponentName;
117         final String mParentShortComponentName;
118         final String mAnnotation;
119         final ApplicationInfo mAppInfo;
120         final WindowProcessController mParentProcess;
121         final boolean mAboveSystem;
122         final long mTimestamp = SystemClock.uptimeMillis();
123 
AnrRecord(ProcessRecord anrProcess, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation)124         AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
125                 ApplicationInfo aInfo, String parentShortComponentName,
126                 WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
127             mApp = anrProcess;
128             mActivityShortComponentName = activityShortComponentName;
129             mParentShortComponentName = parentShortComponentName;
130             mAnnotation = annotation;
131             mAppInfo = aInfo;
132             mParentProcess = parentProcess;
133             mAboveSystem = aboveSystem;
134         }
135 
appNotResponding(boolean onlyDumpSelf)136         void appNotResponding(boolean onlyDumpSelf) {
137             mApp.appNotResponding(mActivityShortComponentName, mAppInfo,
138                     mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,
139                     onlyDumpSelf);
140         }
141     }
142 }
143