Android重學(xué)系列 Service 啟動(dòng)和綁定原理

前言

我們已經(jīng)了解了BroadcastReceiver的原理狮崩,我們?cè)賮?lái)看看四大組件之一的Service是怎么啟動(dòng)的焕盟,以及怎么運(yùn)行的原理缨叫。

如果遇到什么問(wèn)題可以來(lái)到http://www.reibang.com/p/c4927c0b80a9本文下進(jìn)行交流

正文

啟動(dòng)Service的入口就是startService和bindService方法色查。我們先來(lái)看看startService在ContextImpl中做了什么消玄。

startService原理

文件:/frameworks/base/core/java/android/app/ContextImpl.java

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }

    @Override
    public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, true, mUser);
    }

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

此時(shí)調(diào)用的就是AMS的startService方法跟伏。

AMS startService

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
....

        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

mServices是一個(gè)ActiveServices對(duì)象。這個(gè)對(duì)象是在AMS的構(gòu)造函數(shù)中初始化好的翩瓜。

這里調(diào)用了ActiveServices的startServiceLocked酬姆。

ActiveServices startServiceLocked

文件:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {


        final boolean callerFg;
        if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        } else {
            callerFg = true;
        }

        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        ServiceRecord r = res.record;

 ...

        if (unscheduleServiceRestartLocked(r, callingUid, false)) {

        }
        r.lastActivity = SystemClock.uptimeMillis();
        r.startRequested = true;
        r.delayedStop = false;
        r.fgRequired = fgRequired;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid));

        if (fgRequired) {
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
        }

        final ServiceMap smap = getServiceMapLocked(r.userId);
        boolean addToStarting = false;
        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
...
}
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

核心流程有如下三個(gè):

  • 1.retrieveServiceLocked 從ActiveServices中獲取ServiceLookupResult 需要啟動(dòng)Service對(duì)象
  • 2.往ServiceRecord對(duì)象的pendingStarts幾個(gè)中添加一個(gè)ServiceRecord.StartItem對(duì)象。而這個(gè)對(duì)象就是之后Service聲明周期中onCommandStart的回調(diào)參數(shù)
  • 3.startServiceInnerLocked 執(zhí)行Service的啟動(dòng)的流程奥溺。

注意這里addToStarting是一個(gè)比較關(guān)鍵的判斷辞色,addToStarting默認(rèn)為false。

        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                if (r.delayed) {

                    return r.name;
                }
                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {

                    smap.mDelayedStartList.add(r);
                    r.delayed = true;
                    return r.name;
                }

                addToStarting = true;
            } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {

                addToStarting = true;

            } else if (DEBUG_DELAYED_STARTS) {

            }
        } else if (DEBUG_DELAYED_STARTS) {

        }

如果此時(shí)不是啟動(dòng)前臺(tái)服務(wù)浮定,則需要進(jìn)一步進(jìn)行處理相满。如果ProcessRecord為空或者curProcState大于PROCESS_STATE_RECEIVER這個(gè)優(yōu)先級(jí)數(shù)值;也就是優(yōu)先級(jí)更小桦卒。

為了避免此時(shí)App應(yīng)用是沒(méi)有任何的前臺(tái)ui立美,或者App應(yīng)用還沒(méi)有聲明。避免有的App通過(guò)startService進(jìn)行應(yīng)用的包活或者拉起應(yīng)用方灾。就會(huì)進(jìn)行如下能夠存在的最大后臺(tái)服務(wù)數(shù)量建蹄,則放入mDelayedStartList中進(jìn)行延時(shí)啟動(dòng)后臺(tái)服務(wù),現(xiàn)在直接返回了裕偿。

不然則說(shuō)明能夠允許啟動(dòng)后臺(tái)服務(wù)洞慎, 就設(shè)置為addToStarting為true。

ActiveServices retrieveServiceLocked

    private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
            boolean allowInstant) {
        ServiceRecord r = null;


        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);

        ServiceMap smap = getServiceMapLocked(userId);
        final ComponentName comp = service.getComponent();
        if (comp != null) {
            r = smap.mServicesByName.get(comp);

        }
        if (r == null && !isBindExternal) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            r = smap.mServicesByIntent.get(filter);

        }
        if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
                && !callingPackage.equals(r.packageName)) {

            r = null;

        }
        if (r == null) {
            try {
                int flags = ActivityManagerService.STOCK_PM_FLAGS
                        | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
                if (allowInstant) {
                    flags |= PackageManager.MATCH_INSTANT;
                }

                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, flags, userId, callingUid);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                if (sInfo == null) {

                    return null;
                }
                ComponentName name = new ComponentName(
                        sInfo.applicationInfo.packageName, sInfo.name);
                if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
                    if (isBindExternal) {
                        if (!sInfo.exported) {

                        }
                        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {

                        }

                        ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
                                callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);

                        sInfo = new ServiceInfo(sInfo);
                        sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
                        sInfo.applicationInfo.packageName = aInfo.packageName;
                        sInfo.applicationInfo.uid = aInfo.uid;
                        name = new ComponentName(aInfo.packageName, name.getClassName());
                        service.setComponent(name);
                    } else {

                    }
                } else if (isBindExternal) {

                }
                if (userId > 0) {
                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                            sInfo.name, sInfo.flags)
                            && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                        userId = 0;
                        smap = getServiceMapLocked(0);
                    }
                    sInfo = new ServiceInfo(sInfo);
                    sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                }
                r = smap.mServicesByName.get(name);

                if (r == null && createIfNeeded) {
                    final Intent.FilterComparison filter
                            = new Intent.FilterComparison(service.cloneFilter());
                    final ServiceRestarter res = new ServiceRestarter();
                    final BatteryStatsImpl.Uid.Pkg.Serv ss;
                    final BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
                    synchronized (stats) {
                        ss = stats.getServiceStatsLocked(
                                sInfo.applicationInfo.uid, sInfo.packageName,
                                sInfo.name);
                    }
                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                    res.setService(r);
                    smap.mServicesByName.put(name, r);
                    smap.mServicesByIntent.put(filter, r);

                    for (int i=mPendingServices.size()-1; i>=0; i--) {
                        final ServiceRecord pr = mPendingServices.get(i);
                        if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
                                && pr.name.equals(name)) {

                            mPendingServices.remove(i);
                        }
                    }

                }
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            }
        }
        if (r != null) {
...
            return new ServiceLookupResult(r, null);
        }
        return null;
    }
  • 1.通過(guò)UserController.handleIncomingUser獲取的userId嘿棘,從getServiceMapLocked方法通過(guò)userId中獲取ServiceMap對(duì)象劲腿。這個(gè)對(duì)象保存了已經(jīng)啟動(dòng)過(guò)所有的Service對(duì)象。
    • 1.1.ServiceMap保存如下幾種用于查詢映射結(jié)構(gòu):
        final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>();
        final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();

通過(guò)ComponentName也就是包名和類名查找ServiceRecord鸟妙;通過(guò)Intent意圖過(guò)濾找到ServiceRecord焦人』映常·

  • 1.2.如果能夠獲取到,則直接獲取ServiceMap中的ServiceRecord對(duì)象花椭,并包裹成ServiceLookupResult對(duì)象返回忽匈。

  • 2.如果Intent中的ComponentName不為空,ServiceMap則通過(guò)ComponentName查詢緩存ServiceRecord矿辽。

  • 3.如果還是找不到丹允,且isBindExternal為false(此時(shí)就是false),則通過(guò)過(guò)濾條件從ServiceMap查找緩存ServiceRecord嗦锐。

  • 4.如果設(shè)置了FLAG_EXTERNAL_SERVICE嫌松,且ServiceRecord找到了,但是此時(shí)ServiceRecord中的包名和調(diào)用方的包名不一致奕污,則把找到的緩存ServiceRecord設(shè)置為空萎羔。如果設(shè)置了FLAG_EXTERNAL_SERVICE這個(gè)flag,也就是設(shè)置了android:externalService這個(gè)xml標(biāo)簽碳默。這個(gè)標(biāo)簽代表了Service可以綁定調(diào)用方的進(jìn)程贾陷;因此這個(gè)標(biāo)志位支持跨進(jìn)程綁定但是不支持跨包綁定。

  • 5.如果找不到ServiceRecord嘱根,那么需要新建一個(gè)ServiceRecord髓废。

    • 5.1.先通過(guò)PMS的resolveService方法,從PMS中獲取一個(gè)ResolveInfo對(duì)象该抒。這個(gè)對(duì)象能夠獲取安裝時(shí)候通過(guò)解析AndroidManifest.xml到的ServiceInfo對(duì)象慌洪。

    • 5.2.并且isBindExternal為true。此時(shí)會(huì)封裝一個(gè)新的ServiceInfo凑保,并且通過(guò)Intent的setComponent冈爹,獲取此時(shí)真正需要啟動(dòng)Service對(duì)應(yīng)的包名和類名。在這里isBindExternal為false欧引,startService并不會(huì)走這個(gè)邏輯频伤。

    • 5.3.因?yàn)榭赡軙?huì)在5.2的時(shí)候獲取真實(shí)需要啟動(dòng)的包名,此時(shí)再通過(guò)mServicesByName找一次是否能找到緩存的Service芝此。

    • 5.4.到了這個(gè)步驟說(shuō)明真的找不到了ServiceRecord對(duì)象憋肖。先生成Intent.FilterComparison對(duì)象。把ComponentName作為key和ServiceRecord作為value保存到mServicesByName婚苹;把Intent.FilterComparison作為key岸更,ServiceRecord作為value保存到mServicesByIntent。

    • 5.5.如果在mPendingServices隊(duì)列中發(fā)現(xiàn)了這個(gè)需要新生成的Service對(duì)象對(duì)應(yīng)的包名類名租副,就從mPendingServices中移除一樣的包名類名坐慰。

    • 5.6.最后校驗(yàn)權(quán)限返回ServiceLookupResult。

ActiveServices startServiceInnerLocked

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }

        if (r.startRequested && addToStarting) {
            boolean first = smap.mStartingBackground.size() == 0;
            smap.mStartingBackground.add(r);
            r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
...
            if (first) {
                smap.rescheduleDelayedStartsLocked();
            }
        } else if (callerFg || r.fgRequired) {
            smap.ensureNotStartingBackgroundLocked(r);
        }

        return r.name;
    }

核心方法是bringUpServiceLocked用僧。如果bringUpServiceLocked返回了異常结胀,就返回一個(gè)特殊的ComponentName對(duì)象。

addToStarting為true责循,說(shuō)明此時(shí)是一個(gè)能夠啟動(dòng)的后臺(tái)服務(wù)糟港,則ServiceRecord添加到mStartingBackground中。如果mStartingBackground的數(shù)量為0院仿,則直接調(diào)用ServiceMap的rescheduleDelayedStartsLocked啟動(dòng)后臺(tái)服務(wù)秸抚。

ActiveServices bringUpServiceLocked

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {

        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        if (!whileRestarting && mRestartingServices.contains(r)) {
            return null;
        }

        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }

        if (r.delayed) {
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }


        if (!mAm.mUserController.hasStartedUserState(r.userId)) {

            bringDownServiceLocked(r);
            return msg;
        }

        try {
            AppGlobals.getPackageManager().setPackageStoppedState(
                    r.packageName, false, r.userId);
        } catch (RemoteException e) {
        } catch (IllegalArgumentException e) {

        }

        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);

            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                } catch (RemoteException e) {

                }

            }
        } else {

            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }


        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {

                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        if (r.fgRequired) {
            mAm.tempWhitelistUidLocked(r.appInfo.uid,
                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
        }

        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        if (r.delayedStop) {
            r.delayedStop = false;
            if (r.startRequested) {
                stopServiceLocked(r);
            }
        }

        return null;
    }
  • 1.如果ServiceRecord已經(jīng)保存了app遠(yuǎn)程端的Binder對(duì)象,說(shuō)明該Service已經(jīng)啟動(dòng)過(guò)了歹垫,則直接執(zhí)行sendServiceArgsLocked執(zhí)行Service的其他聲明周期剥汤。

  • 2.如果ServiceRecord的delay屬性為true,則從mDelayedStartList移除該ServiceRecord排惨,delay設(shè)置為true吭敢。說(shuō)明此時(shí)開(kāi)始啟動(dòng)服務(wù)了。

  • 3.如果AndroidManifest中的service標(biāo)簽設(shè)置了android:isolatedProcess,說(shuō)明這個(gè)Service需要啟動(dòng)在另一個(gè)隔離的進(jìn)程中執(zhí)行暮芭。我們先只考慮false的情況鹿驼,此時(shí)說(shuō)明是app在app進(jìn)程中啟動(dòng)Service。

    • 3.1.getProcessRecordLocked獲取當(dāng)前App進(jìn)程的ProcessRecord辕宏,如果ProcessRecord不為空畜晰,則說(shuō)明該進(jìn)程已經(jīng)啟動(dòng)了。此時(shí)為ProcessRecord的addPackage后瑞筐,調(diào)用realStartServiceLocked 啟動(dòng)Service凄鼻。
  • 4.如果android:isolatedProcess為true,說(shuō)明每一次啟動(dòng)Service都應(yīng)該是一個(gè)新的隔離進(jìn)程聚假。把ServiceRecord設(shè)置給app块蚌。那么app這個(gè)ProcessRecord對(duì)象就是空,此時(shí)permissionsReviewRequired就是false魔策。每執(zhí)行一次這個(gè)startProcessLocked方法匈子,說(shuō)明android:isolatedProcess標(biāo)志為每一次都是啟動(dòng)app進(jìn)程對(duì)象。

    • 4.1.調(diào)用一次bringDownServiceLocked方法
    • 4.2.mPendingServices如果不包含需要啟動(dòng)的ServiceRecord闯袒,則添加到mPendingService中保存虎敦。
realStartServiceLocked
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }

        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {

            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }

        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            r.delayedStop = false;
            if (r.startRequested) {
                stopServiceLocked(r);
            }
        }
    }
  • 1.啟動(dòng)Service前,先把ServiceRecord添加到ProcessRecord的services集合政敢,說(shuō)明這個(gè)Service正在運(yùn)行了其徙。bumpServiceExecutingLocked埋入Service的ANR消息,更新當(dāng)前App應(yīng)用的adj優(yōu)先級(jí)
  • 2.跨進(jìn)程調(diào)用App端的ApplicationThread的scheduleCreateService方法喷户,創(chuàng)建Service對(duì)象唾那,執(zhí)行onCreate
  • 3.如果創(chuàng)建的過(guò)程中失敗了,說(shuō)明可能App端要么死掉褪尝,要么就是創(chuàng)建過(guò)程發(fā)生了異常闹获,此時(shí)會(huì)調(diào)用serviceDoneExecutingLocked方法期犬,執(zhí)行Service的完成事務(wù)的任務(wù)。
  • 4.如果發(fā)現(xiàn)保存已經(jīng)銷毀的Service對(duì)象集合mDestroyingServices并沒(méi)有這個(gè)Service避诽,就會(huì)再一次的嘗試啟動(dòng)龟虎。
  • 5.requestServiceBindingLocked 執(zhí)行服務(wù)綁定的Connection對(duì)象。注意此時(shí)是startService沙庐,因此不會(huì)有任何掛載的Connection對(duì)象鲤妥。只有bindService才會(huì)執(zhí)行。
  • 6.sendServiceArgsLocked 執(zhí)行Service發(fā)送數(shù)據(jù)
  • 7.移除mDelayedStartList中的ServiceRecord

這幾個(gè)關(guān)鍵的步驟拱雏,讓我們依次的考察棉安,先來(lái)看看scheduleCreateService中做了什么。

bumpServiceExecutingLocked

    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {

        boolean timeoutNeeded = true;
        if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
                && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {

            timeoutNeeded = false;
        }

        long now = SystemClock.uptimeMillis();
        if (r.executeNesting == 0) {
            r.executeFg = fg;
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
            }
            if (r.app != null) {
                r.app.executingServices.add(r);
                r.app.execServicesFg |= fg;
                if (timeoutNeeded && r.app.executingServices.size() == 1) {
                    scheduleServiceTimeoutLocked(r.app);
                }
            }
        } else if (r.app != null && fg && !r.app.execServicesFg) {
            r.app.execServicesFg = true;
            if (timeoutNeeded) {
                scheduleServiceTimeoutLocked(r.app);
            }
        }
        r.executeFg |= fg;
        r.executeNesting++;
        r.executingStart = now;
    }

如果第一次啟動(dòng)就走第一個(gè)if的分支:

  • 1.ProcessRecord的executingServices 正在執(zhí)行任務(wù)的Service集合添加ServiceRecord對(duì)象
  • 2.執(zhí)行scheduleServiceTimeoutLocked ANR超時(shí)埋點(diǎn)铸抑。
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;
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }

能看到和BroadcastReceiver的ANR思路一樣贡耽,通過(guò)一個(gè)延時(shí)的Handler,如果達(dá)到時(shí)間了還沒(méi)有移除這個(gè)Handler消息則報(bào)ANR異常羡滑。

這里根據(jù)啟動(dòng)前臺(tái)和后臺(tái)分為兩種超時(shí)時(shí)間:

  
    // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20*1000;

    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

    // How long the startForegroundService() grace period is to get around to
    // calling startForeground() before we ANR + stop it.
    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;

前臺(tái)分別是10秒菇爪,后臺(tái)服務(wù)不屬于后臺(tái)進(jìn)程組(判斷adj是否在SCHED_GROUP_BACKGROUND)是20秒,后臺(tái)服務(wù)屬于后臺(tái)進(jìn)程組 200秒柒昏。

ApplicationThread scheduleCreateService

        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }

把數(shù)據(jù)封裝成CreateServiceData后凳宙,通過(guò)Handler調(diào)用如下方法:

    private void handleCreateService(CreateServiceData data) {

        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } catch (Exception e) {

        }

        try {
            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();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
        }
    }
  • 1.通過(guò)AppComponentFactory反射創(chuàng)建一個(gè)全新的Service對(duì)象
  • 2.通過(guò)ContextImpl.createAppContext 創(chuàng)建一個(gè)新的Context。
  • 3.獲取LoadedApk中的Application對(duì)象职祷,調(diào)用Service的attach方法綁定Context氏涩。
  • 4.調(diào)用Service的onCreate方法
  • 5.Service以ServiceRecord的token為key緩存到mServices這個(gè)Map對(duì)象中中
  • 5.調(diào)用AMS的serviceDoneExecuting方法。

透三點(diǎn)的核心原理可以看我寫的的Application創(chuàng)建和BroadcastReceiver原理兩篇文章有梆。來(lái)看看Service中都做了什么是尖?

Service attach
    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }

很簡(jiǎn)單就是保存了傳遞過(guò)來(lái)的參數(shù),值得注意的是這個(gè)IBinder對(duì)象其實(shí)就是指ServiceRecord對(duì)象泥耀。

接著執(zhí)行Service.onCreate這個(gè)空實(shí)現(xiàn)的方法饺汹。

AMS serviceDoneExecuting
    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized(this) {
            mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
        }
    }

本質(zhì)上還是調(diào)用了ActiveServices的serviceDoneExecutingLocked方法。

    void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
        boolean inDestroying = mDestroyingServices.contains(r);
        if (r != null) {
            if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
....
            } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
....
                } else if (r.executeNesting != 1) {
....
                }
            }
            final long origId = Binder.clearCallingIdentity();
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            Binder.restoreCallingIdentity(origId);
        } else {
...
        }
    }

type是SERVICE_DONE_EXECUTING_ANON痰催,所不會(huì)做更多的處理兜辞。 最后執(zhí)行了serviceDoneExecutingLocked方法。

ActiveServices serviceDoneExecutingLocked
    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {

        r.executeNesting--;
        if (r.executeNesting <= 0) {
            if (r.app != null) {

                r.app.execServicesFg = false;
                r.app.executingServices.remove(r);
                if (r.app.executingServices.size() == 0) {
                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                } else if (r.executeFg) {

                    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) {

                    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;
            }
        }
    }
  • 1.executeNesting 遞減一之后小于等于0夸溶,說(shuō)明該ServiceRecord只執(zhí)行了一次啟動(dòng)逸吵。接著移除executingServices中的ServiceRecord,說(shuō)明正在執(zhí)行的Service已經(jīng)處理完畢了缝裁。
  • 2.如果executingServices大小為0扫皱,則移除ActivityManagerService.SERVICE_TIMEOUT_MSG這個(gè)Handler消息,也就是拆開(kāi)了ANR的消息
  • 3.如果執(zhí)行的是結(jié)束Service的方法,則從ProcessRecord的services移除ServiceRecord韩脑。

ActiveServices sendServiceArgsLocked

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }

        ArrayList<ServiceStartArgs> args = new ArrayList<>();

        while (r.pendingStarts.size() > 0) {
            ServiceRecord.StartItem si = r.pendingStarts.remove(0);
            if (si.intent == null && N > 1) {
                continue;
            }
            si.deliveredTime = SystemClock.uptimeMillis();
            r.deliveredStarts.add(si);
            si.deliveryCount++;
...
            bumpServiceExecutingLocked(r, execInFg, "start");
            if (!oomAdjusted) {
                oomAdjusted = true;
                mAm.updateOomAdjLocked(r.app, true);
            }
            if (r.fgRequired && !r.fgWaiting) {
                if (!r.isForeground) {
                    scheduleServiceForegroundTransitionTimeoutLocked(r);
                } else {
                    r.fgRequired = false;
                }
            }
            int flags = 0;
            if (si.deliveryCount > 1) {
                flags |= Service.START_FLAG_RETRY;
            }
            if (si.doneExecutingCount > 0) {
                flags |= Service.START_FLAG_REDELIVERY;
            }
            args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
        }

        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            r.app.thread.scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            caughtException = e;
        } catch (RemoteException e) {

            caughtException = e;
        } catch (Exception e) {
            Slog.w(TAG, "Unexpected exception", e);
            caughtException = e;
        }

...
    }
  • 1.遍歷所有保存在ServiceRecord.pendingStarts中的ServiceRecord.StartItem對(duì)象氢妈,把ServiceRecord.StartItem保存到ServiceRecord的deliveredStarts中,說(shuō)明這些數(shù)據(jù)正在分發(fā)扰才。
    • 1.1.調(diào)用bumpServiceExecutingLocked方法繼續(xù)埋下ANR的Handler定時(shí)消息
    • 1.2.更新當(dāng)前進(jìn)程的adj應(yīng)用優(yōu)先級(jí)
    • 1.3.以ServiceRecord.StartItem的Intent,flag,id構(gòu)成用于在App端分發(fā)ServiceStartArgs對(duì)象允懂,并保存到slice這個(gè)ParceledListSlice<ServiceStartArgs>對(duì)象中.
    • 1.4.跨進(jìn)程通信厕怜,調(diào)用ApplicationThread的scheduleServiceArgs方法衩匣。

ActivityThread scheduleServiceArgs

        public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
            List<ServiceStartArgs> list = args.getList();

            for (int i = 0; i < list.size(); i++) {
                ServiceStartArgs ssa = list.get(i);
                ServiceArgsData s = new ServiceArgsData();
                s.token = token;
                s.taskRemoved = ssa.taskRemoved;
                s.startId = ssa.startId;
                s.flags = ssa.flags;
                s.args = ssa.args;

                sendMessage(H.SERVICE_ARGS, s);
            }
        }

這個(gè)方法不斷的循環(huán)遍歷List<ServiceStartArgs>分發(fā)SERVICE_ARGS消息,這個(gè)消息通過(guò)主線程的Looper調(diào)用handleServiceArgs粥航。

handleServiceArgs
    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                if (data.args != null) {
                    data.args.setExtrasClassLoader(s.getClassLoader());
                    data.args.prepareToEnterProcess();
                }
                int res;
                if (!data.taskRemoved) {
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }

                QueuedWork.waitToFinish();

                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                ensureJitEnabled();
            } catch (Exception e) {
...
            }
        }
    }
  • 1.從mServices獲取到已經(jīng)實(shí)例化的Service對(duì)象琅捏,如果ServiceArgsData的taskRemoved為false(都為false,除非是進(jìn)程銷毀時(shí)候才會(huì)出現(xiàn)taskRemoved是true)递雀,則回調(diào)Service的onStartCommand柄延;否則則回調(diào)onTaskRemoved方法
  • 2.QueuedWork調(diào)用waitToFinish方法,阻塞SharePreference把所有的數(shù)據(jù)寫入到磁盤中缀程。
  • 3.serviceDoneExecuting 移除ANR超時(shí)消息

bindService 原理

bindService在開(kāi)發(fā)中用的不是很多搜吧,這里稍微提一下他的使用。
首先申明一個(gè)ServiceConnection對(duì)象杨凑,用于綁定服務(wù)端的Service滤奈。

   private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
 
            MyBinder myBinder = MyBinder.Stub.asInterface(binder);
            service = myBinder.getService();
            int num = service.getRandomNumber();

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBound = false;
        }
    };

            Intent intent = new Intent(this, TestService.class);
            bindService(intent, conn, BIND_AUTO_CREATE);

調(diào)用bindService的方法綁定到某個(gè)Service中。當(dāng)服務(wù)端的service成功回調(diào)onBind方法撩满,我們只需要返回對(duì)應(yīng)的Binder對(duì)象蜒程。就能使用調(diào)用bindService的客戶端在ServiceConnection的onServiceConnected的回調(diào)中獲得Binder對(duì)象。

之后就能通過(guò)這個(gè)Binder調(diào)用本進(jìn)程或者其他進(jìn)程的的方法了伺帘。實(shí)際上我們可以把這個(gè)過(guò)程看成一個(gè)多對(duì)多的服務(wù)-客戶端模型昭躺。多個(gè)客戶端通過(guò)Binder向多服務(wù)端Service通信,每一次我們都可以通過(guò)ComponentName判斷不同服務(wù)返回來(lái)的Binder對(duì)象伪嫁。

bindService的入口 bindServiceCommon

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {

        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • 1.作為參數(shù)的ServiceConnection不能為空领炫。
  • 2.通過(guò)LoadedApk的getServiceDispatcher方法把ServiceConnection轉(zhuǎn)化IServiceConnection對(duì)象。
  • 3.調(diào)用AMS的bindService方法张咳。

LoadedApk getServiceDispatcher

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);

                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

這里面很簡(jiǎn)單帝洪,和BroadcastReceiver的思路很像。動(dòng)態(tài)注冊(cè)的BroadcastReceiver會(huì)封裝成一個(gè)ReceiverDispatcher晶伦,而這里把ServiceConnection封裝成LoadedApk.ServiceDispatcher對(duì)象碟狞。

并且會(huì)把ServiceDispatcher作為value,ServiceConnection作為key緩存一個(gè)map中婚陪。并且以context為key族沃,把這個(gè)臨時(shí)的map作為value緩存起來(lái)。這樣一個(gè)Context就映射有了多個(gè)ServiceDispatcher對(duì)象,也就可以注冊(cè)多個(gè)監(jiān)聽(tīng)被綁定Service狀態(tài)的監(jiān)聽(tīng)者了脆淹。

核心對(duì)象ServiceDispatcher的介紹

    static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;
        private final Context mContext;
        private final Handler mActivityThread;
        private final ServiceConnectionLeaked mLocation;
        private final int mFlags;

        private RuntimeException mUnbindLocation;

        private boolean mForgotten;

        private static class ConnectionInfo {
            IBinder binder;
            IBinder.DeathRecipient deathMonitor;
        }

        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }

            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service, dead);
                }
            }
        }

        private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();

        ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
        }

...
        ServiceConnectionLeaked getLocation() {
            return mLocation;
        }

        ServiceConnection getServiceConnection() {
            return mConnection;
        }

        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

....

        public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                doConnected(name, service, dead);
            }
        }

        public void death(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 1, false));
            } else {
                doDeath(name, service);
            }
        }

        public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            synchronized (this) {
                if (mForgotten) {

                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    return;
                }

                if (service != null) {
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {

                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
                mConnection.onBindingDied(name);
            }

            if (service != null) {
                mConnection.onServiceConnected(name, service);
            } else {

                mConnection.onNullBinding(name);
            }
        }

        public void doDeath(ComponentName name, IBinder service) {
            synchronized (this) {
                ConnectionInfo old = mActiveConnections.get(name);
                if (old == null || old.binder != service) {
                    // Death for someone different than who we last
                    // reported...  just ignore it.
                    return;
                }
                mActiveConnections.remove(name);
                old.binder.unlinkToDeath(old.deathMonitor, 0);
            }

            mConnection.onServiceDisconnected(name);
        }

        private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                mName = name;
                mService = service;
                mCommand = command;
                mDead = dead;
            }

            public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }

        private final class DeathMonitor implements IBinder.DeathRecipient
        {
            DeathMonitor(ComponentName name, IBinder service) {
                mName = name;
                mService = service;
            }

            public void binderDied() {
                death(mName, mService);
            }

            final ComponentName mName;
            final IBinder mService;
        }
    }

這個(gè)類我們可以對(duì)照BroadcastReceiver的原理進(jìn)行對(duì)照學(xué)習(xí)常空。

  • ServiceDispatcher.InnerConnection 這個(gè)InnerConnection對(duì)象是用于監(jiān)聽(tīng)被綁定服務(wù)的狀態(tài),是一個(gè)Binder對(duì)象盖溺,也就說(shuō)可以跨進(jìn)程監(jiān)聽(tīng)被綁定的服務(wù)狀態(tài)漓糙。

一旦ServiceConnection的聲明周期發(fā)生了變化,InnerConnection首先會(huì)得知狀態(tài)的變化烘嘱,從而回調(diào)ServiceDispatcher進(jìn)行處理昆禽。

  • ServiceDispatcher 是整個(gè)Service分發(fā)ServiceConnection事件的核心。注意蝇庭,它持有3個(gè)關(guān)鍵對(duì)象:
    • mIServiceConnection 代表當(dāng)前ServiceDispatcher對(duì)象對(duì)應(yīng)的Binder對(duì)象
    • mActiveConnections 集合醉鳖。每一次當(dāng)一個(gè)新的Service返回了綁定成功的消息后,就會(huì)把這個(gè)Service的類名等信息保存到mActiveConnections中哮内。
    • mConnection 就是bindService注冊(cè)進(jìn)來(lái)的監(jiān)聽(tīng)者盗棵,每當(dāng)被綁定的Service發(fā)生了變化,就會(huì)通過(guò)這個(gè)接口回調(diào)北发。

AMS bindService

   public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
...
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

核心就是調(diào)用了ActiveServices的bindServiceLocked方法纹因。

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {

        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

        ActivityRecord activity = null;
        if (token != null) {
            activity = ActivityRecord.isInStackLocked(token);
            if (activity == null) {
                return 0;
            }
        }

....
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        ServiceRecord s = res.record;

        boolean permissionsReviewRequired = false;

//此時(shí)config_permissionReviewRequired 是false
        if (mAm.mPermissionReviewRequired) {
...
        }

        final long origId = Binder.clearCallingIdentity();

        try {

...

            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);
            if (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }

            if (s.app != null) {
                if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                    s.app.treatLikeActivity = true;
                }
                if (s.whitelistManager) {
                    s.app.whitelistManager = true;
                }
                mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                        || s.app.treatLikeActivity, b.client);
                mAm.updateOomAdjLocked(s.app, true);
            }


            if (s.app != null && b.intent.received) {

                try {
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {

                }

                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
    }
  • 1.ServiceRecord調(diào)用retrieveAppBindingLocked 根據(jù)當(dāng)前的ServiceRecord,Intent 生成一個(gè)IntentBindRecord對(duì)象后,以Intent.FilterComparison為key琳拨,IntentBindRecord為value保存到ServiceRecord的bindings中瞭恰。如果bindings通過(guò)IntentFilter找到對(duì)應(yīng)存在的IntentBindRecord則直接獲取。
    final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
            = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();

    public AppBindRecord retrieveAppBindingLocked(Intent intent,
            ProcessRecord app) {
        Intent.FilterComparison filter = new Intent.FilterComparison(intent);
        IntentBindRecord i = bindings.get(filter);
        if (i == null) {
            i = new IntentBindRecord(this, filter);
            bindings.put(filter, i);
        }
        AppBindRecord a = i.apps.get(app);
        if (a != null) {
            return a;
        }
        a = new AppBindRecord(this, i, app);
        i.apps.put(app, a);
        return a;
    }

在從IntentBindRecord的apps集合中查找AppBindRecord對(duì)象从绘,找到返回寄疏,找不到則生成全新返回。

    final ArrayMap<ProcessRecord, AppBindRecord> apps
            = new ArrayMap<ProcessRecord, AppBindRecord>();

如果能夠從bindings集合僵井,通過(guò)意圖過(guò)濾找到對(duì)應(yīng)的IntentBindRecord陕截,又通過(guò)IntentBindRecord的apps集合,通過(guò)ProcessRecord找到AppBindRecord對(duì)象批什。

而AppBindRecord這個(gè)對(duì)象最終會(huì)保存了所有的IServiceConnection农曲。通過(guò)這樣的關(guān)系就能通過(guò)Intent意圖和ProcessRecord進(jìn)程對(duì)象找到需要發(fā)送綁定監(jiān)聽(tīng)對(duì)象。

  • 2.retrieveServiceLocked 從ServiceMap或者PMS中解析出需要綁定或者啟動(dòng)的ServiceRecord對(duì)象驻债,并包裹成ServiceLookupResult對(duì)象返回乳规。

  • 3.把IServiceConnection通過(guò)ConnectionRecord包裹起來(lái)。并且獲取ServiceRecord中的connections這個(gè)ArrayMap集合合呐。

    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
            = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();

在每一個(gè)ServiceRecord中暮的,以IBinder對(duì)象為key(也就是IServiceConnection),并且保存以ConnectionRecord集合為value淌实。保存一個(gè)Binder對(duì)應(yīng)多個(gè)ServiceDispatcher的情況冻辩。

最后把這個(gè)包裝了IServiceConnection的ConnectionRecord保存到connections的value的list中猖腕。

  • 4.AppBinderRecord的connections集合也保存了ConnectionRecord對(duì)象。

  • 5.如果當(dāng)前調(diào)用bindService的ContextImpl是一個(gè)Activity恨闪,那么就會(huì)在對(duì)應(yīng)的ActivityToken的HashSet<ConnectionRecord>中保存ConnectionRecord倘感。

  • 6.在ProcessRecord創(chuàng)建或者獲取ArraySet<ConnectionRecord>對(duì)象,并把新的ConnectionRecord保存到這個(gè)Set中咙咽。

  • 7.同樣在ActiveServices中有一個(gè)和ServiceRecord相同的connections集合老玛。

  • 8.如果打開(kāi)了Context.BIND_AUTO_CREATE這標(biāo)志位,說(shuō)明此時(shí)bindService執(zhí)行中發(fā)現(xiàn)Service沒(méi)有啟動(dòng)钧敞,則調(diào)用bringUpServiceLocked進(jìn)行啟動(dòng)Service蜡豹。如果bringUpServiceLocked成功的啟動(dòng)了Service,就不繼續(xù)走下面的邏輯犁享,直接返回了余素。

  • 9.下面就是Service默認(rèn)是已經(jīng)創(chuàng)建,Service的進(jìn)程存活炊昆,且IntentBindRecord的receiver為true。則會(huì)調(diào)用ConnectionRecord中的IServiceConnection這個(gè)Binder對(duì)象的跨進(jìn)程方法connected威根,也就是調(diào)用ServiceDispatcher的InnerConnection的connected方法凤巨。

我們來(lái)考察一下之前在bringUpServiceLocked中忽略過(guò)的綁定Service邏輯,也就是在realStartServiceLocked調(diào)用的requestServiceBindingLocked方法洛搀。

requestServiceBindingLocked

    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

能看到實(shí)際上那個(gè)就是獲取ServiceRecord中所有的IntentBindRecord敢茁,調(diào)用requestServiceBindingLocked方法進(jìn)行綁定。

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            return false;
        }

        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
...
            } catch (RemoteException e) {
...
                return false;
            }
        }
        return true;
    }

核心方法就是跨進(jìn)程調(diào)用ApplicationThread的scheduleBindService方法留美。

ActivityThread handleBindService

這個(gè)方法會(huì)通過(guò)ActivityThread主線程handler發(fā)送綁定服務(wù)的消息彰檬,也就是handleBindService

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);

        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
...
            }
        }
    }
  • 1.調(diào)用Service的onBind方法,獲取從Service中返回的允許客戶端操作的Binder對(duì)象谎砾》瓯叮跨進(jìn)程調(diào)用AMS的publishService方法,把需要返回的Binder返回給客戶端景图。
  • 2.如果從BindServiceData中判斷到當(dāng)前的Service需要重新綁定則回調(diào)onRebind方法较雕。調(diào)用serviceDoneExecuting方法告訴AMS已經(jīng)接受了當(dāng)前的執(zhí)行任務(wù)。從而拆下ANR消息挚币。

AMS publishService

    public void publishService(IBinder token, Intent intent, IBinder service) {
...
        synchronized(this) {

            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }
    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {

            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
                                continue;
                            }

                            try {
                                c.conn.connected(r.name, service, false);
                            } catch (Exception e) {

                            }
                        }
                    }
                }

                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
  • 此時(shí)就會(huì)獲得Intent的意圖亮蒋,通過(guò)ServiceRecord的bindings中找到IntentBindRecord,IntentBindRecord設(shè)置receiver為true妆毕。

  • 遍歷ServiceRecord的connections集合中所有的ConnectionRecord慎玖,如果發(fā)現(xiàn)Service的Intent意圖過(guò)濾不匹配則進(jìn)入下一個(gè)loop中;如果符合意圖笛粘,則調(diào)用ConnectionRecord的IServiceConnection的connected方法趁怔。這個(gè)方法就會(huì)跨進(jìn)程調(diào)用的ServiceDisptacher中InnerConnection的connected方法,把從Service的onBind返回的Binder對(duì)象傳遞到InnerConnection中远舅。

  • serviceDoneExecutingLocked 執(zhí)行完成任務(wù)行為,拆除Service的ANR消息痕钢。

InnerConnection 接受connect的行為


            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service, dead);
                }
            }

當(dāng)InnerConnection接受到了connected的調(diào)用图柏,這里就會(huì)調(diào)用ServiceDispatcher的connected,把IBinder傳遞過(guò)來(lái)任连。注意這個(gè)IBinder就是從Service的onBind方法返回的Binder對(duì)象蚤吹。

        public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                doConnected(name, service, dead);
            }
        }

核心就是調(diào)用doConnected,或者調(diào)用RunConnection Runnable對(duì)象執(zhí)行其中的run方法随抠。

RunConnection run
            public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

這里根據(jù)mCommand來(lái)執(zhí)行doConnected進(jìn)行ServiceConnection的綁定回調(diào)還是解綁回調(diào)裁着。

這里是綁定,mCommand也為1拱她。我們直接看doConnected二驰。

ServiceDispatcher doConnected
        public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            synchronized (this) {
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {

                    return;
                }

                if (service != null) {
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
                mConnection.onBindingDied(name);
            }
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            } else {

                mConnection.onNullBinding(name);
            }
        }
  • 1.把傳遞給客戶端的Binder 封裝到ConnectionInfo中。如果通過(guò)ComponentName查找到秉沼,本次發(fā)送給客戶端的Binder和上一次的對(duì)象一致則直接返回桶雀。

  • 2.為當(dāng)前的Binder通過(guò)linkToDeath綁定Binder的死亡監(jiān)聽(tīng)。如果這個(gè)發(fā)送給客戶端操作的Binder對(duì)象死亡了唬复,則會(huì)回調(diào)DeathMonitor矗积,移除mActiveConnections中的對(duì)應(yīng)Service名字的ConnectionInfo。這樣就移除了還在活躍的Binder的緩存對(duì)象敞咧。

  • 3.mActiveConnections 根據(jù)當(dāng)前傳遞過(guò)來(lái)的Service的ComponentName為key棘捣,保存ConnectionInfo。

  • 4.如果上一次的Binder對(duì)象不為空則解綁死亡監(jiān)聽(tīng)休建,先回調(diào)onServiceDisconnected方法乍恐,告訴這個(gè)Binder已經(jīng)解開(kāi)了鏈接。如果此時(shí)Serice還是經(jīng)歷了stop的方法需要銷毀了测砂,還會(huì)執(zhí)行onBindingDied方法茵烈,告訴客戶端,遠(yuǎn)程端已經(jīng)死亡了邑彪。

  • 5.如果是新的不同對(duì)象瞧毙,則會(huì)調(diào)用onServiceConnected分發(fā)Binder對(duì)象,告訴客戶端已經(jīng)綁定了寄症。

Service的銷毀

Service還能通過(guò)stopService結(jié)束當(dāng)前的服務(wù)宙彪。

    private boolean stopServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().stopService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to stop service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

核心就是調(diào)用AMS的stopService方法麦撵。而這個(gè)方法實(shí)際上就是調(diào)用ActiveServices的stopService方法鸿吆。

ActiveServices stopServiceLocked

    private void stopServiceLocked(ServiceRecord service) {
...
        bringDownServiceIfNeededLocked(service, false, false);
    }
    private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
            boolean hasConn) {

...

        bringDownServiceLocked(r);
    }

核心就是bringDownServiceLocked方法。

bringDownServiceLocked
    private final void bringDownServiceLocked(ServiceRecord r) {

        for (int conni=r.connections.size()-1; conni>=0; conni--) {
            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
            for (int i=0; i<c.size(); i++) {
                ConnectionRecord cr = c.get(i);

                cr.serviceDead = true;
                try {
                    cr.conn.connected(r.name, null, true);
                } catch (Exception e) {

                }
            }
        }


        if (r.app != null && r.app.thread != null) {
            for (int i=r.bindings.size()-1; i>=0; i--) {
                IntentBindRecord ibr = r.bindings.valueAt(i);

                if (ibr.hasBound) {
                    try {
                        bumpServiceExecutingLocked(r, false, "bring down unbind");
                        mAm.updateOomAdjLocked(r.app, true);
                        ibr.hasBound = false;
                        ibr.requested = false;
                        r.app.thread.scheduleUnbindService(r,
                                ibr.intent.getIntent());
                    } catch (Exception e) {
                        serviceProcessGoneLocked(r);
                    }
                }
            }
        }


        if (r.fgRequired) {

            r.fgRequired = false;
            r.fgWaiting = false;
            mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
            mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
...
        }


        r.destroyTime = SystemClock.uptimeMillis();


        final ServiceMap smap = getServiceMapLocked(r.userId);
        ServiceRecord found = smap.mServicesByName.remove(r.name);

...
        smap.mServicesByIntent.remove(r.intent);
        r.totalRestartCount = 0;
        unscheduleServiceRestartLocked(r, 0, true);

        for (int i=mPendingServices.size()-1; i>=0; i--) {
            if (mPendingServices.get(i) == r) {
                mPendingServices.remove(i);
            }
        }

...


        if (r.app != null) {
...
            if (r.app.thread != null) {
                updateServiceForegroundLocked(r.app, false);
                try {
                    bumpServiceExecutingLocked(r, false, "destroy");
                    mDestroyingServices.add(r);
                    r.destroying = true;
                    mAm.updateOomAdjLocked(r.app, true);
                    r.app.thread.scheduleStopService(r);
                } catch (Exception e) {

                    serviceProcessGoneLocked(r);
                }
            } else {
              
            }
        } else {

        }

        if (r.bindings.size() > 0) {
            r.bindings.clear();
        }
...
    }

這個(gè)過(guò)程很簡(jiǎn)單望门,可以根據(jù)三個(gè)循環(huán)分為三個(gè)部分:

  • 1.在銷毀之前篮迎,遍歷ServiceRecord中所有的InnerConnection遠(yuǎn)程鏈接男图,并且調(diào)用connected方法示姿,傳遞一個(gè)空的Binder對(duì)象,銷毀存儲(chǔ)在LoadedApk.ServiceDispatcher活躍的綁定監(jiān)聽(tīng)逊笆。

  • 2.遍歷ServiceRecord所有的bindings存儲(chǔ)的綁定的IntentBindRecord栈戳。先調(diào)用bumpServiceExecutingLocked埋下一個(gè)ANR消息。并且跨進(jìn)程調(diào)用對(duì)應(yīng)進(jìn)程的scheduleUnbindService方法难裆,把IntentBindRecord中存儲(chǔ)的啟動(dòng)的意圖傳遞過(guò)去子檀。

  • 3.如果是前臺(tái)的服務(wù)還會(huì)移除SERVICE_FOREGROUND_TIMEOUT_MSG,前臺(tái)服務(wù)執(zhí)行任務(wù)超時(shí)ANR乃戈。

  • 4.如果進(jìn)程還存活褂痰,則bumpServiceExecutingLocked埋下銷毀Service的ANR。更新進(jìn)程的adj優(yōu)先級(jí)后症虑,跨進(jìn)程調(diào)用scheduleStopService方法缩歪。

我們來(lái)看看在ApplicationThread中的scheduleUnbindService和scheduleStopService。

ActivityThread handleUnbindService

scheduleUnbindService最后會(huì)調(diào)用scheduleUnbindService方法谍憔。


    private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                boolean doRebind = s.onUnbind(data.intent);
                try {
                    if (doRebind) {
                        ActivityManager.getService().unbindFinished(
                                data.token, data.intent, doRebind);
                    } else {
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {

            }
        }
    }

從mServices緩存中獲取Service對(duì)象匪蝙,并執(zhí)行onUnbind方法回調(diào)。如果onUnbind返回true說(shuō)明需要重新綁定韵卤,則調(diào)用unbindFinished方法骗污;否則則調(diào)用serviceDoneExecuting完成當(dāng)前任務(wù)的執(zhí)行。

ActivityThread handleStopService

    private void handleStopService(IBinder token) {
        Service s = mServices.remove(token);
        if (s != null) {
            try {

                s.onDestroy();
                s.detachAndCleanUp();
                Context context = s.getBaseContext();
                if (context instanceof ContextImpl) {
                    final String who = s.getClassName();
                    ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
                }

                QueuedWork.waitToFinish();

                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
                } catch (RemoteException e) {
                }
            } catch (Exception e) {

            }
        } else {
        }
    }
  • 1.調(diào)用Service的onDestroy方法
  • 2.Service的detachAndCleanUp 銷毀保存在Service中的ServiceRecord這個(gè)Binder對(duì)象
  • 3.QueuedWork 等待SP的寫入消息的落盤
  • 4.serviceDoneExecuting 通知ActiveServices的移除銷毀ANR的Handler消息

總結(jié)

Service的啟動(dòng)原理實(shí)際上很簡(jiǎn)單沈条,我這邊分為startService和bindService兩個(gè)方法將進(jìn)行總結(jié)。

startService實(shí)際上和bindService執(zhí)行流程十分相似诅炉。只是bindService多執(zhí)行了幾個(gè)步驟蜡歹,直接上bindService和stopService的時(shí)序圖:


Service.png

bindService 與 startService

bindService綁定服務(wù),如果在bindService方法就是BIND_AUTO_CREATE的標(biāo)志位涕烧,就會(huì)包含了startService的邏輯月而。這里就用BIND_AUTO_CREATE的邏輯來(lái)統(tǒng)一說(shuō)說(shuō)整個(gè)流程都做了什么。

  • 1.在bindService進(jìn)入AMS之前议纯,就會(huì)調(diào)用LoadedApk.getServiceDispatcher獲取一個(gè)ServiceDispatcher對(duì)象父款。

    • 1.1.而ServiceDispatcher這個(gè)對(duì)象包含了一個(gè)InnerConnection Binder對(duì)象。這個(gè)對(duì)象是用于直接溝通AMS的那邊的回調(diào)瞻凤,直接回調(diào)到ServiceConnection中憨攒。
    • 1.2.ServiceDispatcher中本身就有mServices緩存,它緩存了已經(jīng)啟動(dòng)過(guò)的ServiceDispatcher阀参。是以當(dāng)前ContextImpl為value肝集,以ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>為value的Map。這樣就會(huì)在同一個(gè)上下文中創(chuàng)建相同的服務(wù)分發(fā)者蛛壳。
  • 2.進(jìn)入AMS后杏瞻,首先會(huì)通過(guò)retrieveServiceLocked從AMS中查找兩個(gè)級(jí)別的緩存所刀,一個(gè)是緩存在AMS中的緩存,一個(gè)是緩存在PMS的緩存捞挥。

    • 2.1.AMS的緩存的緩存中又分為兩個(gè)緩存浮创。一個(gè)是通過(guò)類名+包名查找ServiceRecord;一個(gè)是通過(guò)意圖過(guò)濾器查找Service砌函。
    • 2.2.PMS中則是通過(guò)解析apk的AndroidManifest.xml的xml標(biāo)簽獲得的斩披。
  • 3.如果發(fā)現(xiàn)ServiceRecord已經(jīng)綁定了ProcessRecord說(shuō)明已經(jīng)啟動(dòng)過(guò)了,則調(diào)用scheduleServiceArgs胸嘴,觸發(fā)Service的onStartCommand返回雏掠。

  • 4.如果發(fā)現(xiàn)沒(méi)有綁定過(guò)則說(shuō)明需要啟動(dòng)過(guò),則scheduleCreateService劣像,調(diào)用ActivityThread的handleCreateService乡话,依次執(zhí)行Service的attach方法綁定ServiceRecord以及onCreate方法,并把新的Service緩存起來(lái)耳奕。

  • 5.在AMS的bindServiceLocked中绑青,會(huì)把IServiceConnection綁定到ServiceRecord的ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings集合中。注意在IntentBindRecord集合中就保存了一個(gè)特殊的集合ArrayMap<ProcessRecord, AppBindRecord>屋群,而AppBindRecord實(shí)際上就是持有了核心的ConnectionRecord集合闸婴。而ConnectionRecord就是正在的持有IServiceConnection。

弄的這么復(fù)雜芍躏,Google官方實(shí)際上指向做一件事:可以通過(guò)意圖確定當(dāng)前緩存的IServiceConnection 所指向的客戶端進(jìn)程邪乍,客戶端的監(jiān)聽(tīng)Service綁定接口對(duì)象。

  • 6.requestServiceBindingsLocked方法會(huì)遍歷所有綁定在ServiceRecord的binding集合对竣,并且調(diào)用每一個(gè)ServiceRecord對(duì)應(yīng)的Service的onBind的方法庇楞。

  • 7.onBind返回 Service服務(wù)端允許客戶端操作的Binder對(duì)象,則調(diào)用AMS的publishService否纬。在AMS中則會(huì)查找ServiceRecord的bindings集合吕晌,遍歷每一個(gè)IServiceConnection.connected 嘗試回調(diào)在bindService方法中綁定的ServiceConnection接口。

  • 8.IServiceConnection Binder對(duì)象在客戶端實(shí)際上對(duì)應(yīng)就是ServiceDispatcher中的InnerConnection對(duì)象临燃。這個(gè)對(duì)象在connected方法會(huì)調(diào)用RunConnection的run方法睛驳,他會(huì)調(diào)用ActivityThread的Handler中執(zhí)行doConnected把服務(wù)端分發(fā)過(guò)來(lái)Binder緩存到mActiveConnections,最后回調(diào)ServiceConnection.onServiceConnected

  • 9.當(dāng)啟動(dòng)和綁定都完成后膜廊,就會(huì)調(diào)用sendServiceArgsLocked方法乏沸。這個(gè)方法就是調(diào)用ActivityThread. scheduleServiceArgs方法。而這個(gè)方法最終調(diào)用Service的onStartCommand方法溃论。注意這里分發(fā)的Intent就是之前啟動(dòng)service的Intent屎蜓。當(dāng)然onStartCommand會(huì)根據(jù)返回值在serviceDoneExecuting方法中決定了當(dāng)Service執(zhí)行完onStartCommand是否需要重啟:

  • START_STICKY 如果Service調(diào)用了onStartCommand之后被銷毀,會(huì)重新啟動(dòng)钥勋,如果中間沒(méi)任何命令傳遞給Service炬转,此時(shí)Intent為null辆苔。

  • START_NOT_STICKY 如果Service調(diào)用了onStartCommand之后被銷毀,不會(huì)重啟扼劈。

  • START_REDELIVER_INTENT 如果Service調(diào)用了onStartCommand之后被銷毀驻啤,會(huì)重新啟動(dòng),如果中間沒(méi)任何命令傳遞給Service荐吵,此時(shí)Intent為初始數(shù)骑冗。

  • START_STICKY_COMPATIBILITY 兼容模式,不保證onStartCommand之后銷毀會(huì)重啟先煎。

在這個(gè)過(guò)程中又幾個(gè)比較重要的緩存對(duì)象:

Service緩存圖解.png

Service銷毀

bringDownServiceLocked做了三件事情:

  • 1.調(diào)用所有ServiceConnection的回調(diào)贼涩,回調(diào)onServiceDisconnected方法,并從活躍的Binder集合中移除
  • 2.回調(diào)Service的onUnBind方法
  • 3.回調(diào)Service的onDestroy方法和detachAndCleanUp銷毀ServiceRecord

Service 的ANR與注意

Service的ANR實(shí)際上是由bumpServiceExecutingLocked方法埋下的一個(gè)超時(shí)的ANR薯蝎,超時(shí)時(shí)間根據(jù)是啟動(dòng)后臺(tái)服務(wù)還是前臺(tái)服務(wù):

  • 前臺(tái)服務(wù)是10秒
  • 后臺(tái)服務(wù) 不過(guò)進(jìn)程不是在ProcessList.SCHED_GROUP_BACKGROUND進(jìn)程組中是 20秒
  • 后臺(tái)服務(wù) 不過(guò)進(jìn)程在ProcessList.SCHED_GROUP_BACKGROUND進(jìn)程組中是 200秒

當(dāng)每一個(gè)Service執(zhí)行完一個(gè)任務(wù)之后遥倦,都會(huì)執(zhí)行serviceDoneExecutingLocked方法,把ActiveServices中的Handler的ANR倒計(jì)時(shí)消息移除占锯。

有一點(diǎn)比較有意思的一點(diǎn)袒哥,啟動(dòng)服務(wù)有一個(gè)常見(jiàn)的問(wèn)題,當(dāng)通過(guò)startService啟動(dòng)Service的時(shí)候消略,會(huì)爆出錯(cuò)誤堡称。

  Not allowed to start service Intent{xxxx}

禁止打開(kāi)后臺(tái)服務(wù)。在上面也有體現(xiàn):如果startService返回的包名不是正常的包名而是一個(gè)?則會(huì)爆出這種錯(cuò)誤艺演。

        if (forcedStandby || (!r.startRequested && !fgRequired)) {
            // Before going further -- if this app is not allowed to start services in the
            // background, then at this point we aren't going to let it period.
            final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
...

                UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
                return new ComponentName("?", "app is in background uid " + uidRec);
            }
        }

能看到如果此時(shí)fgRequired為false也就是非前臺(tái)服務(wù)却紧,會(huì)走入getAppStartModeLocked的校驗(yàn)。

  int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
            int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
        UidRecord uidRec = mActiveUids.get(uid);

        if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
            boolean ephemeral;
            ...
             
                final int startMode = (alwaysRestrict)
                        ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
                        : appServicesRestrictedInBackgroundLocked(uid, packageName,
                                packageTargetSdk);
               ...
                return startMode;
             
        }
        return ActivityManager.APP_START_MODE_NORMAL;
    }

mActiveUids收集的是啟動(dòng)的活躍應(yīng)用進(jìn)程uid胎撤。

  • uidRec為空啄寡,必定是沒(méi)有啟動(dòng)或者是后臺(tái)進(jìn)程
  • uidRec.idle為true,說(shuō)明此時(shí)是啟動(dòng)過(guò)了但是呆在了后臺(tái)超過(guò)60秒哩照,從前臺(tái)變化為后臺(tái)進(jìn)程。

這兩個(gè)情況都會(huì)appServicesRestrictedInBackgroundLocked進(jìn)行校驗(yàn):

    int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {

        if (packageTargetSdk >= Build.VERSION_CODES.O) {
            return ActivityManager.APP_START_MODE_DELAYED_RIGID;
        }
        int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
                uid, packageName);

        switch (appop) {
            case AppOpsManager.MODE_ALLOWED:
                // If force-background-check is enabled, restrict all apps that aren't whitelisted.
                if (mForceBackgroundCheck &&
                        !UserHandle.isCore(uid) &&
                        !isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
                    return ActivityManager.APP_START_MODE_DELAYED;
                }
           ...
    }

校驗(yàn)出了不在白名單中懒浮,就會(huì)返回APP_START_MODE_DELAYED飘弧。此時(shí)不是APP_START_MODE_NORMAL就會(huì)返回帶了?的包名從而報(bào)錯(cuò)。

一般的砚著,我們還會(huì)作如下處理從startService改成startForegroundService次伶。但是這樣就又爆出了全新的錯(cuò)誤。

Context.startForegroundService() did not then call Service.startForeground()

android.app.ActivityThread$H.handleMessage(ActivityThread.java:2204)

寫高版本的service 稍不注意都會(huì)遇到這種情況稽穆。這是因?yàn)槟銢](méi)有在Service中使用startForeground方法冠王。如果我們超過(guò)10秒沒(méi)有一般我們都會(huì)使用startForeground啟動(dòng)一個(gè)通知,告訴用戶正在前臺(tái)運(yùn)行舌镶。

而startForeground實(shí)際上是移除超時(shí)ANR的行為柱彻。

但是有時(shí)候豪娜,就算startForeground還是會(huì)報(bào)錯(cuò),即使把時(shí)機(jī)盡可能的提前了哟楷,放在了onCreate中瘤载,還是會(huì)報(bào)錯(cuò)了。

我們能夠看到實(shí)際上這個(gè)過(guò)程中每當(dāng)執(zhí)行完Service的onStartCommand卖擅,就會(huì)等待SP寫入到磁盤的阻塞鸣奔,也有可能是這個(gè)時(shí)候的寫入時(shí)間過(guò)長(zhǎng)了導(dǎo)致的ANR,詳情可看SharedPreferences源碼解析

另一種可能就是因?yàn)檎麄€(gè)流程都是在主線程中執(zhí)行的惩阶,看看主線程有沒(méi)有其他太過(guò)耗時(shí)的行為挎狸,導(dǎo)致來(lái)不及移除前臺(tái)服務(wù)的ANR消息。

后記

到這里Service已經(jīng)全部解析了断楷,接下來(lái)我們來(lái)看看四大組件最后一個(gè)ContentProvider锨匆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市脐嫂,隨后出現(xiàn)的幾起案子统刮,更是在濱河造成了極大的恐慌,老刑警劉巖账千,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥蒙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡匀奏,警方通過(guò)查閱死者的電腦和手機(jī)鞭衩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)娃善,“玉大人论衍,你說(shuō)我怎么就攤上這事【刍牵” “怎么了坯台?”我有些...
    開(kāi)封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瘫寝。 經(jīng)常有香客問(wèn)我蜒蕾,道長(zhǎng),這世上最難降的妖魔是什么焕阿? 我笑而不...
    開(kāi)封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任咪啡,我火速辦了婚禮,結(jié)果婚禮上暮屡,老公的妹妹穿的比我還像新娘撤摸。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布准夷。 她就那樣靜靜地躺著钥飞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冕象。 梳的紋絲不亂的頭發(fā)上代承,一...
    開(kāi)封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音渐扮,去河邊找鬼论悴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛墓律,可吹牛的內(nèi)容都是我干的膀估。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼耻讽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼察纯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起针肥,我...
    開(kāi)封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饼记,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后慰枕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體具则,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年具帮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了博肋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蜂厅,死狀恐怖匪凡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掘猿,我是刑警寧澤病游,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站稠通,受9級(jí)特大地震影響礁遵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜采记,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望政勃。 院中可真熱鬧唧龄,春花似錦、人聲如沸奸远。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至丸冕,卻和暖如春耽梅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胖烛。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工眼姐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佩番。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓众旗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親趟畏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贡歧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345