Android R Input 之ANR的产生与显示流程
Posted pecuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android R Input 之ANR的产生与显示流程相关的知识,希望对你有一定的参考价值。
文章托管在gitee上 Android Notes , 同步csdn
在InputDispatcher的工作流程中,分析过过ANR相关的部分内容,这一篇来详细分析ANR的产生与显示流程
ANR 的检查
在InputDispatcher的dispatchOnce方法中,会在执行完事件派发与Commands后,通过processAnrsLocked方法处理ANR.
/// @frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnce()
nsecs_t nextWakeupTime = LONG_LONG_MAX;
// acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all(); // 通知dispatcher线程还活跃, 用于检测死锁
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) // 如果没有commands 则进行事件分发
dispatchOnceInnerLocked(&nextWakeupTime);
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) // 执行commands
nextWakeupTime = LONG_LONG_MIN; // 立即进行下一轮的派发
// If we are still waiting for ack on some events,
// we might have to wake up earlier to check if an app is anr'ing.
const nsecs_t nextAnrCheck = processAnrsLocked(); // 处理anr
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LONG_LONG_MAX)
mDispatcherEnteredIdle.notify_all(); // 通知进入idle
// release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis); // 等待进行下一轮循环
InputDispatcher::processAnrsLocked
这个方法用来处理ANR,返回值表示下次唤醒的时间,方法逻辑如下:
- 如果有在等待出现焦点窗口的操作,判断是否有超时,如果出现超时,则会调用 onAnrLocked 通知出现ANR
- 对所有的connection检查是否有ANR出现,出现则调用onAnrLocked 通知出现ANR
怎么理解Connection ANR? 在InputDispatcher的工作流程分析中可知, 派发了一个事件到目标窗口后,会将事件从Connection 的 outboundQueue -> waitQueue , 并添加到mAnrTracker 进行ANR追踪.AnrTracker存储了以该事件的超时时间为key,以InputChanel的token为value的记录(即<timeout,token>).如果client处理该事件后在timeout时间内发送事件反馈,则会将之前的ANR追踪记录清除(移除waitQueue和AnrTracker中的记录,),反之,那么就说明该事件处理超时,触发ANR.
/**
* Check if any of the connections' wait queues have events that are too old.
* If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
* Return the time at which we should wake up next.
*/
nsecs_t InputDispatcher::processAnrsLocked()
const nsecs_t currentTime = now();
nsecs_t nextAnrCheck = LONG_LONG_MAX;
// Check if we are waiting for a focused window to appear. Raise ANR if waited too long
if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) // 等待焦点应用的focused 窗口出现
if (currentTime >= *mNoFocusedWindowTimeoutTime) // 等待超时
onAnrLocked(mAwaitedFocusedApplication); // 通知ANR , 注意此处的参数是inputApplicationHandle
mAwaitedFocusedApplication.clear(); // 清除等待焦点应用信息
return LONG_LONG_MIN; // 立即进行下一轮循环
else
// Keep waiting 继续等待焦点窗口出现, 计算到超时事件还有多久
const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);
ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);
nextAnrCheck = *mNoFocusedWindowTimeoutTime;
// Check if any connection ANRs are due 检查是否有connection中的ANR触发时间到了
nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); // 取出mAnrTracker最近的超时时间
if (currentTime < nextAnrCheck) // most likely scenario 还没到最近的超时时间,即还没发生ANR
return nextAnrCheck; // everything is normal. Let's check again at nextAnrCheck
// If we reached here, we have an unresponsive connection.
sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
if (connection == nullptr) // 检查对于的connection是否存在
ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
return nextAnrCheck;
connection->responsive = false; // 修改为未响应
// Stop waking up for this unresponsive connection
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); // 移除此token对应的记录
onAnrLocked(connection); // 通知ANR发生, 注意此处的参数是 Connection
return LONG_LONG_MIN; // 立即进行下一轮循环
InputDispatcher::onAnrLocked
以参数为Connection的为例
void InputDispatcher::onAnrLocked(const sp<Connection>& connection)
// Since we are allowing the policy to extend the timeout, maybe the waitQueue
// is already healthy again. Don't raise ANR in this situation
if (connection->waitQueue.empty()) // 如果此时waitQueue为空,没有等待反馈的事件,不触发ANR.此种情况说明Connection恢复正常
ALOGI("Not raising ANR because the connection %s has recovered",
connection->inputChannel->getName().c_str());
return;
/**
* The "oldestEntry" is the entry that was first sent to the application. That entry, however,
* may not be the one that caused the timeout to occur. One possibility is that window timeout
* has changed. This could cause newer entries to time out before the already dispatched
* entries. In that situation, the newest entries caused ANR. But in all likelihood, the app
* processes the events linearly. So providing information about the oldest entry seems to be
* most useful.
*/
DispatchEntry* oldestEntry = *connection->waitQueue.begin(); // 第一个超时没有收到反馈的事件
const nsecs_t currentWait = now() - oldestEntry->deliveryTime; // 等待事件,与派发时的时间差
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
connection->inputChannel->getName().c_str(),
ns2ms(currentWait),
oldestEntry->eventEntry->getDescription().c_str()); // 未响应原因
// 记录ANR信息
updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
reason);
// 将ANR处理的操作封装为command投递到队列. 处理command会调用 doNotifyAnrLockedInterruptible函数
std::unique_ptr<CommandEntry> commandEntry =
std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
commandEntry->inputApplicationHandle = nullptr;
commandEntry->inputChannel = connection->inputChannel; // 指定inputChannel
commandEntry->reason = std::move(reason);
postCommandLocked(std::move(commandEntry));
InputDispatcher::doNotifyAnrLockedInterruptible
在onAnrLocked方法中post command到mCommandQueue, 在InputDispatcher的下一轮循环首先执行Command,会回调doNotifyAnrLockedInterruptible方法
void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry)
sp<IBinder> token =
commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
mLock.unlock();
const nsecs_t timeoutExtension = // 通过策略派发ANR, 返回值表示是否需要延长ANR超时时间
mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason); // mPolicy 即 NativeInputManager
mLock.lock();
if (timeoutExtension > 0) // 延长ANR超时时间
extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension);
else
// stop waking up for events in this connection, it is already not responding
sp<Connection> connection = getConnectionLocked(token);
if (connection == nullptr)
return;
cancelEventsForAnrLocked(connection); // 对Connection 发送取消事件
NativeInputManager::notifyAnr
注意 此方法是在InputDispatcher线程中被调用
/// @frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<IBinder>& token, const std::string& reason)
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
ATRACE_CALL();
JNIEnv* env = jniEnv();
ScopedLocalFrame localFrame(env);
jobject inputApplicationHandleObj =
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
jobject tokenObj = javaObjectForIBinder(env, token); // InputChanel token
jstring reasonObj = env->NewStringUTF(reason.c_str());
jlong newTimeout = env->CallLongMethod(mServiceObj, // 回调 IMS的 notifyANR
gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR"))
newTimeout = 0; // abort dispatch
else
assert(newTimeout >= 0);
return newTimeout;
InputManagerService#notifyANR
/// @frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason)
return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, // 此处的mWindowManagerCallbacks实际上是WMS的成员mInputManagerCallback
token, reason);
InputManagerCallback#notifyANR
此方法是在InputDispatcher线程中被调用,不能做耗时操作.
/// @frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
/**
* Notifies the window manager about an application that is not responding.
* Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
*
* Called by the InputManager.
*/
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason)
final long startTime = SystemClock.uptimeMillis();
try
return notifyANRInner(inputApplicationHandle, token, reason); // 调用 notifyANRInner
finally
// Log the time because the method is called from InputDispatcher thread. It shouldn't
// take too long that may affect input response time.
Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms");
InputManagerCallback#notifyANRInner
private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason)
ActivityRecord activity = null;
WindowState windowState = null;
boolean aboveSystem = false;
int windowPid = INVALID_PID;
preDumpIfLockTooSlow();
//TODO(b/141764879) Limit scope of wm lock when input calls notifyANR
synchronized (mService.mGlobalLock)
// 首先根据Window类型,计算ANR对话框需要的层级值
// Check if we can blame a window
if (token != null)
windowState = mService.mInputToWindowMap.get(token);
if (windowState != null)
activity = windowState.mActivityRecord;
windowPid = windowState.mSession.mPid;
// Figure out whether this window is layered above system windows.
// We need to do this here to help the activity manager know how to
// layer its ANR dialog.
aboveSystem = isWindowAboveSystem(windowState);
// Check if we can blame an embedded window
if (token != null && windowState == null)
EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(token);
if (embeddedWindow != null)
windowPid = embeddedWindow.mOwnerPid;
WindowState hostWindowState = embeddedWindow.mHostWindowState;
if (hostWindowState == null)
// The embedded window has no host window and we cannot easily determine
// its z order. Try to place the anr dialog as high as possible.
aboveSystem = true;
else
aboveSystem = isWindowAboveSystem(hostWindowState);
// Check if we can blame an activity. If we don't have an activity to blame, pull out
// the token passed in via input application handle. This can happen if there are no
// focused windows but input dispatcher knows the focused app.
if (activity == null && inputApplicationHandle != null)
activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token);
if (windowState != null)
Slog.i(TAG_WM, "Input event dispatching timed out "
+ "sending to " + windowState.mAttrs.getTitle()
+ ". Reason: " + reason);
else if (activity != null)
Slog.i(TAG_WM, "Input event dispatching timed out "
+ "sending to application " + activity.stringName
+ ". Reason: " + reason);
else
Slog.i(TAG_WM, "Input event dispatching timed out "
+ ". Reason: " + reason);
mService.saveANRStateLocked(activity, windowState, reason); // WMS保持ANR状态
// All the calls below need to happen without the WM lock held since they call into AM.
mService.mAtmInternal.saveANRState(reason); //atms dump ANR信息 Dump of the activity state at the time of the last ANR
if (activity != null && activity.appToken != null) // 是一个Activity
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid);// 最终也调用AMS的inputDispatchingTimedOut
if (!abort)
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
return activity.mInputDispatchingTimeoutNanos;
else if (windowState != null || windowPid != INVALID_PID) // 是一个窗口
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
reason); // 调用AMS的inputDispatchingTimedOut
if (timeout >= 0)
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
return timeout * 1000000L; // nanoseconds
return 0; // abort dispatching
ActivityRecord#keyDispatchingTimedOut
/**
* Called when the key dispatching to a window associated with the app window container
* timed-out.
*
* @param reason The reason for the key dispatching time out.
* @param windowPid The pid of the window key dispatching timed out on.
* @return True if input dispatching should be aborted.
*/
public boolean keyDispatchingTimedOut(String reason, int windowPid)
ActivityRecord anrActivity;
WindowProcessController anrApp;
boolean windowFromSameProcessAsActivity;
synchronized (mAtmService.mGlobalLock)
anrActivity = getWaitingHistoryRecordLocked();
anrApp = app;
windowFromSameProcessAsActivity =
!hasProcess() || app.getPid() == windowPid || windowPid == INVALID_PID;
if (windowFromSameProcessAsActivity) // 同一进程
return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
anrActivity.shortComponentName, anrActivity.info.applicationInfo,
shortComponentName, app, false, reason); // 调用AMS的inputDispatchingTimedOut
else
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
return mAtmService.mAmInternal.inputDispatchingTimedOut(
windowPid, false /* aboveSystem */, reason) < 0;
ActivityManagerService$LocalService#inputDispatchingTimedOut
// ActivityManagerInternal
@Override
public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
return ActivityManagerService.this.inputDispatchingTimedOut(pid, aboveSystem, reason);
ActivityManagerService#inputDispatchingTimedOut(int pid,…)
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason)
if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED)
throw new SecurityException("Requires permission " + FILTER_EVENTS);
ProcessRecord proc;
long timeout;
synchronized (this)
synchronized (mPidsSelfLocked)
proc = mPidsSelfLocked.get(pid);
timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
// 调用同名方法
if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason))
return -1;
return timeout;
ActivityManagerService#inputDispatchingTimedOut(ProcessRecord proc,…)
/**
* Handle input dispatching timeouts.
* @return whether input dispatching should be aborted or not.
*/
boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String reason)
if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED)
throw new SecurityException("Requires permission " + FILTER_EVENTS);
final String annotation;
if (reason == null)
annotation = "Input dispatching timed out";
else
annotation = "Input dispatching timed out (" + reason + ")";
if (proc != null)
synchronized (this)
if (proc.isDebugging()) // debug将延长ANR超时
return false;
if (proc.getActiveInstrumentation() != null) // 处理ActiveInstrumentation
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
return true;
// 通过AnrHelper调用appNotResponding
mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation);
return true;
AnrHelper#appNotResponding
/// @frameworks/base/services/core/java/com/android/server/am/AnrHelper.java
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation)
synchronized (mAnrRecords)
// 添加ANR记录
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
startAnrConsumerIfNeeded();
AnrHelper#startAnrConsumerIfNeeded
private void startAnrConsumerIfNeeded()
if (mRunning.compareAndSet(false, true))
new AnrConsumerThread().start(); // 处理ANR线程
AnrConsumerThread#start
启动线程执行run方法
/**
* The thread to execute @link ProcessRecord#appNotResponding. It will terminate if all
* records are handled.
*/
private class AnrConsumerThread extends Thread
AnrConsumerThread()
super("AnrConsumer");
private AnrRecord next()
synchronized (mAnrRecords)
return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
@Override
public void run()
AnrRecord r;
while ((r = next()) != null) // 循环处理所有的AnrRecord
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
final long reportLatency = startTime - r.mTimestamp;
final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
r.appNotResponding(onlyDumpSelf); // 调用AnrRecord的appNotResponding
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
+ (endTime - startTime) + "ms, latency " + reportLatency
+ (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
mRunning.set(false);
synchronized (mAnrRecords)
// The race should be unlikely to happen. Just to make sure we don't miss.
if (!mAnrRecords.isEmpty()) // 如果还有记录, 则执行下一次处理
startAnrConsumerIfNeeded();
AnrRecord#appNotResponding直接调用了 ProcessRecord#appNotResponding
ProcessRecord#appNotResponding
具体记录ANR信息
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, String annotation, boolean onlyDumpSelf)
ArrayList<Integer> firstPids = new ArrayList<>(5);
SparseArray<Boolean> lastPids = new SparseArray<>(20);
mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr",
ApplicationExitInfo.REASON_ANR, true));
long anrTime = SystemClock.uptimeMillis();
if (isMonitorCpuUsage())
mService.updateCpuStatsNow();
final boolean isSilentAnr;
synchronized (mService) // 一些特殊情况,直接返回
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
if (mService.mAtmInternal.isShuttingDown())
Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
return;
else if (isNotResponding())
Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
return;
else if (isCrashing())
Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
return;
else if (killedByAm)
Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
return;
else if (killed)
Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
return;
// In case we come through here for the same app before completing
// this one, mark as anring now so we will bail out.
setNotResponding(true);
// Log the ANR to the event log. 将ANR写入Event log
EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
annotation);
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(pid);
// Don't dump other PIDs if it's a background ANR or is requested to only dump self.
isSilentAnr = isSilentAnr();
if (!isSilentAnr && !onlyDumpSelf)
int parentPid = pid;
if (parentProcess != null && parentProcess.getPid() > 0)
parentPid = parentProcess.getPid();
if (parentPid != pid) firstPids.add(parentPid);
if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID);
for (int i = getLruProcessList().size() - 1; i >= 0; i--)
ProcessRecord r = getLruProcessList().get(i);
if (r != null && r.thread != null)
int myPid = r.pid;
if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID)
if (r.isPersistent())
firstPids.add(myPid);
if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
else if (r.treatLikeActivity)
firstPids.add(myPid);
if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
else
lastPids.put(myPid, Boolean.TRUE);
if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
// Log the ANR to the main log.
StringBuilder info = new StringBuilder();
info.setLength(0);
info.append("ANR in ").append(processName);
if (activityShortComponentName != null)
info.append(" (").append(activityShortComponentName).append(")");
info.append("\\n");
info.append("PID: ").append(pid).append("\\n");
if (annotation != null)
info.append("Reason: ").append(annotation).append("\\n");
if (parentShortComponentName != null
&& parentShortComponentName.equals(activityShortComponentName))
info.append("Parent: ").append(parentShortComponentName).append("\\n");
StringBuilder report = new StringBuilder();
report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
ArrayList<Integer> nativePids = null;
// don't dump native PIDs for background ANRs unless it is the process of interest
String[] nativeProc = null;
if (isSilentAnr || onlyDumpSelf)
for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++)
if (NATIVE_STACKS_OF_INTEREST[i].equals(processName))
nativeProc = new String[] processName ;
break;
int[] pid = nativeProc == null ? null : Process.getPidsForCommands(nativeProc);
if(pid != null)
nativePids = new ArrayList<>(pid.length);
for (int i : pid)
nativePids.add(i);
else
nativePids = Watchdog.getInstance().getInterestingNativePids();
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
StringWriter tracesFileException = new StringWriter();
// To hold the start and end offset to the ANR trace file respectively.
final long[] offsets = new long[2];
File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
nativePids, tracesFileException, offsets);
if (isMonitorCpuUsage())
mService.updateCpuStatsNow();
synchronized (mService.mProcessCpuTracker)
report.append(mService.mProcessCpuTracker.printCurrentState(anrTime));
info.append(processCpuTracker.printCurrentLoad());
info.append(report);
report.append(tracesFileException.getBuffer());
info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
if (tracesFile == null)
// There is no trace file, so dump (only) the alleged culprit's threads to the log
Process.sendSignal(pid, Process.SIGNAL_QUIT);
else if (offsets[1] > 0)
// We've dumped into the trace file successfully
mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace(
pid, uid, getPackageList(), tracesFile, offsets[0], offsets[1]);
FrameworkStatsLog.write(FrameworkStatsLog.ANR_OCCURRED, uid, processName,
activityShortComponentName == null ? "unknown": activityShortComponentName,
annotation,
(this.info != null) ? (this.info.isInstantApp()
? FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
: FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
: FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
isInterestingToUserLocked()
? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
: FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
getProcessClassEnum(),
(this.info != null) ? this.info.packageName : "");
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
parentShortComponentName, parentPr, annotation, report.toString(), tracesFile,
null);
if (mWindowProcessController.appNotResponding(info.toString(), () -> kill("anr",
ApplicationExitInfo.REASON_ANR, true),
() ->
synchronized (mService)
mService.mServices.scheduleServiceTimeoutLocked(this);
))
return;
synchronized (mService)
// mBatteryStatsService can be null if the AMS is constructed with injector only. This
// will only happen in tests.
if (mService.mBatteryStatsService != null)
mService.mBatteryStatsService.noteProcessAnr(processName, uid);
if (isSilentAnr() && !isDebugging())
kill("bg anr", ApplicationExitInfo.REASON_ANR, true);
return;
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(activityShortComponentName,
annotation != null ? "ANR " + annotation : "ANR", info.toString());
// mUiHandler can be null if the AMS is constructed with injector only. This will only
// happen in tests.
if (mService.mUiHandler != null) // 显示ANR 对话框
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);
mService.mUiHandler.sendMessage(msg);
AMS处理SHOW_NOT_RESPONDING_UI_MSG
final class UiHandler extends Handler
public UiHandler()
super(com.android.server.UiThread.get().getLooper(), null, true);
@Override
public void handleMessage(Message msg)
switch (msg.what)
case SHOW_ERROR_UI_MSG:
mAppErrors.handleShowAppErrorUi(msg);
ensureBootCompleted();
break;
case SHOW_NOT_RESPONDING_UI_MSG: // 处理ANR
mAppErrors.handleShowAnrUi(msg);
ensureBootCompleted();
break;
...
AppErrors#handleShowAnrUi
显示ANR 对话框
/// @frameworks/base/services/core/java/com/android/server/am/AppErrors.java
void handleShowAnrUi(Message msg)
List<VersionedPackage> packageList = null;
synchronized (mService)
AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
final ProcessRecord proc = data.proc;
if (proc == null)
Slog.e(TAG, "handleShowAnrUi: proc is null");
return;
if (!proc.isPersistent())
packageList = proc.getPackageListWithVersionCode();
if (proc.getDialogController().hasAnrDialogs())
Slog.e(TAG, "App already has anr dialog: " + proc);
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.ALREADY_SHOWING);
return;
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
if (mService.mAtmInternal.canShowErrorDialogs() || showBackground)
proc.getDialogController().showAnrDialogs(data);
else
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.CANT_SHOW);
// Just kill the app if there is no dialog to be shown.
mService.killAppAtUsersRequest(proc);
// Notify PackageWatchdog without the lock held
if (packageList != null)
mPackageWatchdog.onPackageFailure(packageList,
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
ProcessRecord$ErrorDialogController#showAnrDialogs
void showAnrDialogs(AppNotRespondingDialog.Data data)
List<Context> contexts = getDisplayContexts(isSilentAnr() /* lastUsedOnly */);
mAnrDialogs = new ArrayList<>();
for (int i = contexts.size() - 1; i >= 0; i--)
final Context c = contexts.get(i);
mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data));
mService.mUiHandler.post(() ->
List<AppNotRespondingDialog> dialogs;
synchronized (mService)
dialogs = mAnrDialogs;
if (dialogs != null)
forAllDialogs(dialogs, Dialog::show); // 显示dialog
);
以上是关于Android R Input 之ANR的产生与显示流程的主要内容,如果未能解决你的问题,请参考以下文章
Android R input 之 InputManagerService 的建立