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