Android-Service-ANR-的監控機制,Android高階面試題

語言: CN / TW / HK

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 生命週期

    本文包含不同方向的自學程式設計路線、面試題集合/面經、及系列技術文章等,資源持續更新中…

本文已被 CODING開源專案:《Android學習筆記總結+移動架構影片+大廠面試真題+專案實戰原始碼》 收錄