| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> ANR 弹窗的显示原理 -> 正文阅读 |
|
[移动开发]ANR 弹窗的显示原理 |
作者:template-box |
ANR 的根本原因是:应用未在规定的时间内处理 AMS 指定的任务才会 ANR。 所以 Service 未在指定时间内执行完成而且非主进程的 Service 仍然需要通过 AMS 进行通信。这也能说明一定会产生 ANR 的。 实验: === 理论上是会,那我们就写个小 demo 来试一下。 写一个 Service: class NoZuoNoDieService: Service() { override fun onBind(intent: Intent?): IBinder? { return null } override fun onCreate() { super.onCreate() // 小睡会模拟耗时 Thread.sleep(21_000) } } 然后在 AndroidManifest 里声明在独立进程 <service android:name=".service.NoZuoNoDieService" android:process=":whatever" /> 最后我们把这个 Service 调起来作死 startService(Intent(this, NoZuoNoDieService::class.java)) 应用并没有 ANR 弹窗,不过 logcat 有 ANR 相关信息,看一下 trace 文件: ----- pid 14608 at 2021-03-23 19:56:20 ----- Cmd line: demo.com.sam.demofactory:whatever … 省略无关信息 “main” prio=5 tid=1 Sleeping | group=“main” sCount=1 dsCount=0 flags=1 obj=0x73f13a80 self=0x78e7cc2a00 | sysTid=14608 nice=0 cgrp=default sched=0/0 handle=0x796c96d9a8 | state=S schedstat=( 57816925 3067496 80 ) utm=2 stm=3 core=4 HZ=100 | stack=0x7fe1d03000-0x7fe1d05000 stackSize=8MB | held mutexes= at java.lang.Thread.sleep(Native method)
at java.lang.Thread.sleep(Thread.java:373)
at java.lang.Thread.sleep(Thread.java:314) at demo.com.sam.demofactory.service.NoZuoNoDieService.onCreate(NoZuoNoDieService.kt:15) at android.app.ActivityThread.handleCreateService(ActivityThread.java:3426) at android.app.ActivityThread.-wrap4(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:171) at android.app.ActivityThread.main(ActivityThread.java:6611) at java.lang.reflect.Method.invoke(Native method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) ANR 弹窗的显示原理 =========== 我们来看一下这个没有弹窗的 ANR 是怎么发生的 首先来复习一下?说一说 Service 的启动流程 AMS 真正去启动 Service 调用的是 ActiveServices.realStartServiceLocked 方法: // API 29 com.android.server.am.ActiveServices private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { … bumpServiceExecutingLocked(r, execInFg, “create”); } private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { … scheduleServiceTimeoutLocked(r.app); } // 通过 Handler 延时发一条消息,延时时间则为 Service 触发的 ANR 时长 // SERVICE_TIMEOUT = 20*1000 // SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; void scheduleServiceTimeoutLocked(ProcessRecord proc) { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; mAm.mHandler.sendMessageDelayed(msg, proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); } 如果 Service 在规定时间内启动完成,则这个消息会被 remove 掉,我们今天要看一下超时之后,收到这个消息是怎么处理的。 // com.android.server.am.ActivityManagerService.MainHandler final class MainHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { mServices.serviceTimeout((ProcessRecord)msg.obj); } break; } } mServices 是 ActiveServices: // com.android.server.am.ActiveServices#serviceTimeout void serviceTimeout(ProcessRecord proc) { … if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) { Slog.w(TAG, "Timeout executing service: " + timeout); … mAm.mHandler.removeCallbacks(mLastAnrDumpClearer); mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS); anrMessage = "executing service " + timeout.shortInstanceName; } … if (anrMessage != null) { proc.appNotResponding(null, null, null, null, false, anrMessage); } } appNotResponding 就是最终处理 ANR 逻辑的代码了 // com.android.server.am.ProcessRecord void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, …) { … if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 5:27:25- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |