(笔记)Android ANR检测机制深度分析
概述
ANR(Application Not Responding)是Android系统用于检测应用程序无响应状态的重要机制。当应用程序在主线程上执行长时间阻塞操作时,系统会检测到这种异常情况并触发ANR,向用户显示"应用程序无响应"对话框。本文深入分析Android 7.0中ANR检测机制的实现,特别关注输入事件超时检测和ANR触发逻辑。
ANR检测系统整体架构
┌─────────────────────────────────────────────────────────────┐
│ 应用进程 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ MainThread │ │ UI Operation │ │ Event │ │
│ │ (主线程) │ │ (UI操作) │ │ Handling │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ MessageQueue │ │
│ │ (消息队列处理) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘│▼ (Binder调用超时)
┌─────────────────────────────────────────────────────────────┐
│ 系统服务层 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ActivityManagerService │ │
│ │ (AMS - ANR协调者) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ ANR检测管理 │ │ │
│ │ │ ┌─────────────┐ ┌─────────────────────────┐ │ │ │
│ │ │ │ Broadcast │ │ Service ANR │ │ │ │
│ │ │ │ ANR检测 │ │ 检测和处理 │ │ │ │
│ │ │ └─────────────┘ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ ANR日志生成 │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ Trace收集 │ │ 堆栈转储 │ │ 系统状态 │ │ │ │
│ │ │ │ 和分析 │ │ (Stack Dump) │ │ 记录 │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ InputManagerService │ │
│ │ (输入事件ANR检测) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 输入事件超时监控 │ │ │
│ │ │ ┌─────────────┐ ┌─────────────────────────┐ │ │ │
│ │ │ │ 分发超时 │ │ 窗口无响应检测 │ │ │ │
│ │ │ │ 检测 │ │ (5秒默认超时) │ │ │ │
│ │ │ └─────────────┘ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Watchdog │ │
│ │ (系统服务监控) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 服务死锁检测 │ │ │
│ │ │ ┌─────────────┐ ┌─────────────────────────┐ │ │ │
│ │ │ │ 系统服务 │ │ 死锁超时检测 │ │ │ │
│ │ │ │ 心跳监控 │ │ (60秒默认超时) │ │ │ │
│ │ │ └─────────────┘ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘│▼ (Native层超时检测)
┌─────────────────────────────────────────────────────────────┐
│ Native输入系统 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ InputDispatcher │ │
│ │ (输入事件分发器) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 事件分发超时检测 │ │ │
│ │ │ ┌─────────────┐ ┌─────────────────────────┐ │ │ │
│ │ │ │ 连接状态 │ │ 输入目标等待 │ │ │ │
│ │ │ │ 监控 │ │ 超时检测 │ │ │ │
│ │ │ └─────────────┘ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ ANR回调机制 │ │ │
│ │ │ InputDispatcherPolicyInterface.notifyANR() │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1. ANR类型和检测场景
1.1 ANR类型分类
Android系统中主要有以下几种ANR类型:
ANR类型 | 检测对象 | 超时时间 | 检测场景 |
---|---|---|---|
Input ANR | 输入事件处理 | 5秒 | 触摸、按键无响应 |
Broadcast ANR | 广播接收器 | 前台10秒/后台60秒 | onReceive()超时 |
Service ANR | 服务组件 | 前台20秒/后台200秒 | Service启动超时 |
Provider ANR | 内容提供者 | 10秒 | ContentProvider操作超时 |
System Server ANR | 系统服务 | 60秒 | 系统服务死锁 |
1.2 ANR检测的核心条件
// ANR检测的基本条件
public class ANRDetectionConditions {// 输入事件ANR条件public static final class InputANR {/** 默认输入分发超时时间:5秒 */public static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5 * 1000 * 1000000L; // 5秒(纳秒)/** 输入目标应用无响应超时 */public static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000; // 5秒(毫秒)/** 窗口无响应检测条件 */public static boolean isWindowNotResponding(long currentTime, long startTime) {return (currentTime - startTime) >= DEFAULT_INPUT_DISPATCHING_TIMEOUT;}}// 广播ANR条件public static final class BroadcastANR {/** 前台广播超时时间:10秒 */public static final long BROADCAST_FG_TIMEOUT = 10 * 1000;/** 后台广播超时时间:60秒 */public static final long BROADCAST_BG_TIMEOUT = 60 * 1000;public static boolean isBroadcastTimeout(boolean isForeground, long duration) {long timeout = isForeground ? BROADCAST_FG_TIMEOUT : BROADCAST_BG_TIMEOUT;return duration >= timeout;}}// 服务ANR条件public static final class ServiceANR {/** 前台服务超时时间:20秒 */public static final long SERVICE_TIMEOUT = 20 * 1000;/** 后台服务超时时间:200秒 */public static final long SERVICE_BACKGROUND_TIMEOUT = 200 * 1000;public static boolean isServiceTimeout(boolean isForeground, long duration) {long timeout = isForeground ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT;return duration >= timeout;}}
}
2. 输入事件超时检测机制
2.1 InputDispatcher中的超时检测
文件路径: frameworks/native/services/inputflinger/InputDispatcher.cpp
/*** InputDispatcher中的ANR检测核心逻辑* 当输入事件分发超时时触发ANR*/
class InputDispatcher : public InputDispatcherInterface {
private:// ANR相关的成员变量/** 输入目标等待原因 */int32_t mInputTargetWaitCause;/** 输入目标等待开始时间 */nsecs_t mInputTargetWaitStartTime;/** 输入目标等待超时时间 */nsecs_t mInputTargetWaitTimeoutTime;/** 输入目标等待是否已超时 */bool mInputTargetWaitTimeoutExpired;/** 等待中的应用程序句柄 */sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;// 等待原因常量static const int32_t INPUT_TARGET_WAIT_CAUSE_NONE = 0;static const int32_t INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY = 1;static const int32_t INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY = 2;public:/*** 检查输入目标是否准备就绪* 如果超时则触发ANR*/int32_t handleTargetsNotReadyLocked(nsecs_t currentTime,const EventEntry* entry,const sp<InputApplicationHandle>& applicationHandle,const sp<InputWindowHandle>& windowHandle,nsecs_t* nextWakeupTime, const char* reason) {if (applicationHandle == NULL && windowHandle == NULL) {if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {if (DEBUG_FOCUS) {ALOGD("Waiting for system to become ready for input. Reason: %s", reason);}mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;mInputTargetWaitStartTime = currentTime;mInputTargetWaitTimeoutTime = LONG_LONG_MAX;mInputTargetWaitTimeoutExpired = false;mInputTargetWaitApplicationHandle.clear();}} else {if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {if (DEBUG_FOCUS) {ALOGD("Waiting for application to become ready for input: %s. Reason: %s",getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),reason);}// 计算超时时间nsecs_t timeout;if (windowHandle != NULL) {timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);} else if (applicationHandle != NULL) {timeout = applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);} else {timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;}mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;mInputTargetWaitStartTime = currentTime;mInputTargetWaitTimeoutTime = currentTime + timeout;mInputTargetWaitTimeoutExpired = false;mInputTargetWaitApplicationHandle.clear();if (windowHandle != NULL) {mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;}if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {mInputTargetWaitApplicationHandle = applicationHandle;}}}if (mInputTargetWaitTimeoutExpired) {return INPUT_EVENT_INJECTION_TIMED_OUT;}// 检查是否超时if (currentTime >= mInputTargetWaitTimeoutTime) {// 触发ANRonANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, mInputTargetWaitStartTime, reason);// 强制下次循环立即唤醒*nextWakeupTime = LONG_LONG_MIN;return INPUT_EVENT_INJECTION_PENDING;} else {// 设置下次唤醒时间为超时时间if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {*nextWakeupTime = mInputTargetWaitTimeoutTime;}return INPUT_EVENT_INJECTION_PENDING;}}/*** ANR触发回调* 当检测到输入事件超时时调用*/void onANRLocked(nsecs_t currentTime,const sp<InputApplicationHandle>& applicationHandle,const sp<InputWindowHandle>& windowHandle,nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) {float dispatchLatency = (currentTime - eventTime) * 0.000001f;float waitDuration = (currentTime - waitStartTime) * 0.000001f;ALOGI("Application is not responding: %s. ""It has been %0.1fms since event, %0.1fms since wait started. Reason: %s",getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),dispatchLatency, waitDuration, reason);// 记录ANR事件到日志time_t t = time(NULL);struct tm tm;localtime_r(&t, &tm);char timestr[64];strftime(timestr, sizeof(timestr), "%F %T", &tm);ALOGI("ANR in %s (pid %d) at %s",applicationHandle != NULL ? applicationHandle->getName().string() : "<unknown>",applicationHandle != NULL ? applicationHandle->getDispatchingTimeout() : -1,timestr);// 通知WindowManagerService ANR发生CommandEntry* commandEntry = postCommandLocked(& InputDispatcher::doNotifyANRLockedInterruptible);commandEntry->inputApplicationHandle = applicationHandle;commandEntry->inputWindowHandle = windowHandle;commandEntry->reason = reason;}/*** 执行ANR通知(可中断版本)*/void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) {mLock.unlock();nsecs_t newTimeout = mPolicy->notifyANR(commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,commandEntry->reason);mLock.lock();resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,commandEntry->inputChannel);}/*** 获取等待应用程序响应的时间*/nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) {if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {return currentTime - mInputTargetWaitStartTime;}return 0;}/*** 重置ANR超时状态*/void resetANRTimeoutsLocked() {if (DEBUG_FOCUS) {ALOGD("Resetting ANR timeouts.");}// 重置等待状态mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;mInputTargetWaitApplicationHandle.clear();}
};/*** 默认输入分发超时时间常量定义*/
// 在InputDispatcher.h中定义
static const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5秒/*** 输入窗口句柄中的超时获取*/
class InputWindowHandle : public RefBase {
public:nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {return mInfo ? mInfo->dispatchingTimeout : defaultValue;}private:const InputWindowInfo* mInfo;
};/*** 输入应用程序句柄中的超时获取*/
class InputApplicationHandle : public RefBase {
public:nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {return mInfo ? mInfo->dispatchingTimeout : defaultValue;}String8 getName() const {return mInfo ? mInfo->name : String8("<unknown>");}private:const InputApplicationInfo* mInfo;
};
2.2 连接状态监控
/*** InputDispatcher中的连接管理* 监控每个输入连接的响应状态*/
class InputDispatcher {/*** 连接状态枚举*/class Connection : public RefBase {public:enum Status {STATUS_NORMAL, // 正常状态STATUS_BROKEN, // 连接已断开STATUS_ZOMBIE // 僵尸状态(等待清理)};Status status; // 连接状态sp<InputChannel> inputChannel; // 输入通道sp<InputWindowHandle> inputWindowHandle; // 窗口句柄bool monitor; // 是否为监控连接InputPublisher inputPublisher; // 输入发布器InputState inputState; // 输入状态// 等待队列相关Queue<DispatchEntry> outboundQueue; // 出站队列Queue<DispatchEntry> waitQueue; // 等待队列explicit Connection(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle, bool monitor);~Connection();/*** 获取等待队列头部事件的等待时间*/nsecs_t getWaitQueueHead(nsecs_t currentTime) const {if (waitQueue.isEmpty()) {return LONG_LONG_MAX;}DispatchEntry* head = waitQueue.head;return head->deliveryTime;}/*** 检查连接是否响应超时*/bool hasTimeoutExpired(nsecs_t currentTime, nsecs_t timeout) const {if (waitQueue.isEmpty()) {return false;}DispatchEntry* head = waitQueue.head;return currentTime >= head->deliveryTime + timeout;}};/*** 检查连接响应超时*/void abortBrokenDispatchCycleLocked(nsecs_t currentTime, Connection* connection,bool notify) {if (DEBUG_DISPATCH_CYCLE) {ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",connection->getInputChannelName(), toString(notify));}// 清空出站队列drainDispatchQueueLocked(&connection->outboundQueue);// 清空等待队列并生成取消事件if (connection->status == Connection::STATUS_NORMAL) {connection->status = Connection::STATUS_BROKEN;if (notify) {// 通知ANRonDispatchCycleBrokenLocked(currentTime, connection);}}}/*** 分发循环中断处理*/void onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) {ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",connection->getInputChannelName());CommandEntry* commandEntry = postCommandLocked(& InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);commandEntry->connection = connection;}/*** 处理分发超时*/void handleDispatchTimeoutLocked(nsecs_t currentTime) {// 检查所有连接的等待队列for (size_t i = 0; i < mConnectionsByFd.size(); i++) {Connection* connection = mConnectionsByFd.valueAt(i);if (connection->status != Connection::STATUS_NORMAL) {continue;}// 检查是否有超时的事件if (!connection->waitQueue.isEmpty()) {DispatchEntry* head = connection->waitQueue.head;nsecs_t timeout = head->targetFlags & InputTarget::FLAG_FOREGROUND ?FOREGROUND_APP_DISPATCH_TIMEOUT : BACKGROUND_APP_DISPATCH_TIMEOUT;if (currentTime >= head->deliveryTime + timeout) {// 触发分发超时ANRonDispatchTimeoutLocked(currentTime, connection, head);}}}}/*** 分发超时ANR处理*/void onDispatchTimeoutLocked(nsecs_t currentTime, Connection* connection,DispatchEntry* head) {nsecs_t waitDuration = currentTime - head->deliveryTime;ALOGI("Dispatch timeout on channel '%s'. Waited %0.1fms for %s",connection->getInputChannelName(),waitDuration * 0.000001f,head->eventEntry->getDescription().string());// 标记连接为已断开abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);}private:// 超时常量定义static const nsecs_t FOREGROUND_APP_DISPATCH_TIMEOUT = 5000 * 1000000LL; // 5秒static const nsecs_t BACKGROUND_APP_DISPATCH_TIMEOUT = 15000 * 1000000LL; // 15秒
};
3. ActivityManagerService中的ANR处理
3.1 AMS ANR协调机制
/*** ActivityManagerService中的ANR处理核心逻辑*/
public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {// ANR相关常量static final int SHOW_ERROR_UI_MSG = 1;static final int SHOW_NOT_RESPONDING_UI_MSG = 2;static final int SHOW_FACTORY_ERROR_UI_MSG = 3;static final int UPDATE_CONFIGURATION_MSG = 4;static final int GC_BACKGROUND_PROCESSES_MSG = 5;static final int WAIT_FOR_DEBUGGER_UI_MSG = 6;static final int SERVICE_TIMEOUT_MSG = 12;static final int UPDATE_TIME_ZONE = 13;static final int SHOW_UID_ERROR_UI_MSG = 14;static final int SHOW_FINGERPRINT_ERROR_UI_MSG = 15;static final int PROC_START_TIMEOUT_MSG = 20;static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;static final int KILL_APPLICATION_MSG = 22;static final int FINALIZE_PENDING_INTENT_MSG = 23;static final int POST_HEAVY_NOTIFICATION_MSG = 24;static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;static final int CLEAR_DNS_CACHE_MSG = 28;static final int UPDATE_HTTP_PROXY_MSG = 29;static final int SHOW_COMPAT_MODE_DIALOG_UI_MSG = 30;static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31;static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;static final int REPORT_MEM_USAGE_MSG = 33;static final int REPORT_USER_SWITCH_MSG = 34;static final int CONTINUE_USER_SWITCH_MSG = 35;static final int USER_SWITCH_TIMEOUT_MSG = 36;static final int IMMERSIVE_MODE_LOCK_MSG = 37;static final int PERSIST_URI_GRANTS_MSG = 38;static final int REQUEST_ALL_PSS_MSG = 39;static final int START_PROFILES_MSG = 40;static final int UPDATE_TIME_PREFERENCE_MSG = 41;static final int SYSTEM_USER_START_MSG = 42;static final int SYSTEM_USER_CURRENT_MSG = 43;static final int ENTER_ANIMATION_COMPLETE_MSG = 44;static final int FINISH_BOOTING_MSG = 45;static final int START_USER_SWITCH_UI_MSG = 46;static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;static final int DISMISS_DIALOG_UI_MSG = 48;static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;static final int DELETE_DUMPHEAP_MSG = 52;static final int FOREGROUND_PROFILE_CHANGED_MSG = 53;static final int DISPATCH_UIDS_CHANGED_UI_MSG = 54;static final int REPORT_TIME_TRACKER_MSG = 55;static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;static final int APP_BOOST_DEACTIVATE_MSG = 58;static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;static final int IDLE_UIDS_MSG = 60;static final int SYSTEM_USER_UNLOCK_MSG = 61;static final int LOG_STACK_STATE = 62;static final int VR_MODE_CHANGE_MSG = 63;static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 64;/*** 输入分发超时ANR处理* 从InputManagerService调用*/public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires permission "+ android.Manifest.permission.FILTER_EVENTS);}ProcessRecord proc;long timeout;synchronized (this) {proc = findProcessLocked(pid, "ANR");if (proc == null) {Slog.w(TAG, "inputDispatchingTimedOut: no process record for pid " + pid);return 0;}ActivityRecord activity = proc.curActivity;if (activity != null) {if (activity.app != proc) {Slog.w(TAG, "inputDispatchingTimedOut: proc.curActivity.app (" + activity.app + ") != proc (" + proc + ")");return 0;}}timeout = proc.inputDispatchingTimeoutNanos;}if (inputDispatchingTimedOutLocked(proc, activity, null, aboveSystem, reason)) {return -2; // 告诉调用者我们有ANR对话框}return timeout;}/*** 输入分发超时处理核心逻辑*/boolean inputDispatchingTimedOutLocked(ProcessRecord proc, ActivityRecord activity,ActivityRecord parent, boolean aboveSystem, String reason) {if (DEBUG_ANR) Slog.i(TAG, "Input ANR: proc=" + proc + ", activity=" + activity+ ", parent=" + parent + ", aboveSystem=" + aboveSystem + ", reason=" + reason);if (proc != null && proc.debugging) {return false; // 如果进程正在调试,不触发ANR}if (mService.mController != null) {try {// 通知系统控制器ANR发生int res = mService.mController.appCrashed(proc != null ? proc.processName : null,proc != null ? proc.pid : -1,reason != null ? reason : "ANR",null);if (res != 0) {return true; // 控制器处理了ANR}} catch (RemoteException e) {mService.mController = null;Watchdog.getInstance().setActivityController(null);}}// 生成ANR报告return appNotRespondingLocked(proc, activity, parent, aboveSystem, reason);}/*** 应用程序无响应处理*/final boolean appNotRespondingLocked(ProcessRecord app, ActivityRecord activity,ActivityRecord parent, boolean aboveSystem, String annotation) {long anrTime = SystemClock.uptimeMillis();if (MONITOR_CPU_USAGE) {updateCpuStatsNow();}// 构建ANR信息StringBuilder info = new StringBuilder();info.setLength(0);info.append("ANR in ").append(app.processName);if (activity != null && activity.shortComponentName != null) {info.append(" (").append(activity.shortComponentName).append(")");}info.append("\n");info.append("PID: ").append(app.pid).append("\n");if (annotation != null) {info.append("Reason: ").append(annotation).append("\n");}if (parent != null && parent != activity) {info.append("Parent: ").append(parent.shortComponentName).append("\n");}final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids,nativePids);String cpuInfo = null;if (MONITOR_CPU_USAGE) {updateCpuStatsNow();synchronized (mProcessCpuTracker) {cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);}info.append(processCpuTracker.printCurrentLoad());info.append(cpuInfo);}info.append(processCpuTracker.printCurrentState(anrTime));Slog.e(TAG, info.toString());if (tracesFile == null) {// 没有生成堆栈跟踪文件时,执行轻量级转储Process.sendSignal(app.pid, Process.SIGNAL_QUIT);}StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,activity == null ? "unknown": activity.shortComponentName, annotation,(app.info != null) ? (app.info.isInstantApp()? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE: StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE): StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,app.isInterestingToUserLocked()? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND: StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,app.getProcessClassEnum(),(activity != null) ? activity.app.info.packageName : "");// 记录到dropboxaddErrorToDropBox("anr", app, app.processName, activity, parent, annotation,cpuInfo, tracesFile, null);if (mService.mController != null) {try {// 0 == continue, -1 = kill process immediatelyint res = mService.mController.appNotResponding(app.processName, app.pid, info.toString());if (res != 0) {if (res < 0 && app.pid != MY_PID) {app.kill("anr", true);} else {synchronized (this) {mServices.scheduleServiceTimeoutLocked(app);}}return true;}} catch (RemoteException e) {mService.mController = null;Watchdog.getInstance().setActivityController(null);}}synchronized (mService) {mBatteryStatsService.noteProcessAnr(app.processName, app.uid);if (isSilentANR(app)) {app.kill("bg anr", true);return false;}// 设置错误报告makeAppNotRespondingLocked(app,activity != null ? activity.shortComponentName : null,annotation != null ? "ANR " + annotation : "ANR",info.toString());// 显示ANR对话框Message msg = Message.obtain();HashMap<String, Object> map = new HashMap<String, Object>();msg.what = SHOW_NOT_RESPONDING_UI_MSG;msg.obj = map;msg.arg1 = aboveSystem ? 1 : 0;map.put("app", app);if (activity != null) {map.put("activity", activity);}mUiHandler.sendMessage(msg);}return true;}
}
3.2 广播和服务ANR检测
public final class ActivityManagerService {/*** 广播ANR检测*/private final void broadcastTimeoutLocked(boolean fromMsg) {if (fromMsg) {mBroadcastTimeoutMsg = false;}if (mOrderedBroadcasts.size() == 0) {return;}BroadcastRecord r = mOrderedBroadcasts.get(0);if (fromMsg) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Timeout of broadcast " + r + " - receiver=" + r.receiver+ ", started " + (SystemClock.uptimeMillis() - r.receiverTime) + "ms ago");r.receiverTime = SystemClock.uptimeMillis();r.anrCount++;ProcessRecord app = null;String anrMessage = null;Object curReceiver;if (r.nextReceiver > 0) {curReceiver = r.receivers.get(r.nextReceiver-1);r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;} else {curReceiver = r.curReceiver;}Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + curReceiver+ ", started " + (SystemClock.uptimeMillis() - r.receiverTime) + "ms ago");if (curReceiver != null && curReceiver instanceof BroadcastFilter) {BroadcastFilter bf = (BroadcastFilter)curReceiver;if (bf.receiverList.pid != 0&& bf.receiverList.pid != ActivityManagerService.MY_PID) {synchronized (mService.mPidsSelfLocked) {app = mService.mPidsSelfLocked.get(bf.receiverList.pid);}}} else {app = r.curApp;}if (app != null) {anrMessage = "Broadcast of " + r.intent.toString();}if (mPendingBroadcast == r) {mPendingBroadcast = null;}// 移动到下一个接收器finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);scheduleBroadcastsLocked();if (anrMessage != null) {// 触发广播ANRmHandler.post(new Runnable() {@Overridepublic void run() {mService.appNotResponding(app, null, null, false, anrMessage);}});}}}/*** 服务ANR检测*/void serviceTimeout(ProcessRecord proc) {String anrMessage = null;synchronized(mAm) {if (proc.executingServices.size() == 0 || proc.thread == null) {return;}final long now = SystemClock.uptimeMillis();final long maxTime = now -(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);ServiceRecord timeout = null;long timeoutTime = 0;for (int i=proc.executingServices.size()-1; i>=0; i--) {ServiceRecord sr = proc.executingServices.valueAt(i);if (sr.executingStart < maxTime) {timeout = sr;timeoutTime = sr.executingStart;break;}}if (timeout != null && mAm.mLruProcesses.contains(proc)) {Slog.w(TAG, "Timeout executing service: " + timeout);StringWriter sw = new StringWriter();PrintWriter pw = new FastPrintWriter(sw, false, 1024);pw.println(timeout);timeout.dump(pw, " ");pw.close();mLastANRState = sw.toString();mAm.mHandler.removeCallbacks(mLastANRStateRunnable);mAm.mHandler.postDelayed(mLastANRStateRunnable, LAST_ANR_LIFETIME_DURATION_MSECS);anrMessage = "executing service " + timeout.shortName;} else {Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_TIMEOUT_MSG);msg.obj = proc;mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg? (SystemClock.uptimeMillis()+SERVICE_TIMEOUT): (SystemClock.uptimeMillis()+SERVICE_BACKGROUND_TIMEOUT));}}if (anrMessage != null) {mAm.appNotResponding(proc, null, null, false, anrMessage);}}/*** ContentProvider ANR检测*/boolean checkContentProviderUriPermissionLocked(Uri uri, int userId, int modeFlags,int minSdk) {// ContentProvider操作的超时检测final long timeout = 10 * 1000; // 10秒超时final long startTime = SystemClock.uptimeMillis();try {// 执行Provider操作// 如果超时则触发ANRif (SystemClock.uptimeMillis() - startTime > timeout) {// 触发Provider ANRreturn false;}} catch (Exception e) {// 异常处理}return true;}
}
4. Watchdog系统服务监控
4.1 Watchdog核心机制
/*** Watchdog系统监控机制* 监控系统服务的健康状态,防止系统服务死锁*/
public class Watchdog extends Thread {static final String TAG = "Watchdog";// 监控超时时间static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000; // 调试版10秒,发布版60秒static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2; // 检查间隔为超时时间的一半// 监控器接口public interface Monitor {void monitor();}final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();final ArrayList<Integer> mMonitorChecker = new ArrayList<Integer>();ActivityManagerService mActivity;/*** 添加需要监控的服务*/public void addMonitor(Monitor monitor) {synchronized (this) {if (isAlive()) {throw new RuntimeException("Monitors can't be added once the Watchdog is running");}mMonitors.add(monitor);}}/*** Watchdog主循环*/@Overridepublic void run() {boolean waitedHalf = false;while (true) {final ArrayList<Monitor> monitors;final String subject;final boolean allowRestart;int debuggerWasConnected = 0;synchronized (this) {long timeout = DEFAULT_TIMEOUT;// 等待一个检查间隔for (int i=0; i<mMonitors.size(); i++) {mMonitorChecker.add(-1);}long start = SystemClock.uptimeMillis();while (timeout > 0) {if (Debug.isDebuggerConnected()) {debuggerWasConnected = 2;}try {wait(timeout); // 等待指定时间} catch (InterruptedException e) {Log.wtf(TAG, e);}if (Debug.isDebuggerConnected()) {debuggerWasConnected = 2;}timeout = DEFAULT_TIMEOUT - (SystemClock.uptimeMillis() - start);}boolean fdLimitTriggered = false;if (mMonitorChecker.size() >= 1) {fdLimitTriggered = mMonitorChecker.get(0) == 1;}if (timeout <= 0 && !waitedHalf) {// 第一次超时,等待一半时间后再检查waitedHalf = true;continue;}final boolean fdLimitTriggeredLocal = fdLimitTriggered;final int waitState = evaluateCheckerCompletionLocked();if (waitState == COMPLETED) {// 所有监控器都正常响应waitedHalf = false;continue;} else if (waitState == WAITING) {// 仍在等待某些监控器响应continue;} else if (waitState == WAITED_HALF) {if (!waitedHalf) {// 等待一半时间waitedHalf = true;continue;}}// 检测到超时,准备处理monitors = (ArrayList<Monitor>)mMonitors.clone();subject = describeCheckersLocked(monitors);allowRestart = mAllowRestart;}// 只有在调试器未连接时才处理超时if (debuggerWasConnected >= 2) {Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");} else if (debuggerWasConnected > 0) {Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process");} else if (!allowRestart) {Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");} else {Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);// 收集调试信息WatchdogDiagnostics.diagnoseCheckers(monitors);// 杀死系统进程Process.killProcess(Process.myPid());System.exit(10);}waitedHalf = false;}}/*** 评估监控器完成状态*/private int evaluateCheckerCompletionLocked() {if (mMonitorChecker.isEmpty()) {return COMPLETED;}int completed = 0;int waitedHalf = 0;for (int i = 0; i < mMonitorChecker.size(); i++) {switch (mMonitorChecker.get(i)) {case COMPLETED:completed++;break;case WAITING:// 继续等待break;case WAITED_HALF: {waitedHalf++;break;}case OVERDUE:return OVERDUE;}}if (completed == mMonitorChecker.size()) {return COMPLETED;} else if (waitedHalf > 0) {return WAITED_HALF;} else {return WAITING;}}/*** 描述检查器状态*/private String describeCheckersLocked(ArrayList<Monitor> monitors) {StringBuilder builder = new StringBuilder(128);for (int i=0; i<monitors.size(); i++) {if (builder.length() > 0) {builder.append(", ");}builder.append(monitors.get(i).getClass().getName());}return builder.toString();}// 监控状态常量static final int COMPLETED = 0;static final int WAITING = 1;static final int WAITED_HALF = 2;static final int OVERDUE = 3;
}/*** ActivityManagerService实现Watchdog.Monitor接口*/
public final class ActivityManagerService implements Watchdog.Monitor {/*** Watchdog监控检查* 用于检测AMS是否死锁*/@Overridepublic void monitor() {synchronized (this) {// 尝试获取AMS锁,如果死锁则会阻塞在这里// Watchdog会检测到超时并重启系统}}
}
5. ANR日志生成和分析
5.1 堆栈跟踪收集
public final class ActivityManagerService {/*** 转储堆栈跟踪* 当发生ANR时收集所有相关进程的堆栈信息*/public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,String[] nativeProcs) {String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);if (tracesPath == null || tracesPath.length() == 0) {return null;}File tracesFile = new File(tracesPath);try {if (clearTraces && tracesFile.exists()) tracesFile.delete();tracesFile.createNewFile();FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-} catch (IOException e) {Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);return null;}dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativeProcs);return tracesFile;}/*** 转储堆栈跟踪实现*/private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,String[] nativeProcs) {// 使用FileObserver监控traces文件写入完成FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {@Overridepublic void onEvent(int event, String path) {synchronized (this) {notify();}}};try {observer.startWatching();// 首先转储最重要的进程if (firstPids != null) {try {int num = firstPids.size();for (int i = 0; i < num; i++) {synchronized (observer) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid " + firstPids.get(i));final long sime = SystemClock.elapsedRealtime();Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);observer.wait(1000); // 等待最多1秒if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)+ " in " + (SystemClock.elapsedRealtime()-sime) + "ms");}}} catch (InterruptedException e) {Slog.wtf(TAG, e);}}// 转储native进程if (nativeProcs != null) {for (String proc : nativeProcs) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native process " + proc);final long sime = SystemClock.elapsedRealtime();Debug.dumpNativeBacktraceToFile(firstPids.get(0), tracesPath);if (DEBUG_ANR) Slog.d(TAG, "Done with native process " + proc+ " in " + (SystemClock.elapsedRealtime()-sime) + "ms");}}// 转储其他相关进程if (lastPids != null) {for (int i = 0; i < lastPids.size(); i++) {int pid = lastPids.keyAt(i);boolean doWait = lastPids.valueAt(i);synchronized (observer) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);final long sime = SystemClock.elapsedRealtime();Process.sendSignal(pid, Process.SIGNAL_QUIT);if (doWait) {observer.wait(1000); // 等待最多1秒}if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + pid+ " in " + (SystemClock.elapsedRealtime()-sime) + "ms");}}}} finally {observer.stopWatching();}}/*** 添加错误到DropBox* 用于ANR日志的持久化存储*/public void addErrorToDropBox(String eventType, ProcessRecord process, String processName,ActivityRecord activity, ActivityRecord parent, String subject,String report, File logFile, ApplicationErrorReport.CrashInfo crashInfo) {// 获取DropBoxManagerfinal DropBoxManager dbox = (DropBoxManager)mContext.getSystemService(Context.DROPBOX_SERVICE);// 如果DropBox不可用或者不接受这种类型的报告,返回if (dbox == null || !dbox.isTagEnabled("anr")) return;final StringBuilder sb = new StringBuilder(1024);appendDropBoxProcessHeaders(process, processName, sb);if (activity != null) {sb.append("Activity: ").append(activity.shortComponentName).append("\n");}if (parent != null && parent.app.pid != process.pid) {sb.append("Parent-Process: ").append(parent.app.processName).append("\n");sb.append("Parent-PID: ").append(parent.app.pid).append("\n");if (parent.shortComponentName != null) {sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");}}if (subject != null) {sb.append("Subject: ").append(subject).append("\n");}sb.append("Build: ").append(Build.FINGERPRINT).append("\n");if (Debug.isDebuggerConnected()) {sb.append("Debugger: Connected\n");}sb.append("\n");// 添加报告内容if (report != null) {sb.append(report);}// 添加日志文件if (logFile != null) {sb.append("\n");// 读取并添加traces文件内容InputStreamReader input = null;try {input = new InputStreamReader(new FileInputStream(logFile));char[] buf = new char[4096];int amt;while ((amt = input.read(buf)) > 0) {sb.append(buf, 0, amt);}} catch (IOException e) {Slog.w(TAG, "Error reading " + logFile, e);} finally {if (input != null) {try {input.close();} catch (IOException e) {}}}}dbox.addText(eventType, sb.toString());}
}
5.2 ANR分析工具
/*** ANR分析工具类* 提供ANR日志解析和分析功能*/
public class ANRAnalyzer {/*** ANR信息结构*/public static class ANRInfo {public String processName; // 进程名称public int pid; // 进程IDpublic String packageName; // 包名public String activityName; // Activity名称public String reason; // ANR原因public long timestamp; // 发生时间public String mainThreadStack; // 主线程堆栈public Map<String, String> allThreadStacks; // 所有线程堆栈public String cpuInfo; // CPU信息public String memoryInfo; // 内存信息}/*** 解析ANR日志文件*/public static ANRInfo parseANRLog(File anrFile) {ANRInfo info = new ANRInfo();info.allThreadStacks = new HashMap<>();try (BufferedReader reader = new BufferedReader(new FileReader(anrFile))) {String line;StringBuilder currentThreadStack = new StringBuilder();String currentThreadName = null;boolean inThreadStack = false;while ((line = reader.readLine()) != null) {// 解析ANR头信息if (line.startsWith("ANR in ")) {parseANRHeader(line, info);} else if (line.startsWith("PID: ")) {info.pid = Integer.parseInt(line.substring(5));} else if (line.startsWith("Reason: ")) {info.reason = line.substring(8);} else if (line.startsWith("Build: ")) {// 跳过Build信息} else if (line.startsWith("\"") && line.contains("\" prio=")) {// 新线程开始if (currentThreadName != null && inThreadStack) {info.allThreadStacks.put(currentThreadName, currentThreadStack.toString());}currentThreadName = extractThreadName(line);currentThreadStack = new StringBuilder();currentThreadStack.append(line).append("\n");inThreadStack = true;// 检查是否为主线程if (currentThreadName.equals("main")) {// 主线程堆栈,特殊处理}} else if (inThreadStack) {currentThreadStack.append(line).append("\n");// 检查堆栈结束if (line.trim().isEmpty() && currentThreadName != null) {info.allThreadStacks.put(currentThreadName, currentThreadStack.toString());if (currentThreadName.equals("main")) {info.mainThreadStack = currentThreadStack.toString();}currentThreadName = null;inThreadStack = false;}} else if (line.contains("TOTAL:") && line.contains("%")) {// CPU信息info.cpuInfo = parseCPUInfo(reader);} else if (line.contains("MemTotal:")) {// 内存信息info.memoryInfo = parseMemoryInfo(reader);}}// 处理最后一个线程if (currentThreadName != null && inThreadStack) {info.allThreadStacks.put(currentThreadName, currentThreadStack.toString());if (currentThreadName.equals("main")) {info.mainThreadStack = currentThreadStack.toString();}}} catch (IOException e) {e.printStackTrace();}return info;}/*** 分析ANR原因*/public static String analyzeANRCause(ANRInfo anrInfo) {if (anrInfo.mainThreadStack == null) {return "无法获取主线程堆栈信息";}String mainStack = anrInfo.mainThreadStack;// 检查常见的ANR原因if (mainStack.contains("android.os.MessageQueue.nativePollOnce")) {return "主线程空闲,可能是其他线程阻塞导致";} else if (mainStack.contains("java.lang.Thread.sleep")) {return "主线程调用Thread.sleep()导致阻塞";} else if (mainStack.contains("java.lang.Object.wait")) {return "主线程等待其他线程信号";} else if (mainStack.contains("java.util.concurrent")) {return "主线程等待并发操作完成";} else if (mainStack.contains("android.database")) {return "数据库操作阻塞主线程";} else if (mainStack.contains("java.net") || mainStack.contains("okhttp")) {return "网络请求阻塞主线程";} else if (mainStack.contains("java.io.File") || mainStack.contains("FileInputStream")) {return "文件I/O操作阻塞主线程";} else if (mainStack.contains("Binder.transact")) {return "Binder调用超时";} else {return "其他原因导致的主线程阻塞";}}/*** 生成ANR分析报告*/public static String generateANRReport(ANRInfo anrInfo) {StringBuilder report = new StringBuilder();report.append("=== ANR分析报告 ===\n");report.append("进程: ").append(anrInfo.processName).append("\n");report.append("PID: ").append(anrInfo.pid).append("\n");report.append("包名: ").append(anrInfo.packageName).append("\n");report.append("Activity: ").append(anrInfo.activityName).append("\n");report.append("原因: ").append(anrInfo.reason).append("\n");report.append("时间: ").append(new Date(anrInfo.timestamp)).append("\n");report.append("\n");// 分析结果String analysis = analyzeANRCause(anrInfo);report.append("=== 分析结果 ===\n");report.append(analysis).append("\n\n");// 主线程堆栈report.append("=== 主线程堆栈 ===\n");report.append(anrInfo.mainThreadStack).append("\n");// 建议report.append("=== 修复建议 ===\n");report.append(generateFixSuggestions(analysis)).append("\n");return report.toString();}/*** 生成修复建议*/private static String generateFixSuggestions(String analysis) {if (analysis.contains("数据库操作")) {return "建议将数据库操作移到后台线程执行,使用AsyncTask或线程池";} else if (analysis.contains("网络请求")) {return "建议使用异步网络库,如OkHttp + 异步回调或RxJava";} else if (analysis.contains("文件I/O")) {return "建议将文件操作移到后台线程,避免在主线程进行I/O操作";} else if (analysis.contains("Binder调用")) {return "建议检查系统服务调用,考虑使用异步调用或增加超时处理";} else {return "建议检查主线程代码,将耗时操作移到后台线程执行";}}
}
6. ANR预防和优化策略
6.1 应用层优化
优化策略 | 实现方法 | 效果 |
---|---|---|
异步任务处理 | AsyncTask、Handler、Thread | 避免主线程阻塞 |
数据库优化 | 后台线程、预加载、索引 | 减少查询时间 |
网络请求优化 | 异步HTTP、缓存、超时设置 | 防止网络阻塞 |
图片加载优化 | 异步加载、内存缓存、压缩 | 减少内存压力 |
代码逻辑优化 | 算法优化、减少循环、懒加载 | 提高执行效率 |
6.2 系统级监控
/*** ANR预防监控系统*/
public class ANRPreventionMonitor {private static final long WARNING_THRESHOLD = 3000; // 3秒警告阈值private Handler mMainHandler;private volatile boolean mIsMonitoring;/*** 开始监控主线程阻塞*/public void startMonitoring() {mIsMonitoring = true;mMainHandler = new Handler(Looper.getMainLooper());// 定期发送心跳消息scheduleHeartbeat();}/*** 调度心跳检测*/private void scheduleHeartbeat() {if (!mIsMonitoring) return;final long startTime = SystemClock.uptimeMillis();mMainHandler.post(new Runnable() {@Overridepublic void run() {long currentTime = SystemClock.uptimeMillis();long delay = currentTime - startTime;if (delay > WARNING_THRESHOLD) {// 主线程可能发生阻塞Log.w("ANRMonitor", "Main thread blocked for " + delay + "ms");// 收集堆栈信息collectStackTrace();}// 调度下次检测mMainHandler.postDelayed(new Runnable() {@Overridepublic void run() {scheduleHeartbeat();}}, 1000); // 每秒检测一次}});}/*** 收集堆栈跟踪*/private void collectStackTrace() {Map<Thread, StackTraceElement[]> allTraces = Thread.getAllStackTraces();for (Map.Entry<Thread, StackTraceElement[]> entry : allTraces.entrySet()) {Thread thread = entry.getKey();if (thread.getName().equals("main")) {StackTraceElement[] stackTrace = entry.getValue();StringBuilder sb = new StringBuilder();for (StackTraceElement element : stackTrace) {sb.append(element.toString()).append("\n");}Log.w("ANRMonitor", "Main thread stack:\n" + sb.toString());break;}}}
}
7. 总结
7.1 ANR检测机制核心价值
- 系统稳定性保障: 及时发现和处理应用程序无响应状态
- 用户体验保护: 防止用户界面长时间无响应
- 问题诊断支持: 提供详细的ANR日志用于问题分析
- 系统资源管理: 防止恶意或有问题的应用占用系统资源
- 开发调试辅助: 帮助开发者发现和修复性能问题
7.2 检测机制特点
- 多层次监控: Input、Broadcast、Service、Watchdog等多个层面
- 精确超时控制: 不同场景下的差异化超时时间设置
- 智能触发逻辑: 考虑调试状态、前后台等多种因素
- 完整日志收集: 堆栈跟踪、CPU信息、内存状态等全面信息
- 灵活处理策略: Kill、等待、重启等多种处理方式
7.3 系统协作优势
ANR检测机制作为Android系统稳定性的重要保障:
- 与InputFlinger集成: 实时监控输入事件处理延迟
- 与ActivityManager协作: 统一的ANR处理和报告机制
- 与WindowManager联动: 窗口焦点变化与输入超时的关联
- 与调试系统配合: 开发阶段的ANR检测和分析支持
相关文件路径
Native输入系统
frameworks/native/services/inputflinger/InputDispatcher.cpp
- 输入事件超时检测frameworks/native/services/inputflinger/InputDispatcher.h
- ANR检测接口定义
系统服务层
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- ANR协调处理frameworks/base/services/core/java/com/android/server/Watchdog.java
- 系统服务监控
应用框架层
frameworks/base/core/java/android/os/Handler.java
- 主线程消息处理frameworks/base/core/java/android/os/Looper.java
- 消息循环机制
调试和日志
frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java
- CPU使用监控frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java
- ANR日志存储