Android-Service-ANR-的監控機制,Android高階面試題
if (DEBUG_MESS
《Android學習筆記總結+最新移動架構影片+大廠安卓面試真題+專案實戰原始碼講義》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整資料開源分享
AGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
-
": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);//類H,繼承Handler,專門接收AMS排程過來的四大元件排程訊息。
}
//H程式碼:
public void handleMessage(Message msg) {
switch (msg.what) {
。。。//省略
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
。。。//省略
}
}
//ActivityThread程式碼:
private void handleCreateService(CreateServiceData data) {
...//省略
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();//呼叫onCreate()
mServices.put(data.token, service);
try {//跨程序傳達service建立成功。
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
-
": " + e.toString(), e);
}
}
}
由上面的核心程式碼片段可以看出,最終Service的建立流程會由sys_server程序中的AMS,跨程序呼叫ApplicationThread,在App程序通過Handler傳送訊息的形式,執行handleCreateService(),呼叫Service.onCreate()後,再跨程序通知AMSserviceDoneExecuting()。走到這裡,Service在App程序就建立完畢了。onCreate()執行完成。
這一步的流程中,埋下的炸彈時間也在悄然流逝。我們繼續往下看,接下來就看AMS中如何處理炸彈了。
AMS被呼叫到了serviceDoneExecuting() 方法後,會呼叫AS的serviceDoneExecutingLocked()。 在處理了Service.START_STICKY等各種亂七八糟的標記位之後,走到serviceDoneExecutingLocked()方法,這裡真正執行到了“拆除炸彈"的過程,將此前埋入的延時訊息remove。
<pre language="javascript" code_block="true">private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
//省略...
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
//拆除炸彈!!!
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app, true);
}
r.executeFg = false;
if (r.tracker != null) {
r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
}
r.app = null;
}
}
}
那麼問題來了,如果在呼叫mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);的時候發現沒有該訊息了會發生什麼呢? 那其實就說明,mAm.mHandler 已經處理了該訊息。我們進入到mAm.mHandler中去一探究竟,它收到該訊息會做什麼事情。
<pre language="javascript" code_block="true">final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//...省略
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
//...省略
}
//...省略
}
//...省略
它委託了AS去執行serviceTimeout(),
<pre language="javascript" code_block="true"> 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 nextTime = 0;
for (int i=proc.executingServices.size()-1; i>=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
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();
mLastAnrDump = sw.toString();
《設計思想解讀開源框架》
第一章、 熱修復設計
-
第一節、 AOT/JIT & dexopt 與 dex2oat
-
第二節、 熱修復設計之 CLASS_ISPREVERIFIED 問題
-
第三節、熱修復設計之熱修復原理
-
第四節、Tinker 的整合與使用(自動補丁包生成)
第二章、 外掛化框架設計
-
第一節、 Class 檔案與 Dex 檔案的結構解讀
-
第二節、 Android 資源載入機制詳解
-
第三節、 四大元件呼叫原理
-
第四節、 so 檔案載入機制
-
第五節、 Android 系統服務實現原理
第三章、 元件化框架設計
-
第一節、阿里巴巴開源路由框——ARouter 原理分析
-
第二節、APT 編譯時期自動生成程式碼&動態類載入
-
第三節、 Java SPI 機制
-
第四節、 AOP&IOC
-
第五節、 手寫元件化架構
第四章、圖片載入框架
-
第一節、圖片載入框架選型
-
第二節、Glide 原理分析
-
第三節、手寫圖片載入框架實戰
第五章、網路訪問框架設計
-
第一節、網路通訊必備基礎
-
第二節、OkHttp 原始碼解讀
-
第三節、Retrofit 原始碼解析
第六章、 RXJava 響應式程式設計框架設計
-
第一節、鏈式呼叫
-
第二節、 擴充套件的觀察者模式
-
第三節、事件變換設計
-
第四節、Scheduler 執行緒控制
第七章、 IOC 架構設計
-
第一節、 依賴注入與控制反轉
-
第二節、ButterKnife 原理上篇、中篇、下篇
-
第三節、Dagger 架構設計核心解密
第八章、 Android 架構元件 Jetpack
-
第一節、 LiveData 原理
-
第二節、 Navigation 如何解決 tabLayout 問題
-
第三節、 ViewModel 如何感知 View 生命週期及核心原理
-
第四節、 Room 架構方式方法
-
第五節、 dataBinding 為什麼能夠支援 MVVM
-
第六節、 WorkManager 核心揭祕
-
第七節、 Lifecycles 生命週期
本文包含不同方向的自學程式設計路線、面試題集合/面經、及系列技術文章等,資源持續更新中…
- 35歲危機?內捲成程式設計師代名詞了…
- 線上文字實體抽取能力,助力應用解析海量文字資料
- 不買排名,不去SEO,如何做到登上谷歌搜尋首頁?
- HtmlParse:一款超輕量級的HTML檔案解析和爬取工具
- 五款當下超火熱的相親交友APP測評
- 盡一份孝心,為家人做一個老人防摔報警系統
- 作為軟體工程師,給年輕時的自己的建議(下)
- 技術分享| 淺談排程平臺設計
- 組態介面推陳出新:打造新一代再生水廠工藝二維組態系統
- 平頭哥 芯事訪談 | 全志科技CTO丁然:影片、AI市場爆發,RISC-V生態需要產業一起努力
- IDEA SSM Maven實現商品管理系統(超詳細SSM整合專案)
- 如何為迴歸測試選擇測試用例?
- 前端必學——函數語言程式設計(五)
- 40篇學完C語言——(第八篇)【指標陣列以及指向指標的指標】
- 焱融看|非結構化資料場景下,資料湖到底有多香?
- 低程式碼開發的未來~
- Docker容器:將帶UI的程式直接轉為Web應用,so easy
- PHP 基於 SW-X 框架,搭建WebSocket伺服器(二)
- 低程式碼開發的前後端聯調——APICloud Studio 3 API管理工具結合資料雲3.0使用教程
- 揭祕華為雲GaussDB(for Influx)最佳實踐:hint查詢