[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
英文地址,請注明出處:http://en.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;是最常用的兩種方式。本文將深入…