Service(二)ANR

Service生命周期时序图
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<Integer> firstPids = new ArrayList<Integer>(5);
    SparseArray<Boolean> lastPids = new SparseArray<Boolean>(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("\\n");
    info.append("PID: ").append(app.pid).append("\\n");
    if (annotation != null) {
        info.append("Reason: ").append(annotation).append("\\n");
    }
    if (parent != null && parent != activity) {
        info.append("Parent: ").append(parent.shortComponentName).append("\\n");
    }

    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<String, Object> map = new HashMap<String, Object>();
        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<String, Object> data = (HashMap<String, Object>) 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;
        }
    }
}

Service在执行完生命周期方法后都会通知ActivityManagerService执行serviceDoneExecuting()(这一步我并没有在时序图里画出来,实在太多了)
serviceDoneExecuting()内部会移除超时msg,所以如果超过20s(后台服务200s,默认当然是后台服务)还没收到这个通知,那么超时msg就进入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);
            }
            ...
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 发起进程端: 1、ComponentName startService(Intent service)(Conte...
    野望Echo阅读 360评论 0 0
  • 哎呀呀 ,马上就要面临找工作了,媛媛心里紧张呀. 作为一个即将毕业的Android程序媛,开始面临找工作了,...
    仇诺伊阅读 4,534评论 7 59
  • 第一章:Activity生命周期和启动模式 Activity关闭时会调用onPause()和onStop(),如果...
    loneyzhou阅读 873评论 0 2
  • 今天晨读分享的是韬盛和夫的工作观,能力观,人才观。 01 虽然没看过他的书,但从这三观能看出他是一个实干家。 他的...
    houpanpan926阅读 419评论 5 4
  • 1.今天学堂组织放生,一大早6点多起床心里有个坚定的信念一定要赶在大家出发前到达,因为自己今年一直想去放生一次,没...
    Ai马爷阅读 139评论 0 0