日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Android ANR原理分析

瀏覽:171日期:2022-09-17 18:18:37
目錄卡頓原理卡頓監(jiān)控ANR原理卡頓原理

主線程有耗時(shí)操作會(huì)導(dǎo)致卡頓,卡頓超過閥值,觸發(fā)ANR。 應(yīng)用進(jìn)程啟動(dòng)時(shí)候,Zygote會(huì)反射調(diào)用ActivityThread的main方法,啟動(dòng)loop循環(huán)。 ActivityThread(api29)

public static void main(String[] args) {Looper.prepareMainLooper();...Looper.loop();throw new RuntimeException('Main thread loop unexpectedly exited'); }

Looper的loop方法:

// 在線程中運(yùn)行消息隊(duì)列。一定要調(diào)用public static void loop() {for (;;) { // 1、取消息 Message msg = queue.next(); // might block ... // This must be in a local variable, in case a UI event sets the logger // 2、消息處理前回調(diào) final Printer logging = me.mLogging; if (logging != null) {logging.println('>>>>> Dispatching to ' + msg.target + ' ' +msg.callback + ': ' + msg.what); } ... // 3、消息開始處理 msg.target.dispatchMessage(msg); ... // 4、消息處理完回調(diào) if (logging != null) {logging.println('<<<<< Finished to ' + msg.target + ' ' + msg.callback); }}}

loop中for循環(huán)存在,主線程可以長(zhǎng)時(shí)間運(yùn)行。在主線程執(zhí)行任務(wù),可以通過Handler post一個(gè)任務(wù)到消息隊(duì)列去,loop循環(huán)拿到msg,交給msg的target(Handler)處理。

可能導(dǎo)致卡頓兩個(gè)地方:

注釋1 queue.next() 注釋3 dispatchMessage耗時(shí)

MessageQueue.next 耗時(shí)代碼(api29)

@UnsupportedAppUsage Message next() {for (;;) { // 1、nextPollTimeoutMillis不為0則阻塞 nativePollOnce(ptr, nextPollTimeoutMillis); // 2、先判斷當(dāng)前第一條消息是不是同步屏障消息, if (msg != null && msg.target == null) { // 3、遇到同步屏障消息,就跳過去取后面的異步消息來處理,同步消息相當(dāng)于被設(shè)立了屏障 // Stalled by a barrier. Find the next asynchronous message in the queue. do {prevMsg = msg;msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } // 4、正常消息處理,判斷是否延時(shí) if (msg != null) { if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else {// Got a message.mBlocked = false;if (prevMsg != null) { prevMsg.next = msg.next;} else { mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, 'Returning message: ' + msg);msg.markInUse();return msg; }} else { // 5、如果沒有取到異步消息,下次循環(huán)到注視1,nativePollOnce為-1,會(huì)一直阻塞 // No more messages. nextPollTimeoutMillis = -1;}} } MessageQueue是鏈表數(shù)據(jù)結(jié)構(gòu),判斷MessageQueue頭部(第一個(gè)消息)是不是同步屏障消息(給同步消息加一層屏障,讓同步消息不被處理,只會(huì)處理異步消息); 如果遇到同步屏障消息,就會(huì)跳過MessageQueue中同步消息,只會(huì)處理里面的異步消息來處理。如果沒有異步消息則到注釋5,nextPollTimeoutMillis為-1,下次循環(huán)調(diào)用注釋1的nativePollOnce就會(huì)阻塞; 如果looper能正常獲取消息,不論異步/同步消息,處理流程一樣,在注釋4,判斷是否延時(shí),如果是,nextPollTimeoutMillis被賦值,下次調(diào)用注釋1的nativePollOnce就會(huì)阻塞一段時(shí)間。如果不是delay消息,直接返回msg,給handler處理。

next方法不斷從MessageQueue取消息,有消息就處理,沒有消息就調(diào)用nativePollOnce阻塞,底層是Linux的epoll機(jī)制,Linux IO多路復(fù)用。

Linux IO多路復(fù)用方案有select、poll、epoll。其中epoll性能最優(yōu),支持并發(fā)量最大。

select: 是操作系統(tǒng)提供的系統(tǒng)調(diào)用函數(shù),可以把文件描述符的數(shù)組發(fā)給操作系統(tǒng),操作系統(tǒng)去遍歷,確定哪個(gè)描述符可以讀寫,告訴我們?nèi)ヌ幚怼? poll:和select主要區(qū)別,去掉了select只能監(jiān)聽1024個(gè)文件描述符的限制。 epoll:針對(duì)select的三個(gè)可優(yōu)化點(diǎn)進(jìn)行改進(jìn)。

1、內(nèi)核中保持一份文件描述符集合,無需用戶每次重新傳入,只需要告訴內(nèi)核修改部分。2、內(nèi)核不再通過輪詢方式找到就緒的文件描述符,通過異步IO事件喚醒。3、內(nèi)核僅會(huì)將有IO的文件描述符返回給用戶,用戶無需遍歷整個(gè)文件描述符集合。

同步屏障消息

Android App是無法直接調(diào)用同步消息屏障的,MessageQueue(api29)代碼

@TestApi public int postSyncBarrier() {return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier(long when) {... }

系統(tǒng)高優(yōu)先級(jí)的操作使用到同步屏障消息,例如:View繪制的時(shí)候ViewRootImpl的scheduleTraversals方法,插入同步屏障消息,繪制完成后移除同步屏障消息。ViewRootImpl api29

@UnsupportedAppUsage void scheduleTraversals() {if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) {scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded();} }void unscheduleTraversals() {if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); mChoreographer.removeCallbacks( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);} }

為了保證View的繪制過程不被主線程其他任務(wù)影響,View在繪制之前會(huì)先往MessageQueue插入同步屏障消息,然后再注冊(cè)Vsync信號(hào)監(jiān)聽,Choreographer$FrameDisplayEventReceiver監(jiān)聽接收vsync信號(hào)回調(diào)的。

private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { @Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {Message msg = Message.obtain(mHandler, this);// 1、發(fā)送異步消息msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } @Override public void run() {// 2、doFrame優(yōu)先執(zhí)行doFrame(mTimestampNanos, mFrame); } }

收到Vsync信號(hào)回調(diào),注釋1往主線程MessageQueue post一個(gè)異步消息,保證注釋2的doFrame優(yōu)先執(zhí)行。

doFrame才是View真正開始繪制的地方,會(huì)調(diào)用ViewRootIml的doTraversal、performTraversals,而performTraversals里面會(huì)調(diào)用View的onMeasure、onLayout、onDraw。

雖然app無法發(fā)送同步屏障消息,但是使用異步消息是允許的。

異步消息 SDK中限制了App不能post異步消息到MessageQueue中,Message類

@UnsupportedAppUsage /*package*/ int flags;

謹(jǐn)慎使用異步消息,使用不當(dāng),可能出現(xiàn)主線程假死。

Handler#dispatchMessage

/** * Handle system messages here. */ public void dispatchMessage(@NonNull Message msg) {if (msg.callback != null) { handleCallback(msg);} else { if (mCallback != null) {if (mCallback.handleMessage(msg)) { return;} } handleMessage(msg);} } Handler#post(Runnable r) 構(gòu)造方法傳CallBack Handler重寫handlerMessage方法

應(yīng)用卡頓,一般都是Handler處理消息太耗時(shí)導(dǎo)致的(方法本身、算法效率、cpu被搶占、內(nèi)存不足、IPC超時(shí)等)

卡頓監(jiān)控

卡頓監(jiān)控方案一 Looper#loop

// 在線程中運(yùn)行消息隊(duì)列。一定要調(diào)用public static void loop() {for (;;) { // 1、取消息 Message msg = queue.next(); // might block ... // This must be in a local variable, in case a UI event sets the logger // 2、消息處理前回調(diào) final Printer logging = me.mLogging; if (logging != null) {logging.println('>>>>> Dispatching to ' + msg.target + ' ' +msg.callback + ': ' + msg.what); } ... // 3、消息開始處理 msg.target.dispatchMessage(msg); ... // 4、消息處理完回調(diào) if (logging != null) {logging.println('<<<<< Finished to ' + msg.target + ' ' + msg.callback); }}}

注釋2和4的logging.println是api提供接口,可監(jiān)聽Handler耗時(shí),通過Looper.getMainLooper().setMessageLogging(printer),拿到消息前后的時(shí)間。監(jiān)聽到卡頓后,dispatchMessage早已調(diào)用結(jié)束,堆棧不包含卡頓代碼。

定時(shí)獲取主線程堆棧,時(shí)間為key,堆棧信息為value,保存map中,發(fā)生卡頓,取出卡頓時(shí)間內(nèi)的堆棧可行。適合線下使用。

logging.println存在字符串拼接,頻繁調(diào)用,創(chuàng)建大量對(duì)象,內(nèi)存抖動(dòng)。 后臺(tái)頻繁獲取主線程堆棧,對(duì)性能影響,獲取主線程堆棧,暫停主線程的運(yùn)行。

卡頓監(jiān)控方案二

對(duì)于線上卡頓監(jiān)控,需要字節(jié)碼插樁技術(shù)。

通過Gradle Plugin+ASM,編譯期在每個(gè)方法開始和結(jié)束位置分別插入一行代碼,統(tǒng)計(jì)耗時(shí)。例如微信Matrix使用的卡頓監(jiān)控方案。注意問題:

避免方法數(shù)暴增:分配獨(dú)立ID作為參數(shù) 過濾簡(jiǎn)單函數(shù):添加黑明單降低非必要函數(shù)統(tǒng)計(jì)

微信Matrix做大量?jī)?yōu)化,包體積增加1%~2%,幀率下降2幀以內(nèi),灰度包使用。

ANR原理 Service Timeout:前臺(tái)服務(wù)20s內(nèi)未執(zhí)行完成,后臺(tái)服務(wù)是10s BroadcastQueue Timeout:前臺(tái)廣播10s內(nèi)執(zhí)行完成,后臺(tái)60s ContentProvider Timeout:publish超時(shí)10s InputDispatching Timeout:輸入事件分發(fā)超過5s,包括按鍵和觸摸事件。

ActivityManagerService api29

// How long we allow a receiver to run before giving up on it. static final int BROADCAST_FG_TIMEOUT = 10*1000; static final int BROADCAST_BG_TIMEOUT = 60*1000;

ANR觸發(fā)流程

埋炸彈

后臺(tái)sevice調(diào)用:Context.startService--> AMS.startService--> ActiveService.startService--> ActiveService.realStartServiceLocked

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {// 1、發(fā)送delay消息(SERVICE_TIMEOUT_MSG)bumpServiceExecutingLocked(r, execInFg, 'create');try { // 2、通知AMS創(chuàng)建服務(wù) app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.getReportedProcState());} }

注釋1內(nèi)部調(diào)用scheduleServiceTimeoutLocked

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;// 發(fā)送delay消息,前臺(tái)服務(wù)是20s,后臺(tái)服務(wù)是200smAm.mHandler.sendMessageDelayed(msg,proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); }

注釋2通知AMS啟動(dòng)服務(wù)前,注釋1發(fā)送handler延遲消息,20s內(nèi)(前臺(tái)服務(wù))沒有處理完,則ActiveServices#serviceTimeout被調(diào)用。

拆炸彈

啟動(dòng)一個(gè)Service,先要經(jīng)過AMS管理,然后AMS通知應(yīng)用執(zhí)行Service的生命周期,ActivityThread的handlerCreateService方法被調(diào)用。

@UnsupportedAppUsage private void handleCreateService(CreateServiceData data) {try { Application app = packageInfo.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); // 1、service onCreate調(diào)用 service.onCreate(); mServices.put(data.token, service); try {// 2、拆炸彈ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) {throw e.rethrowFromSystemServer(); }} }

注釋1,Service的onCreate方法被調(diào)用 注釋2,調(diào)用AMS的serviceDoneExecuting方法,最終會(huì)調(diào)用ActiveServices.serviceDoneExecutingLocked

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {//移除delay消息 mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); }

onCreate調(diào)用后,就會(huì)移除delay消息,炸彈拆除。

引爆炸彈,假設(shè)Service的onCreate執(zhí)行超過10s,那么炸彈就會(huì)引爆,也就是ActiveServices#serviceTimeout方法會(huì)被調(diào)用。api29

void serviceTimeout(ProcessRecord proc) {if (anrMessage != null) { proc.appNotResponding(null, null, null, null, false, anrMessage);}}

所有ANR,最終帶調(diào)用ProcessRecord的appNotResponding方法。api29

void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation) {// 1、寫入event log// Log the ANR to the event log.EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags, annotation);// 2、收集需要的log、anr、cpu等,放到StringBuilder中。// Log the ANR to the main log.StringBuilder info = new StringBuilder();info.setLength(0);info.append('ANR in ').append(processName);if (activityShortComponentName != null) { info.append(' (').append(activityShortComponentName).append(')');}info.append('n');info.append('PID: ').append(pid).append('n');if (annotation != null) { info.append('Reason: ').append(annotation).append('n');}if (parentShortComponentName != null&& parentShortComponentName.equals(activityShortComponentName)) { info.append('Parent: ').append(parentShortComponentName).append('n');}ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);// 3、dump堆棧信息,包括java堆棧和native堆棧,保存到文件中// For background ANRs, don’t pass the ProcessCpuTracker to// avoid spending 1/2 second collecting stats to rank lastPids.File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,(isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,nativePids);String cpuInfo = null;// 4、輸出ANR日志Slog.e(TAG, info.toString());if (tracesFile == null) { // 5、沒有抓到tracesFile,發(fā)一個(gè)SIGNAL_QUIT信號(hào) // There is no trace file, so dump (only) the alleged culprit’s threads to the log Process.sendSignal(pid, Process.SIGNAL_QUIT);}// 6、輸出到drapboxmService.addErrorToDropBox('anr', this, processName, activityShortComponentName,parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);synchronized (mService) { // 7、后臺(tái)ANR,直接殺進(jìn)程 if (isSilentAnr() && !isDebugging()) {kill('bg anr', true);return; } // 8、錯(cuò)誤報(bào)告 // Set the app’s notResponding state, and look up the errorReportReceiver makeAppNotRespondingLocked(activityShortComponentName, annotation != null ? 'ANR ' + annotation : 'ANR', info.toString()); // 9、彈出ANR dialog,會(huì)調(diào)用handleShowAnrUi方法 Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem); mService.mUiHandler.sendMessage(msg);} } 寫入event log 寫入main log 生成tracesFile 輸出ANR logcat(控制臺(tái)可以看到) 如果沒有獲取tracesFile,會(huì)發(fā)SIGNAL_QUIT信號(hào),觸發(fā)收集線程堆棧信息流程,寫入traceFile 輸出到drapbox 后臺(tái)ANR,直接殺進(jìn)程 錯(cuò)誤報(bào)告 彈出ANR dialog 調(diào)用AppErrors#handleShowAnrUi方法。

ANR觸發(fā)流程,埋炸彈--》拆炸彈的過程啟動(dòng)Service,onCreate方法調(diào)用之前會(huì)使用Handler延時(shí)10s的消息,Service的onCreate方法執(zhí)行完,會(huì)把延遲消息移除掉。假如Service的onCreate方法耗時(shí)超過10s,延時(shí)消息就會(huì)被正常處理,觸發(fā)ANR,收集cpu、堆棧消息,彈ANR dialog

抓取系統(tǒng)的data/anr/trace.txt文件,但是高版本系統(tǒng)需要root權(quán)限才能讀取這個(gè)目錄。

ANRWatchDog github.com/SalomonBrys…

自動(dòng)檢測(cè)ANR開源庫(kù)

以上就是Android ANR原理分析的詳細(xì)內(nèi)容,更多關(guān)于Android ANR原理的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
天堂精品久久久久| 国产精品亚洲一区二区在线观看| 国产成人免费精品| 国产综合精品| 国产精品一区二区三区四区在线观看| 亚洲一区资源| 国产精品流白浆在线观看| 欧美日韩中文一区二区| 久久激五月天综合精品| 波多野结衣一区| 成年男女免费视频网站不卡| 亚洲专区视频| 日韩电影免费网址| 麻豆久久久久久| 国产综合亚洲精品一区二| 亚洲区第一页| 日韩在线看片| 国产精品久久久久久av公交车| 欧美中文字幕一区二区| 色爱av综合网| 一区二区小说| 99热免费精品| 亚洲免费黄色| 日韩中文字幕区一区有砖一区 | av综合电影网站| 精品视频99| 精品国产乱码久久久| 国产精品www.| 国产精品欧美日韩一区| 国产精品久久久久av蜜臀| 国产日韩一区二区三区在线 | 青青青国产精品| 午夜久久av| 国产精品99精品一区二区三区∴| 国产精品一区毛片| 久久久国产精品网站| 久久国产精品免费精品3p| 国产精品久久国产愉拍| 国产福利亚洲| 蜜臀久久精品| 中文精品视频| 国产调教精品| 久久精品成人| 亚洲精品第一| 成人在线超碰| 男人的天堂久久精品| 亚洲一区二区日韩| 捆绑调教美女网站视频一区| 久久五月天小说| 日韩精品亚洲aⅴ在线影院| 精品91福利视频| 视频一区中文字幕国产| 精品一区二区三区在线观看视频 | 欧美亚洲一级| 久久久777| 国产精品视频一区二区三区四蜜臂| 中文字幕高清在线播放| 野花国产精品入口| 欧美日韩国产一区二区在线观看| 韩国女主播一区二区三区| 亚洲免费一区二区| 国产精品原创| 久久国际精品| 男人的天堂久久精品| 日产精品一区二区| 日本高清久久| 视频在线在亚洲| 亚洲一区亚洲| 九一成人免费视频| 99热国内精品| 91精品在线观看国产| 97精品一区二区| 一区二区三区四区日本视频| 日韩激情综合| 中文不卡在线| 亚洲午夜久久| 伊人国产精品| 视频一区中文字幕精品| 老鸭窝毛片一区二区三区| 激情久久久久久久| 激情五月综合网| 一级欧洲+日本+国产| 亚洲福利一区| 尤物精品在线| 久久成人一区| 日本综合视频| 国产精品嫩模av在线| 久久wwww| 福利精品一区| 欧美精品日日操| 亚洲精品一区二区妖精| 免费人成精品欧美精品| 丝瓜av网站精品一区二区| 亚州精品视频| 精品国产欧美| 在线视频观看日韩| 蜜芽一区二区三区| 欧美国产日韩电影| 麻豆视频久久| 午夜欧美精品| 国产欧美一级| 精品欧美久久| 久久国产精品免费一区二区三区| 国产精品nxnn| 99久久视频| 国产伦精品一区二区三区千人斩 | 国产一区二区视频在线看| 日韩精品水蜜桃| 日韩精品欧美成人高清一区二区| 久久永久免费| 久久一二三区| 日韩av自拍| 国产欧美午夜| 免费在线观看成人| 日韩一区电影| 91欧美极品| 日韩午夜av在线| 国产91在线精品| 亚洲色图综合| 亚洲午夜黄色| 精品久久影院| 欧美一区久久| 狠狠色综合网| 麻豆精品蜜桃| 久久一区视频| 久久黄色影视| 综合激情一区| 国产亚洲一级| 欧美中文一区二区| 国产91欧美| 国产精品主播在线观看| 亚洲精品小说| 日韩综合精品| 亚洲91精品| 欧美日韩国产免费观看视频| 色婷婷色综合| 99久久亚洲精品| 日韩精品水蜜桃| 99久精品视频在线观看视频| 日韩成人a**站| 久久久精品网| 午夜久久99| 丝袜脚交一区二区| 亚洲一级大片| 欧美日本久久| 久久精品 人人爱| 91精品国产经典在线观看| 久久超级碰碰| 久久久天天操| 国产农村妇女精品一二区| 手机精品视频在线观看| 欧美亚洲三区| 久久视频国产| 国产精品videossex久久发布| 日韩精品一区二区三区免费视频| 日韩精品a在线观看91| 国产精品久久久网站| 成人自拍av| 日韩午夜精品| 久久国产婷婷国产香蕉| 精品精品久久| 视频在线观看一区二区三区| 日韩在线电影| 久久国产免费| 国产欧美日韩在线观看视频| 日韩综合一区| 亚洲18在线| 天堂中文在线播放| 亚洲精品在线国产| 偷拍精品精品一区二区三区| 亚洲影院天堂中文av色| 98精品视频| 欧美日韩亚洲一区在线观看| 久久九九精品| 国产精品久久久网站| 国产一区二区高清| 国产精品久久国产愉拍| 91久久视频| 色爱av综合网| 麻豆成人91精品二区三区| 亚洲免费在线| 久久一区二区三区电影| 国产不卡精品| 国产精品xvideos88| 日韩精品一级| 日韩在线成人| 综合欧美亚洲| 亚洲一区欧美激情| 自拍日韩欧美| 亚洲成人精品| 亚洲不卡av不卡一区二区| 久久国产尿小便嘘嘘| 天堂久久av| 日韩高清二区| 亚洲图片久久| 国产精品天堂蜜av在线播放| 天堂久久av| 欧美日韩一区二区三区不卡视频| 日本午夜精品久久久| 日韩福利在线观看|