<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android ANR 無響應(yīng)原理解讀

          共 22926字,需瀏覽 46分鐘

           ·

          2024-04-11 00:02

          571b2f4d3fa719b6a3645bd95664d6b7.webp

          和你一起終身學(xué) 習(xí),這里是程序員Android

          經(jīng)典好文推薦,通過閱讀本文,您將收獲以下知識(shí)點(diǎn):

          一 概述

          ANR (Application Not responding),是指應(yīng)用程序未響應(yīng),Android 系統(tǒng)對(duì)于一些事件需要在一定的時(shí)間范圍內(nèi)完成,如果超過預(yù)定時(shí)間能未能得到有效響應(yīng)或者響應(yīng)時(shí)間過長(zhǎng),都會(huì)造成 ANR。一般地,這時(shí)往往會(huì)彈出一個(gè)提示框,告知用戶當(dāng)前 xxx 未響應(yīng),用戶可選擇繼續(xù)等待或者Force Close。

          那么哪些場(chǎng)景會(huì)造成 ANR 呢?

          • Service Timeout:前臺(tái)服務(wù)在 20s 內(nèi)未執(zhí)行完成

          • BroadcastQueue Timeout:前臺(tái)廣播在 10s 內(nèi)未執(zhí)行完成

          • ContentProvider Timeout:內(nèi)容提供者,超時(shí) 10s

          • InputDispatching Timeout:輸入事件分發(fā)超時(shí) 5s,包括按鍵和觸摸事件

          觸發(fā) ANR 的過程可分為三個(gè)步驟:埋炸彈,拆炸彈,引爆炸彈

          二 Service

          Service Timeout 是位于 ”ActivityManager” 線程中的 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG 消息時(shí)觸發(fā)。

          對(duì)于 Service 有兩類:

          • 對(duì)于前臺(tái)服務(wù),則超時(shí)為 SERVICE_TIMEOUT = 20s

          • 對(duì)于后臺(tái)服務(wù),則超時(shí)為 SERVICE_BACKGROUND_TIMEOUT = 200s

          由變量 ProcessRecord.execServicesFg 來決定是否前臺(tái)啟動(dòng)

          2.1 埋炸彈

          文章Android四大組件系列4 Service啟動(dòng)流程詳細(xì)介紹了 Service 的啟動(dòng)流程。其中在 Service 進(jìn)程 attach 到 system_server 進(jìn)程的過程中會(huì)調(diào)用 realStartServiceLocked() 方法來埋下炸彈。

          2.1.1 ActiveServices.realStartServiceLocked

          ActiveServices.java

              private final void realStartServiceLocked(ServiceRecord r,
          ProcessRecord app, boolean execInFg) throws RemoteException {
          ......
          //發(fā)送delay消息(SERVICE_TIMEOUT_MSG)
          bumpServiceExecutingLocked(r, execInFg, "create");
          try {
          ......
          //最終執(zhí)行服務(wù)的onCreate()方法
          app.thread.scheduleCreateService(r, r.serviceInfo,
          mAm.compatibilityInfoForPackageLocked(
          r.serviceInfo.applicationInfo),
          app.repProcState);
          } catch (DeadObjectException e) {
          ......
          } finally {
          ......
          }
          ......
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          2.1.2 ActiveServices.bumpServiceExecutingLocked

          ActiveServices.java

              private final void bumpServiceExecutingLocked(ServiceRecord r,
          boolean fg, String why) {
          ......
          scheduleServiceTimeoutLocked(r.app);
          ......
          }

          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;
          //當(dāng)超時(shí)后仍沒有remove該SERVICE_TIMEOUT_MSG消息,則執(zhí)行service Timeout流程
          mAm.mHandler.sendMessageDelayed(msg,
          proc.execServicesFg ? (now+SERVICE_TIMEOUT) :
          (now+ SERVICE_BACKGROUND_TIMEOUT));
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          該方法的主要工作是發(fā)送 delay 消息 (SERVICE_TIMEOUT_MSG)。炸彈已埋下,我們并不希望炸彈被引爆,那么就需要在炸彈爆炸之前拆除炸彈。

          2.2 拆炸彈

          在 system_server 進(jìn)程 ActiveServices.realStartServiceLocked() 調(diào)用的過程會(huì)埋下一顆炸彈,超時(shí)沒有啟動(dòng)完成則會(huì)爆炸。那么什么時(shí)候會(huì)拆除這顆炸彈的引線呢?我們來看經(jīng)過 Binder 等進(jìn)程間通信層層調(diào)用進(jìn)入目標(biāo)進(jìn)程的主線程 handleCreateService() 函數(shù)。

          2.2.1 ActivityThread.handleCreateService

          ActivityThread.java

              private void handleCreateService(CreateServiceData data) {
          ......
          java.lang.ClassLoader cl = packageInfo.getClassLoader();
          Service service = packageInfo.getAppFactory()
          .instantiateService(cl, data.info.name, data.intent);
          ......
          try {
          //創(chuàng)建ContextImpl對(duì)象
          ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
          context.setOuterContext(service);
          //創(chuàng)建Application對(duì)象
          Application app = packageInfo.makeApplication(false, mInstrumentation);
          service.attach(context, this, data.info.name, data.token, app,
          ActivityManagerNative.getDefault());
          //調(diào)用服務(wù)onCreate()方法
          service.onCreate();
          mServices.put(data.token, service);

          //拆除炸彈引線
          ActivityManager.getService().serviceDoneExecuting(
          data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
          } catch (Exception e) {
          ......
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          在這個(gè)過程會(huì)創(chuàng)建目標(biāo)服務(wù)對(duì)象,并回調(diào)其 onCreate() 方法,緊接著再次經(jīng)過 IPC 調(diào)用回到 system_server 來執(zhí)行 serviceDoneExecuting。

          2.2.2 ActiveServices.serviceDoneExecutingLocked

          ActiveServices.java

              private void serviceDoneExecutingLocked(ServiceRecord r,
          boolean inDestroying, boolean finishing) {
          ......
          if (r.executeNesting <= 0) {
          if (r.app != null) {
          r.app.execServicesFg = false;
          r.app.executingServices.remove(r);
          if (r.app.executingServices.size() == 0) {
          //當(dāng)前服務(wù)所在進(jìn)程中沒有正在執(zhí)行的service
          mAm.mHandler.removeMessages(
          ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
          ......
          }
          ......
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          該方法的主要工作是當(dāng) service 啟動(dòng)完成,則移除服務(wù)超時(shí)消息 SERVICE_TIMEOUT_MSG。

          2.3 引爆炸彈

          前面介紹了埋炸彈和拆炸彈的過程,如果在炸彈倒計(jì)時(shí)結(jié)束之前成功拆卸炸彈,那么就沒有爆炸的機(jī)會(huì),但是世事難料,總有些極端情況下無法即時(shí)拆除炸彈,導(dǎo)致炸彈爆炸,其結(jié)果就是 App 發(fā)生 ANR。接下來,分析下炸彈爆炸的現(xiàn)場(chǎng)。

          在 system_server 進(jìn)程中有一個(gè) Handler 線程,名叫 ”ActivityManager”。當(dāng)?shù)褂?jì)時(shí)結(jié)束便會(huì)向該 Handler 線程發(fā)送一條消息 SERVICE_TIMEOUT_MSG。

          2.3.1 MainHandler.handleMessage

          ActivityManagerService.java ::MainHandler

              final class MainHandler extends Handler {
          ......
          public void handleMessage(Message msg) {
          switch (msg.what) {
          case SERVICE_TIMEOUT_MSG: {
          ......
          mServices.serviceTimeout((ProcessRecord)msg.obj);
          } break;
          ......
          }
          ......
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          2.3.2 ActiveServices.serviceTimeout

          ActiveServices.java

              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.mProcessList.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();
          mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
          mAm.mHandler.postDelayed(mLastAnrDumpClearer,
          LAST_ANR_LIFETIME_DURATION_MSECS);
          anrMessage = "executing service " + timeout.shortName;
          }
          }

          if (anrMessage != null) {
          //當(dāng)存在timeout的service,則執(zhí)行appNotResponding
          proc.appNotResponding(null, null, null, null, false, anrMessage);
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          • 27

          • 28

          • 29

          • 30

          • 31

          • 32

          • 33

          • 34

          • 35

          • 36

          • 37

          • 38

          • 39

          • 40

          • 41

          • 42

          • 43

          其中 anrMessage 的內(nèi)容為 ”executing service [發(fā)送超時(shí) serviceRecord 信息]”。

          三 BroadcastReceiver

          BroadcastReceiver Timeout 是位于 ”ActivityManager” 線程中的 BroadcastQueue.BroadcastHandler 收到 BROADCAST_TIMEOUT_MSG 消息時(shí)觸發(fā)。

          對(duì)于廣播隊(duì)列在 AMS 中有兩個(gè):mFgBroadcastQueue 隊(duì)列和 mBgBroadcastQueue 隊(duì)列:

          • 對(duì)于前臺(tái)廣播,則超時(shí)為 BROADCAST_FG_TIMEOUT = 10s

          • 對(duì)于后臺(tái)廣播,則超時(shí)為 BROADCAST_BG_TIMEOUT = 60s

          3.1 埋炸彈

          我們之前已經(jīng)分析過廣播的注冊(cè)和發(fā)送流程,通過調(diào)用 processNextBroadcast 來處理廣播。其流程為先處理并行廣播,再處理當(dāng)前有序廣播,最后獲取并處理下條有序廣播。

          3.1.1 processNextBroadcast

              final void processNextBroadcast(boolean fromMsg) {
          synchronized (mService) {
          processNextBroadcastLocked(fromMsg, false);
          }
          }


          final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
          BroadcastRecord r;
          ......
          //part 2: 處理當(dāng)前有序廣播
          do {
          final long now = SystemClock.uptimeMillis();
          r = mDispatcher.getNextBroadcastLocked(now);
          ......
          //獲取所有該廣播所有的接收者
          int numReceivers =
          (r.receivers != null) ? r.receivers.size() : 0;
          if (mService.mProcessesReady && !r.timeoutExempt &&
          r.dispatchTime > 0) {
          long now = SystemClock.uptimeMillis();
          if ((numReceivers > 0) &&
          (now > r.dispatchTime + (2*mConstants.TIMEOUT*numReceivers))) {
          //當(dāng)廣播處理時(shí)間超時(shí),則強(qiáng)制結(jié)束這條廣播
          broadcastTimeoutLocked(false);
          ......
          }
          }
          if (r.receivers == null || r.nextReceiver >= numReceivers
          || r.resultAbort || forceReceive) {
          if (r.resultTo != null) {
          //處理廣播消息消息
          performReceiveLocked(r.callerApp, r.resultTo,
          new Intent(r.intent), r.resultCode,
          r.resultData, r.resultExtras, false, false, r.userId);
          r.resultTo = null;
          }
          //拆炸彈
          cancelBroadcastTimeoutLocked();
          }
          } while (r == null);
          ......
          //part 3: 獲取下條有序廣播
          r.receiverTime = SystemClock.uptimeMillis();
          if (!mPendingBroadcastTimeoutMessage) {
          long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
          //埋炸彈
          setBroadcastTimeoutLocked(timeoutTime);
          }
          ......
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          • 27

          • 28

          • 29

          • 30

          • 31

          • 32

          • 33

          • 34

          • 35

          • 36

          • 37

          • 38

          • 39

          • 40

          • 41

          • 42

          • 43

          • 44

          • 45

          • 46

          • 47

          • 48

          • 49

          • 50

          • 51

          對(duì)于廣播超時(shí)處理時(shí)機(jī):

          1.首先在 part3 的過程中 setBroadcastTimeoutLocked(timeoutTime) 設(shè)置超時(shí)廣播消息
          2.然后在 part2 根據(jù)廣播處理情況來處理:

          • 當(dāng)廣播接收者等待時(shí)間過長(zhǎng),則調(diào)用 broadcastTimeoutLocked(false)

          • 當(dāng)執(zhí)行完廣播,則調(diào)用 cancelBroadcastTimeoutLocked

          3.1.2 setBroadcastTimeoutLocked

              final void setBroadcastTimeoutLocked(long timeoutTime) {
          if (!mPendingBroadcastTimeoutMessage) {
          Message msg =
          mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
          mHandler.sendMessageAtTime(msg, timeoutTime);
          mPendingBroadcastTimeoutMessage = true;
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          設(shè)置定時(shí)廣播 BROADCAST_TIMEOUT_MSG,即當(dāng)前往后推 mTimeout 時(shí)間廣播還沒處理完畢,則進(jìn)入廣播超時(shí)流程。

          3.2 拆炸彈

          broadcast 跟 service 超時(shí)機(jī)制大體上相同,但有一個(gè)非常隱蔽的技能點(diǎn),那就是通過靜態(tài)注冊(cè)的廣播超時(shí)會(huì)受 SharedPreferences 的影響。

          3.2.1 sendFinished

          關(guān)于廣播是否考慮 SP 的情況取決于如下代碼:

          BroadcastReceiver.PendingResult.finish

              public final void finish() {
          if (mType == TYPE_COMPONENT) {
          final IActivityManager mgr = ActivityManager.getService();
          if (QueuedWork.hasPendingWork()) {
          //當(dāng)SP有未同步到磁盤的工作,則需等待其完成,才告知系統(tǒng)已完成該廣播
          QueuedWork.queue(new Runnable() {
          @Override public void run() {
          if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
          "Finishing broadcast after work to component " + mToken);
          sendFinished(mgr);
          }
          }, false);
          } else {
          if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
          "Finishing broadcast to component " + mToken);
          sendFinished(mgr);
          }
          } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
          if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
          "Finishing broadcast to " + mToken);
          final IActivityManager mgr = ActivityManager.getService();
          sendFinished(mgr);
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          可見,只有 XML 靜態(tài)注冊(cè)的廣播超時(shí)檢測(cè)過程會(huì)考慮是否有 SP 尚未完成,動(dòng)態(tài)廣播并不受其影響。

          3.2.2 cancelBroadcastTimeoutLocked

              final void cancelBroadcastTimeoutLocked() {
          if (mPendingBroadcastTimeoutMessage) {
          mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
          mPendingBroadcastTimeoutMessage = false;
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          移除廣播超時(shí)消息 BROADCAST_TIMEOUT_MSG。

          3.3 引爆炸彈

          3.3.1 BroadcastHandler.handleMessage

          BroadcastQueue.java ::BroadcastHandler

              private final class BroadcastHandler extends Handler {
          public void handleMessage(Message msg) {
          switch (msg.what) {
          case BROADCAST_INTENT_MSG: {
          if (DEBUG_BROADCAST) Slog.v(
          TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
          + mQueueName + "]");
          processNextBroadcast(true);
          } break;
          case BROADCAST_TIMEOUT_MSG: {
          synchronized (mService) {
          broadcastTimeoutLocked(true);
          }
          } break;
          }
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          3.3.2 broadcastTimeoutLocked

          BroadcastQueue.java

              final void broadcastTimeoutLocked(boolean fromMsg) {
          if (fromMsg) {//fromMsg = true
          mPendingBroadcastTimeoutMessage = false;
          }
          if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked()
          == null) {
          return;
          }
          long now = SystemClock.uptimeMillis();
          BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
          if (fromMsg) {
          //當(dāng)系統(tǒng)還沒有準(zhǔn)備就緒時(shí),廣播處理流程中不存在廣播超時(shí)
          if (!mService.mProcessesReady) {
          return;
          }
          ......
          long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
          if (timeoutTime > now) {
          //如果當(dāng)前正在執(zhí)行的receiver沒有超時(shí),則重新設(shè)置廣播超時(shí)
          setBroadcastTimeoutLocked(timeoutTime);
          return;
          }
          }
          if (r.state == BroadcastRecord.WAITING_SERVICES) {
          //廣播已經(jīng)處理完成,但需要等待已啟動(dòng)service執(zhí)行完成。當(dāng)?shù)却銐驎r(shí)間,則處理下一條廣播。
          r.curComponent = null;
          r.state = BroadcastRecord.IDLE;
          processNextBroadcast(false);
          return;
          }
          r.receiverTime = now;
          if (!debugging) {
          r.anrCount++;//當(dāng)前BroadcastRecord的anr次數(shù)執(zhí)行加1操作
          }
          Object curReceiver;
          if (r.nextReceiver > 0) {
          curReceiver = r.receivers.get(r.nextReceiver-1);
          r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
          } else {
          curReceiver = r.curReceiver;
          }
          //查詢App進(jìn)程
          if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
          BroadcastFilter bf = (BroadcastFilter)curReceiver;
          if (bf.receiverList.pid != 0
          && bf.receiverList.pid != ActivityManagerService.MY_PID) {
          synchronized (mService.mPidsSelfLocked) {
          app = mService.mPidsSelfLocked.get(
          bf.receiverList.pid);
          }
          }
          } else {
          app = r.curApp;
          }
          if (app != null) {
          anrMessage = "Broadcast of " + r.intent.toString();
          }

          if (mPendingBroadcast == r) {
          mPendingBroadcast = null;
          }
          //繼續(xù)移動(dòng)到下一個(gè)廣播接收者
          finishReceiverLocked(r, r.resultCode, r.resultData,
          r.resultExtras, r.resultAbort, false);
          scheduleBroadcastsLocked();

          if (!debugging && anrMessage != null) {
          mHandler.post(new AppNotResponding(app, anrMessage));
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          • 27

          • 28

          • 29

          • 30

          • 31

          • 32

          • 33

          • 34

          • 35

          • 36

          • 37

          • 38

          • 39

          • 40

          • 41

          • 42

          • 43

          • 44

          • 45

          • 46

          • 47

          • 48

          • 49

          • 50

          • 51

          • 52

          • 53

          • 54

          • 55

          • 56

          • 57

          • 58

          • 59

          • 60

          • 61

          • 62

          • 63

          • 64

          • 65

          • 66

          • 67

          • 68

          • 69

          • 70

          3.3.3 AppNotResponding

          BroadcastQueue.java

              private final class AppNotResponding implements Runnable {
          private final ProcessRecord mApp;
          private final String mAnnotation;

          public AppNotResponding(ProcessRecord app, String annotation) {
          mApp = app;
          mAnnotation = annotation;
          }

          @Override
          public void run() {
          // 進(jìn)入ANR處理流程
          mApp.appNotResponding(null, null, null, null, false, mAnnotation);
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          四 ContentProvider

          ContentProvider Timeout 是位于 ”ActivityManager” 線程中的 AMS.MainHandler 收到 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG 消息時(shí)觸發(fā)。

          ContentProvider 超時(shí)為 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s。這個(gè)跟前面的 Service 和 BroadcastQueue 完全不同,由 Provider 進(jìn)程啟動(dòng)過程相關(guān)。

          4.1 埋炸彈

          我們之前詳細(xì)介紹了 Provider 啟動(dòng)流程。埋炸彈的過程其實(shí)是在進(jìn)程創(chuàng)建的過程,進(jìn)程創(chuàng)建后會(huì)調(diào)用 attachApplicationLocked() 進(jìn)入 system_server 進(jìn)程。

          4.1.1 AMS.attachApplicationLocked

              private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
          int pid, int callingUid, long startSeq) {
          ProcessRecord app;
          long startTime = SystemClock.uptimeMillis();
          long bindApplicationTimeMillis;
          if (pid != MY_PID && pid >= 0) {
          synchronized (mPidsSelfLocked) {
          app = mPidsSelfLocked.get(pid); // 根據(jù)pid獲取ProcessRecord
          }
          }
          ......
          //系統(tǒng)處于ready狀態(tài)或者該app為FLAG_PERSISTENT進(jìn)程則為true
          boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
          List<ProviderInfo> providers = normalMode ?
          generateApplicationProvidersLocked(app) : null;

          //app進(jìn)程存在正在啟動(dòng)中的provider
          // 則超時(shí)10s后發(fā)送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
          if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
          Message msg = mHandler.obtainMessage(
          CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
          msg.obj = app;
          mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
          }
          ......
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          4.2 拆炸彈

          當(dāng) provider 成功 publish 之后,便會(huì)拆除該炸彈。

          4.2.1 AMS.publishContentProviders

              public final void publishContentProviders(IApplicationThread caller,
          List<ContentProviderHolder> providers) {
          ......
          synchronized (this) {
          final ProcessRecord r = getRecordForAppLocked(caller);

          final int N = providers.size();
          for (int i = 0; i < N; i++) {
          ContentProviderHolder src = providers.get(i);
          ......
          ContentProviderRecord dst = r.pubProviders.get(src.info.name);
          if (dst != null) {
          ComponentName comp =
          new ComponentName(dst.info.packageName, dst.info.name);
          //將該provider添加到mProviderMap
          mProviderMap.putProviderByClass(comp, dst);
          String names[] = dst.info.authority.split(";");
          for (int j = 0; j < names.length; j++) {
          mProviderMap.putProviderByName(names[j], dst);
          }

          int launchingCount = mLaunchingProviders.size();
          int j;
          boolean wasInLaunchingProviders = false;
          for (j = 0; j < launchingCount; j++) {
          if (mLaunchingProviders.get(j) == dst) {
          //將該provider移除mLaunchingProviders隊(duì)列
          mLaunchingProviders.remove(j);
          wasInLaunchingProviders = true;
          j--;
          launchingCount--;
          }
          }
          //成功pubish則移除該消息
          if (wasInLaunchingProviders) {
          mHandler.removeMessages(
          CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
          }
          synchronized (dst) {
          dst.provider = src.provider;
          dst.proc = r;
          //喚醒客戶端的wait等待方法
          dst.notifyAll();
          }
          ......
          }
          }
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          • 27

          • 28

          • 29

          • 30

          • 31

          • 32

          • 33

          • 34

          • 35

          • 36

          • 37

          • 38

          • 39

          • 40

          • 41

          • 42

          • 43

          • 44

          • 45

          • 46

          • 47

          • 48

          • 49

          4.3 引爆炸彈

          在 system_server 進(jìn)程中有一個(gè) Handler 線程, 名 叫”ActivityManager”。當(dāng)?shù)褂?jì)時(shí)結(jié)束便會(huì)向該 Handler 線程發(fā)送 一條信息 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG

          4.3.1 MainHandler.handleMessage

          ActivityManagerService.java ::MainHandler

              final class MainHandler extends Handler {
          public void handleMessage(Message msg) {
          switch (msg.what) {
          ......
          case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
          ProcessRecord app = (ProcessRecord)msg.obj;
          synchronized (ActivityManagerService.this) {
          processContentProviderPublishTimedOutLocked(app);
          }
          } break;
          ......
          }
          ......
          }
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          4.3.2 AMS.processContentProviderPublishTimedOutLocked

              private final void processContentProviderPublishTimedOutLocked(
          ProcessRecord app) {
          cleanupAppInLaunchingProvidersLocked(app, true);
          mProcessList.removeProcessLocked(app, false, true,
          "timeout publishing content providers");
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          4.3.3 AMS.cleanupAppInLaunchingProvidersLocked

              boolean cleanupAppInLaunchingProvidersLocked(
          ProcessRecord app, boolean alwaysBad) {
          boolean restart = false;
          for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
          ContentProviderRecord cpr = mLaunchingProviders.get(i);
          if (cpr.launchingApp == app) {
          if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
          restart = true;
          } else {
          //移除死亡的provider
          removeDyingProviderLocked(app, cpr, true);
          }
          }
          }
          return restart;
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          removeDyingProviderLocked() 的功能跟進(jìn)程的存活息息相關(guān)

          • 對(duì)于 stable 類型的 provider (即 conn.stableCount > 0),則會(huì)殺掉所有跟該 provider 建立 stable 連接的非persistent 進(jìn)程

          • 對(duì)于 unstable 類的 provider (即 conn.unstableCount > 0),并不會(huì)導(dǎo)致 client 進(jìn)程被級(jí)聯(lián)所殺

          4.3.4 ProcessList.removeProcessLocked

              boolean removeProcessLocked(ProcessRecord app,
          boolean callerWillRestart, boolean allowRestart, String reason) {
          final String name = app.processName;
          final int uid = app.uid;
          ......
          //移除mProcessNames中的相應(yīng)對(duì)象
          removeProcessNameLocked(name, uid);
          mService.mAtmInternal.clearHeavyWeightProcessIfEquals(
          app.getWindowProcessController());

          boolean needRestart = false;
          if ((app.pid > 0 && app.pid != ActivityManagerService.MY_PID) ||
          (app.pid == 0 && app.pendingStart)) {
          int pid = app.pid;
          if (pid > 0) {
          ......
          }
          boolean willRestart = false;
          if (app.isPersistent() && !app.isolated) {
          if (!callerWillRestart) {
          willRestart = true;
          } else {
          needRestart = true;
          }
          }
          app.kill(reason, true);//殺進(jìn)程
          mService.handleAppDiedLocked(app, willRestart, allowRestart);
          if (willRestart) {
          removeLruProcessLocked(app);
          mService.addAppLocked(app.info, null, false, null /* ABI override */);
          }
          } else {
          mRemovedProcesses.add(app);
          }

          return needRestart;
          }
          • 1

          • 2

          • 3

          • 4

          • 5

          • 6

          • 7

          • 8

          • 9

          • 10

          • 11

          • 12

          • 13

          • 14

          • 15

          • 16

          • 17

          • 18

          • 19

          • 20

          • 21

          • 22

          • 23

          • 24

          • 25

          • 26

          • 27

          • 28

          • 29

          • 30

          • 31

          • 32

          • 33

          • 34

          • 35

          • 36

          • 37

          五 總結(jié)

          當(dāng)出現(xiàn) ANR 時(shí),都是調(diào)用到 AMS.appNotResponding() 方法,詳細(xì)過程見文章理解Android ANR的信息收集過程. 當(dāng)然這里介紹的 provider 例外。

          5.1 Timeout時(shí)長(zhǎng)

          • 對(duì)于前臺(tái)服務(wù),則超時(shí)為 SERVICE_TIMEOUT = 20s

          • 對(duì)于后臺(tái)服務(wù),則超時(shí)為 SERVICE_BACKGROUND_TIMEOUT = 200s

          • 對(duì)于前臺(tái)廣播,則超時(shí)為 BROADCAST_FG_TIMEOUT = 10s

          • 對(duì)于后臺(tái)廣播,則超時(shí)為 BROADCAST_BG_TIMEOUT = 60s

          • ContentProvider 超時(shí)為 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s

          5.2 超時(shí)檢測(cè)

          Service 超時(shí)檢測(cè)機(jī)制:

          • 超過一定時(shí)間沒有執(zhí)行完相應(yīng)操作來觸發(fā)移除延時(shí)消息,則會(huì)觸發(fā) anr

          BroadcastReceiver 超時(shí)檢測(cè)機(jī)制:

          • 有序廣播的總執(zhí)行時(shí)間超過 2* receiver 個(gè)數(shù) * timeout 時(shí)長(zhǎng),則會(huì)觸發(fā) anr

          • 有序廣播的某一個(gè) receiver 執(zhí)行過程超過 timeout 時(shí)長(zhǎng),則會(huì)觸發(fā) anr

          另外:

          • 對(duì)于 Service,Broadcast,Input 發(fā)生 ANR 之后,最終都會(huì)調(diào)用 AMS.appNotResponding

          • 對(duì)于 provider,在其進(jìn)程啟動(dòng)時(shí) publish 過程可能會(huì)出現(xiàn) ANR,則會(huì)直接殺進(jìn)程以及清理相應(yīng)信息,而不會(huì)彈出 ANR 的對(duì)話框。appNotRespondingViaProvider() 過程會(huì)走 appNotResponding(),這個(gè)就不介紹了,很少使用,由用戶自定義超時(shí)時(shí)間.

           原文鏈接:

          https://blog.csdn.net/liuwg1226/article/details/11383483

          至此,本篇已結(jié)束。轉(zhuǎn)載網(wǎng)絡(luò)的文章,小編覺得很優(yōu)秀,歡迎點(diǎn)擊閱讀原文,支持原創(chuàng)作者,如有侵權(quán),懇請(qǐng)聯(lián)系小編刪除,歡迎您的建議與指正。同時(shí)期待您的關(guān)注,感謝您的閱讀,謝謝!

          點(diǎn)個(gè)在看,方便您使用時(shí)快速查找!

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲精品视频网 | 黄片免费视频在线 | 国模吧一二三区 | 精品婷婷色一区二区三区蜜桃 | a天堂视频|