当前位置: 首页 > news >正文

[Android]ANR的线程

ANR的原理是进行了超时告警,在执行一个需要被监控的任务时,注册一个超时提醒,如果很快执行好了,删除这个提醒,如果超时,这个提醒就被触发,这个超时处理是通过handler方式来调用的,这里我们来关注一个细节,任务在执行,超时处理显然应该是在另外一个线程里来进行监控的。这是显而易见的,这里我们就通过广播里的ANR处理来查看这个显而易见的线程问题,

在广播发送过程中,会调用到AMS中的

ActivityManagerService.java - Android社区 - https://www.androidos.net.cn/

            synchronized(this) {BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0? mFgBroadcastQueue : mBgBroadcastQueue;r = queue.getMatchingOrderedReceiver(who);if (r != null) {doNext = r.queue.finishReceiverLocked(r, resultCode,resultData, resultExtras, resultAbort, true);}if (doNext) {r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);}

这是AMS中的一个线程,调用了BroadcastQueue中的processNextBroadcastLocked

https://www.androidos.net.cn/android/9.0.0_r8/xref/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {BroadcastRecord r;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["+ mQueueName + "]: "+ mParallelBroadcasts.size() + " parallel broadcasts, "+ mOrderedBroadcasts.size() + " ordered broadcasts");mService.updateCpuStats();if (fromMsg) {mBroadcastsScheduled = false;}// First, deliver any non-serialized broadcasts right away.while (mParallelBroadcasts.size() > 0) {r = mParallelBroadcasts.remove(0);r.dispatchTime = SystemClock.uptimeMillis();r.dispatchClockTime = System.currentTimeMillis();if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}final int N = r.receivers.size();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["+ mQueueName + "] " + r);for (int i=0; i<N; i++) {Object target = r.receivers.get(i);if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,"Delivering non-ordered on [" + mQueueName + "] to registered "+ target + ": " + r);deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);}addBroadcastToHistoryLocked(r);if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["+ mQueueName + "] " + r);}// Now take care of the next serialized one...// If we are waiting for a process to come up to handle the next// broadcast, then do nothing at this point.  Just in case, we// check that the process we're waiting for still exists.if (mPendingBroadcast != null) {if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"processNextBroadcast [" + mQueueName + "]: waiting for "+ mPendingBroadcast.curApp);boolean isDead;if (mPendingBroadcast.curApp.pid > 0) {synchronized (mService.mPidsSelfLocked) {ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);isDead = proc == null || proc.crashing;}} else {final ProcessRecord proc = mService.mProcessNames.get(mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);isDead = proc == null || !proc.pendingStart;}if (!isDead) {// It's still alive, so keep waitingreturn;} else {Slog.w(TAG, "pending app  ["+ mQueueName + "]" + mPendingBroadcast.curApp+ " died before responding to broadcast");mPendingBroadcast.state = BroadcastRecord.IDLE;mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;mPendingBroadcast = null;}}boolean looped = false;do {if (mOrderedBroadcasts.size() == 0) {// No more broadcasts pending, so all done!mService.scheduleAppGcsLocked();if (looped) {// If we had finished the last ordered broadcast, then// make sure all processes have correct oom and sched// adjustments.mService.updateOomAdjLocked();}return;}r = mOrderedBroadcasts.get(0);boolean forceReceive = false;// Ensure that even if something goes awry with the timeout// detection, we catch "hung" broadcasts here, discard them,// and continue to make progress.//// This is only done if the system is ready so that PRE_BOOT_COMPLETED// receivers don't get executed with timeouts. They're intended for// one time heavy lifting after system upgrades and can take// significant amounts of time.int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;if (mService.mProcessesReady && r.dispatchTime > 0) {long now = SystemClock.uptimeMillis();if ((numReceivers > 0) &&(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {Slog.w(TAG, "Hung broadcast ["+ mQueueName + "] discarded after timeout failure:"+ " now=" + now+ " dispatchTime=" + r.dispatchTime+ " startTime=" + r.receiverTime+ " intent=" + r.intent+ " numReceivers=" + numReceivers+ " nextReceiver=" + r.nextReceiver+ " state=" + r.state);broadcastTimeoutLocked(false); // forcibly finish this broadcastforceReceive = true;r.state = BroadcastRecord.IDLE;}

这里面调用了broadcastTimeoutLocked来进行ANR埋雷,

这个broadcastTimeoutLocked埋雷后的处理,显然应当是在另外一个线程中,

查看其定义

    final void setBroadcastTimeoutLocked(long timeoutTime) {if (! mPendingBroadcastTimeoutMessage) {Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);mHandler.sendMessageAtTime(msg, timeoutTime);mPendingBroadcastTimeoutMessage = true;}}

使用了mHandler相应的线程looper去处理,这个mHander是什么

是在这里定义的,继续查看传入的handler是什么,在AMS中,有

mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); 
mHandlerThread.start(); 
mHandler = new MainHandler(mHandlerThread.getLooper());mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); 
mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true);

可以看到,是定义了一个ServiceThread,启动了一个线程looper,得证。

相关文章:

  • 理解WebGL中的顶点着色器和片元着色器
  • git lfs 提交大文件
  • 解决git clone报错:fatal unable to access xxx. Could not resolve host github.com
  • 【PaddleOCR】PaddlePaddle 3.0环境安装,及PaddleOCR3.0 快速入门使用
  • MCP -1(待补充)
  • <4>_Linux进程概念
  • 同步日志系统深度解析【链式调用】【宏定义】【固定缓冲区】【线程局部存储】【RAII】
  • 数据结构与算法学习笔记(Acwing 提高课)----动态规划·单调队列优化DP
  • Neo4j无法建立到 localhost:7474 服务器的连接出现404错误
  • 鸿蒙5:组件监听和部分状态管理V2
  • 【YOLOv13保姆级教程#03】自建数据集训练与验证(Train Val)全流程 | 手把手教你构建数据集、标签格式转换与yaml配置
  • NV046NV060美光固态闪存NV061NV063
  • matplotlib 绘制水平柱状图
  • 使用deepseek制作“喝什么奶茶”随机抽签小网页
  • linux面试常考
  • SpringBoot3.x整合Knife4j接口文档
  • HarmonyOS应用开发实验操作步骤
  • Python 数据分析与可视化 Day 10 - 数据合并与连接
  • HashMap 和 ConcurrentHashMap的区别
  • Python 数据分析:numpy,抽提,整数数组索引。听故事学知识点怎么这么容易?