[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,得证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89068.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RLVR来做Agent任务能力增强训练

和上一篇其实有点承接 上一篇的争论其实是因为要优化agent的任务规划和实现能力的 所以有了self-learning之争 当我们说Self-learning&#xff0c;其实是在说什么&#xff1f; 其实上一篇最后时候提了一点拿RLVR来做agent的任务提升 正好今天看到了一篇应景的论文&#xf…

如何运营一个开源项目并取得较大影响力?

开源不仅是主要的软件开发方法论&#xff0c;还是助力快速创新、分散协作、 生态系统建设和职业发展的卓越战略。如今&#xff0c;无论在哪里&#xff0c;都离不开与 开源的互动。开源存在于你的手机、汽车和冰箱中&#xff0c;它使你最喜欢的节 目或电影的制作和发行成为可能&…

华为高斯数据库的数据类型

华为高斯数据库的数据类型 国产数据库华为高斯的GaussDB的数据类型 华为高斯数据库的数据类型✅ 一、数值类型&#xff08;Numeric Types&#xff09;✅ 二、字符类型&#xff08;Character Types&#xff09;✅ 三、布尔类型&#xff08;Boolean Type&#xff09;✅ 四、日期和…

生物实验室安全、化学品安全

zhihu.com/column/c_1922752541369800632 Docs 目录 第七章 7.1 实验室生物安全等级 7.1.1 生物安全基本概念 7.1.2 生物的危害等级 7.1.2.1 国内生物危害等级 7.1.3 实验室生物安全防护水平分级 7.2 实验室生物安全控制 7.2.1 实验室生物仪器设备安全控制 7.2.1.1 生…

【QT】第一个QT程序 || 对象树 || 编码时的注意事项

一、编写第一个 Qt 程序 1. 开发环境搭建 安装 Qt Creator&#xff08;推荐使用官方在线安装器&#xff09;安装 Qt 库&#xff08;如 Qt 5.15.2 或 Qt 6.x&#xff09;配置编译器&#xff08;MinGW / MSVC / GCC&#xff09; 2. 创建一个简单的 Qt GUI 应用程序 打开 Qt C…

多服务器IP白名单配置(使用redis stream实现)

应用背景 现在我有一个管理平台,可以通过代理连接到内网网站,但是这个代理服务器没有设置密码,所以需要IP白名单让指定用户才可以使用代理。 添加白名单流程图 流程描述: 登录管理平台成功后,管理平台的后台将这个登录的IP地址添加到redis,并设置过期时间为24小时redis…

Vue 3 Teleport 特性

目录 基本用法​ 搭配组件使用​ 禁用 Teleport​ 多个 Teleport 共享目标​ 延迟解析的 Teleport ​ 总结 <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。 基本用法​ 有时我们可能会遇到这…

常用指令合集(DOS/Linux/git/Maven等)

文章目录 常用指令收集vmware 虚拟机联网设置ubuntu 常见问题设置apt 相关指令&#xff1a;gcc 编译相关指令 sqlite3VSCode 快捷键&#xff1a;收索引擎技巧&#xff08;google&#xff09;Intelideashell--LinxvimgitDOS:mavendockerkubectl 指令nginx配置redis-clientMySQLl…

ABP VNext + MassTransit:构建分布式事务与异步消息协作

ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680; &#x1f4da; 目录 ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680;&#x1f4da; 1. 背景与动机&#x1f6e0;️ 2. 环境与依赖&#x1f527; 3. 在 ABP 模块…

语义网技术

用通俗语言说语义网技术&#xff0c;以及它和现在互联网的关系 一、语义网技术&#xff1a;让网络“听懂人话”的智能升级 现有互联网就像一本巨大的“图文报纸”&#xff1a;我们人类看文章、图片能轻松理解意思&#xff0c;但计算机只能识别文字符号&#xff0c;不知道“苹…

pytorch学习—4.反向传播(用pytorch算梯度)

2. 线性模型 3.梯度下降算法 4.反向传播_哔哩哔哩_bilibili 4.1 代码复现 import torch import matplotlib.pyplot as pltx_data=[1.0,2.0,3.0] y_data=[2.0,4.0,6.0]#这里创建了一个PyTorch张量w,初始值为1.0,并且设置requires_grad=True, #这意味着在计算过程中,PyTo…

7类茶叶嫩芽图像分类数据集

在茶叶育种、溯源管理与自动采摘等智能农业场景中&#xff0c;茶树品种的识别与分类是一项关键任务。不同茶叶品种在嫩芽期表现出显著的形态差异&#xff0c;例如颜色、叶缘结构、芽头密度等。因此&#xff0c;基于图像的茶叶品种分类不仅具备实际应用价值&#xff0c;也为农业…

【Elasticsearch】Linux环境下安装Elasticsearch

一&#xff0c;前言 Elasticsearch&#xff08;简称 ES&#xff09;是一个基于 ​​Apache Lucene​​ 构建的开源分布式搜索与分析引擎。它支持​​实时数据处理​​&#xff0c;提供近实时的全文搜索能力&#xff0c;并通过 ​​JSON 格式的 RESTful API​​ 实现数据索引与检…

【数据结构--树于哨兵查找-1】

查找 从前到后- 线性查找 -就是顺序查找. 哨兵法查找–节省每次都要判断是否越界的这一步骤利于节省开销&#xff0c;从而提升效率。 参考我的程序 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdbool.h>#define SIZE …

MyBatis修改(update)操作

1. 三步法口诀 “接口收对象&#xff0c;SQL全赋值&#xff0c;主键定目标” 2. 详细记忆点 | 步骤 | 口诀 | 说明与示例 | |--------------|----------------|----------------------------------------------------------------------------| | 1. 写接口 | “接口收对象…

Spring Boot 入门学习

一、 Web应用开发概述 什么是Web应用 1. Web应用 &#xff08;Web Application&#xff09;是一种运行在Web服务器上的软件程序&#xff0c;由用户通过Web浏览器进行访问和交互。 2.Web应用与传统的桌面应用不同&#xff0c;它不需要在个人计算机上安装特定的软件&#xff0…

深度解读概率与证据权重 -Probability and the Weighing of Evidence

以下是I.J.古德&#xff08;I.J. Good&#xff09;的经典著作 《概率与证据权衡》&#xff08;Probability and the Weighing of Evidence, 1950&#xff09; 的中文详细总结&#xff1a; 本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒…

跟着AI学习C#之项目实战-电商平台 Day6

&#x1f4c5; Day 6&#xff1a;后台管理系统开发&#xff08;Admin Panel&#xff09; ✅ 今日目标&#xff1a; 创建管理员页面布局实现商品管理&#xff08;CRUD&#xff09;实现订单管理&#xff08;查看、状态变更&#xff09;添加权限控制&#xff08;仅管理员可访问&…

使用OpcUaHelper在C# WinForms中连接OPC UA服务器并读取数据

使用OpcUaHelper在C# WinForms中连接OPC UA服务器并读取数据 下面是一个完整的示例&#xff0c;展示如何使用OpcUaHelper库在C# WinForms应用程序中连接OPC UA服务器并读取数据。 1. 准备工作 首先&#xff0c;确保你已经安装了OpcUaHelper NuGet包。可以通过NuGet包管理器控…

鸿蒙应用开发中的数据存储:SQLite与Preferences全面解析

在鸿蒙&#xff08;HarmonyOS&#xff09;应用开发中&#xff0c;数据存储是构建功能完整、用户体验良好的应用程序的关键环节。鸿蒙系统提供了多种数据存储解决方案&#xff0c;其中SQLite数据库和Preferences&#xff08;偏好设置&#xff09;是最常用的两种方式。本文将深入…