서비스 (2) ANR

10495 단어
서비스 라이프 사이클 시퀀스 다이어그램 Service.onCreate()←ApplicationThreadProxy.scheduleCreateService()←realStartServiceLocked() scheduleCreateService()를 호출하기 전에 bumpServiceExecutingLocked()가 호출됩니다.
Service.onBind()/onRebind()←ApplicationThreadProxy.scheduleBindService()← requestServiceBindingLocked() scheduleBindService()를 호출하기 전에, bumpServiceExecutingLocked()가 호출됩니다.
Service.onStartCommand←ApplicationThreadProxy.scheduleServiceArgs()←sendServiceArgsLocked() scheduleServiceArgs()를 호출하기 전에, bumpServiceExecutingLocked()가 호출됩니다.
Service.onUnbind()←ApplicationThreadProxy.scheduleUnbindService()←removeConnectionLocked() scheduleUnbindService()를 호출하기 전에, bumpServiceExecutingLocked()가 호출됩니다.
Service.onDestroy()←ApplicationThreadProxy.scheduleStopService()←bringDownServiceLocked() scheduleStopService()를 호출하기 전에 bumpServiceExecutingLocked()가 호출됩니다.
ActiveServices.bumpServiceExecutingLocked()→ ActiveServices.scheduleServiceTimeoutLocked()→...→ ActiveServices.serviceTimeout()→...→ ActivityManagerSerivce.appNotResponding()→...→ Dialog.show()
ActiveServices.java
static final int SERVICE_TIMEOUT = 20*1000;

static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

final ActivityManagerService mAm;

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    long now = SystemClock.uptimeMillis();
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageAtTime(msg,
            proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}

void serviceTimeout(ProcessRecord proc) {
    String anrMessage = null;
    ...
    if (anrMessage != null) {
        mAm.appNotResponding(proc, null, null, false, anrMessage);
    }
}
ActivityManagerService.java
final MainHandler mHandler;

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;
    }
}

final void appNotResponding(ProcessRecord app, ActivityRecord activity,
        ActivityRecord parent, boolean aboveSystem, final String annotation) {
    ArrayList firstPids = new ArrayList(5);
    SparseArray lastPids = new SparseArray(20);
    ...
    synchronized (this) {
        // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
        if (mShuttingDown) {
            Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
            return;
        } else if (app.notResponding) {
            //已经弹出ANR,再次ANR直接return
            Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
            return;
        } else if (app.crashing) {
            Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
            return;
        }

        // In case we come through here for the same app before completing
        // this one, mark as anring now so we will bail out.
         //标记ANR,避免多次执行
        app.notResponding = true;

        // Log the ANR to the event log.
        EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
                app.processName, app.info.flags, annotation);

        // Dump thread traces as quickly as we can, starting with "interesting" processes.
        firstPids.add(app.pid);

        int parentPid = app.pid;
        if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
        if (parentPid != app.pid) firstPids.add(parentPid);

        if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);

        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
            ProcessRecord r = mLruProcesses.get(i);
            if (r != null && r.thread != null) {
                int pid = r.pid;
                if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
                    if (r.persistent) {
                        firstPids.add(pid);
                    } else {
                        lastPids.put(pid, Boolean.TRUE);
                    }
                }
            }
        }
    }

    // Log the ANR to the main log.
    StringBuilder info = new StringBuilder();
    info.setLength(0);
    info.append("ANR in ").append(app.processName);
    if (activity != null && activity.shortComponentName != null) {
        info.append(" (").append(activity.shortComponentName).append(")");
    }
    info.append("\
"); info.append("PID: ").append(app.pid).append("\
"); if (annotation != null) { info.append("Reason: ").append(annotation).append("\
"); } if (parent != null && parent != activity) { info.append("Parent: ").append(parent.shortComponentName).append("\
"); } final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST); String cpuInfo = null; if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); synchronized (mProcessCpuTracker) { cpuInfo = mProcessCpuTracker.printCurrentState(anrTime); } info.append(processCpuTracker.printCurrentLoad()); info.append(cpuInfo); } info.append(processCpuTracker.printCurrentState(anrTime)); Slog.e(TAG, info.toString()); if (tracesFile == null) { // There is no trace file, so dump (only) the alleged culprit's threads to the log Process.sendSignal(app.pid, Process.SIGNAL_QUIT); } addErrorToDropBox("anr", app, app.processName, activity, parent, annotation, cpuInfo, tracesFile, null); ... // Unless configured otherwise, swallow ANRs in background processes & kill the process. boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; synchronized (this) { mBatteryStatsService.noteProcessAnr(app.processName, app.uid); if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) { app.kill("bg anr", true); return; } // Set the app's notResponding state, and look up the errorReportReceiver makeAppNotRespondingLocked(app, activity != null ? activity.shortComponentName : null, annotation != null ? "ANR " + annotation : "ANR", info.toString()); // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); HashMap map = new HashMap(); msg.what = SHOW_NOT_RESPONDING_MSG; msg.obj = map; msg.arg1 = aboveSystem ? 1 : 0; map.put("app", app); if (activity != null) { map.put("activity", activity); } mUiHandler.sendMessage(msg); } } final class UiHandler extends Handler { public UiHandler() { super(com.android.server.UiThread.get().getLooper(), null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { ... case SHOW_NOT_RESPONDING_MSG: { synchronized (ActivityManagerService.this) { HashMap data = (HashMap) msg.obj; ProcessRecord proc = (ProcessRecord)data.get("app"); if (proc != null && proc.anrDialog != null) { Slog.e(TAG, "App already has anr dialog: " + proc); return; } Intent intent = new Intent("android.intent.action.ANR"); if (!mProcessesReady) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_FOREGROUND); } broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); if (mShowDialogs) { Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, mContext, proc, (ActivityRecord)data.get("activity"), msg.arg1 != 0); d.show(); proc.anrDialog = d; } else { // Just kill the app if there is no dialog to be shown. killAppAtUsersRequest(proc, null); } } ensureBootCompleted(); } break; } } }
ServiceDoneExecuting()은 수명 주기 메서드를 실행한 후 ServiceDoneExecuting()을 실행하도록 ActivityManagerService에 알립니다(시퀀스 다이어그램에서 이 단계를 그리지 않았고 너무 많습니다) serviceDoneExecuting()은 내부적으로 시간 초과 메시지를 제거하므로 20초(백그라운드 서비스 200초)를 초과하면 , 기본값은 물론 백그라운드 서비스임) 이 알림을 수신하지 않은 경우 시간 초과 메시지가 handleMessage를 입력합니다.
ActivityManagerService.serviceDoneExecuting()→ ActiveServices.serviceDoneExecutingLocked()
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
        boolean finishing) {
    ...
    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) {//app没有正在执行的service
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
            }
            ...
}

좋은 웹페이지 즐겨찾기