Android中Service的啟動(dòng)與綁定過(guò)程詳解(基于api29)

歡迎讀者閱讀我的個(gè)人博客點(diǎn)擊前往我的個(gè)人博客
更精美的UI喧笔,擁有更舒適的閱讀體驗(yàn)饺著。
本文章個(gè)人博客鏈接Android中Service的啟動(dòng)與綁定過(guò)程詳解(基于api29)

前言

前面我寫(xiě)到一個(gè)文章是關(guān)于Activity啟動(dòng)流程的點(diǎn)擊鏈接前往畔乙。這一篇的內(nèi)容是關(guān)于Service的啟動(dòng)和綁定的流程詳解较屿。Service和Activity一樣丐一,都是受AMS和ActivityThread的管理登下,所以在啟動(dòng)流程上兩者有一些相似茫孔。不同的是Service有綁定的流程,相對(duì)比較復(fù)雜一點(diǎn)被芳,結(jié)合Service的生命周期來(lái)理解缰贝,也不是很復(fù)雜。

了解啟動(dòng)源碼的好處是整個(gè)Service對(duì)于你來(lái)說(shuō)已經(jīng)是透明的了畔濒,我們所做的每一個(gè)操作剩晴,心里都很清楚他的背后發(fā)生了什么。這是一種自信,也是一種能力赞弥,一種區(qū)別于入門(mén)與高級(jí)工程師的能力毅整。

文章涉及到很多的源碼,我以“思路先行绽左,代碼后講”的思維來(lái)講解這一過(guò)程悼嫉。先對(duì)總體有個(gè)感知,再對(duì)具體代碼進(jìn)行研究會(huì)有更深刻的理解拼窥。希望可以認(rèn)真看完每一處的代碼戏蔑。我更加建議把一邊看文章一邊自己查看源碼,這樣可以加深理解鲁纠。文章涉及到跨進(jìn)程通信辛臊,如果對(duì)此還沒(méi)有學(xué)習(xí)的話(huà),可能看起來(lái)一些步驟比較難以理解房交,建議先學(xué)一下跨進(jìn)程通信AIDL彻舰。

代碼中我加了非常多的注釋來(lái)幫助大家理解每個(gè)重點(diǎn)的內(nèi)容,請(qǐng)一定要看代碼內(nèi)容候味。代碼外的講解僅僅只是總體流程的概述刃唤。

理解源碼需要對(duì)Service的生命周期有一個(gè)完整的認(rèn)識(shí),可以幫助理解源碼中的內(nèi)容白群。在下面的解析中我也會(huì)穿插生命周期的一些補(bǔ)充尚胞,希望可以幫助大家理解。

本文內(nèi)容大綱

image

總體工作流程思路概述

這一部分主要為大家有個(gè)整體的流程感知帜慢,不會(huì)在源碼中丟失自己笼裳。分為兩個(gè)部分:?jiǎn)?dòng)流程與綁定流程。

直接啟動(dòng)流程概述

概述

直接啟動(dòng)粱玲,也就是我們?cè)贏ctivity中調(diào)用startService來(lái)啟動(dòng)一個(gè)Service的方式躬柬。

圖解

image

簡(jiǎn)析

啟動(dòng)的步驟:

  1. Activity向AMS,即ActivityManagerService請(qǐng)求啟動(dòng)Service抽减。
  2. AMS判斷Service所在的進(jìn)程是否已經(jīng)創(chuàng)建允青,注意Service和Activity是可以同個(gè)進(jìn)程的。
  3. 如果還沒(méi)創(chuàng)建則通過(guò)Zygote進(jìn)程fork一個(gè)進(jìn)程卵沉。
  4. AMS請(qǐng)求Service所在進(jìn)程的ActivityThread創(chuàng)建Service和啟動(dòng)颠锉,并回調(diào)Service的onCreate方法。
  5. Service創(chuàng)建完成之后史汗,AMS再次請(qǐng)求ActivityThread進(jìn)行相關(guān)操作并回調(diào)onStartCommand方法琼掠。

過(guò)程中onCreate和onStartCommand是在兩次跨進(jìn)程通信中完成的,需要注意一下停撞〈赏埽總共最多涉及到四個(gè)進(jìn)程。

綁定流程概述

概述

綁定服務(wù)即我們?cè)贏ctivity中調(diào)用bindService來(lái)綁定服務(wù)。綁定的過(guò)程相對(duì)直接啟動(dòng)來(lái)說(shuō)比較復(fù)雜一點(diǎn)速挑,因?yàn)樯婕暗揭恍┥芷诎担枰M(jìn)行一些條件判斷。

圖解

圖有點(diǎn)復(fù)雜姥宝,配合下面的解析一起看


image

簡(jiǎn)析

介紹一下步驟:

  1. Activity請(qǐng)求AMS綁定Service翅萤。
  2. AMS判斷Service是否已經(jīng)啟動(dòng)了。如果還沒(méi)啟動(dòng)會(huì)先去啟動(dòng)Service腊满。
  3. AMS調(diào)用Service的onBind方法獲取Service的IBinder對(duì)象套么。
  4. Service把自己的IBinder對(duì)象發(fā)布到AMS中保存,這樣下次綁定就不需要再調(diào)用onBind了碳蛋。
  5. 把拿到的IBinder對(duì)象返回給Activity胚泌。
  6. Activity可以直接通過(guò)這個(gè)IBinder對(duì)象訪(fǎng)問(wèn)Service。

這里是主體的流程肃弟。綁定的過(guò)程涉及到很多情況的判斷玷室,如:進(jìn)程是否創(chuàng)建,是否已經(jīng)綁定過(guò)笤受,是否已經(jīng)調(diào)用了onUnBind方法等穷缤。后面的源碼講解會(huì)講到。這里我只放整體的流程箩兽。

源碼講解

這一部分內(nèi)容枯燥津肛,但我把源碼盡量提取相關(guān)的代碼,其他的用省略號(hào)進(jìn)行省略汗贫,減少無(wú)用的代碼干擾身坐。源碼中的重點(diǎn)我用了很多的注釋解析,一定要看注釋落包,是非常重要的一部分部蛇。

直接啟動(dòng)流程源碼講解

一、Activity訪(fǎng)問(wèn)AMS的過(guò)程

圖解
image
源碼解析
  1. 我們?cè)贏ctivity中調(diào)用startService方法妥色,其實(shí)是調(diào)用ContentWrapper的startService搪花,因?yàn)锳ctivity是繼承自ContextWrapper的遏片。startService是Context的抽象方法嘹害,ContentWrapper繼承自Content,但是他運(yùn)行了裝飾者模式吮便,本身沒(méi)有真正實(shí)現(xiàn)Context笔呀,他的內(nèi)部有一個(gè)真正的實(shí)例mBase,他是ContextImpl的實(shí)例髓需,所以最終的真正實(shí)現(xiàn)是在ContextImpl中许师。

    /frameworks/base/core/java/android/content/ContextWrapper.java
    
    // 這里的mBase是startService的真正實(shí)現(xiàn)。他是從哪里來(lái)的?從activit的創(chuàng)建開(kāi)始看
    Context mBase;
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
    

    想要知道什么時(shí)候得到Context微渠,要回到ActivityThread創(chuàng)建Activity的時(shí)候創(chuàng)建的Context搭幻。最終可以看到就是ContextImpl這個(gè)類(lèi)是具體的實(shí)現(xiàn)。

    /frameworks/base/core/java/android/app/ActivityThread.java
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 在這里創(chuàng)建了Content逞盆,可以看到他的類(lèi)型是ContentImpl
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    ...
    // 在這里把a(bǔ)ppContext給到了activity檀蹋。說(shuō)明這個(gè)就是Activity里面的Context的具體實(shí)現(xiàn)
    appContext.setOuterContext(activity);
    activity.attach(appContext, this, getInstrumentation(), r.token,
          r.ident, app, r.intent, r.activityInfo, title, r.parent,
          r.embeddedID, r.lastNonConfigurationInstances, config,
          r.referrer, r.voiceInteractor, window, r.configCallback,
          r.assistToken);
    ...
    }
    
  1. ContextImpl的處理邏輯是直接調(diào)用AMS在本地的代理對(duì)象IActivityManagerService來(lái)請(qǐng)求AMS。

    /frameworks/base/core/java/android/app/ContextImpl.java;
    
    // 直接跳轉(zhuǎn)下個(gè)方法
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
        // 如果了解過(guò)activity啟動(dòng)流程看到這個(gè)ActivityManager.getService()應(yīng)該很熟悉
        // 這里直接調(diào)用AMS在本地的IBinder接口云芦,進(jìn)行跨進(jìn)程通信俯逾。不了解的可以去看一下我的
        // 關(guān)于解析activity啟動(dòng)流程的文章。鏈接在上頭舅逸。
        ComponentName cn = ActivityManager.getService().startService(
        mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                    getContentResolver()), requireForeground,
                    getOpPackageName(), user.getIdentifier());
        
    }
    

    這里再次簡(jiǎn)單介紹一下這個(gè)IActivityManager桌肴。這一步是通過(guò)AIDL技術(shù)進(jìn)行跨進(jìn)行通信。拿到AMS的代理對(duì)象琉历,把啟動(dòng)任務(wù)交給了AMS坠七。

    /frameworks/base/core/java/android/app/ActivityManager.java/;
    //單例類(lèi)
    public static IActivityManager getService() {
       return IActivityManagerSingleton.get();
    }
    
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    
    protected IActivityManager create() {
    //得到AMS的IBinder接口
    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
    //轉(zhuǎn)化成IActivityManager對(duì)象。遠(yuǎn)程服務(wù)實(shí)現(xiàn)了這個(gè)接口旗笔,所以可以直接調(diào)用這個(gè)
    //AMS代理對(duì)象的接口方法來(lái)請(qǐng)求AMS灼捂。這里采用的技術(shù)是AIDL
    final IActivityManager am = IActivityManager.Stub.asInterface(b);
    return am;
    }
    };
    

二、AMS處理服務(wù)啟動(dòng)請(qǐng)求的過(guò)程

圖解
image
源碼解析
  1. AMS調(diào)用ActivityServices進(jìn)行處理换团。有點(diǎn)類(lèi)似activity啟動(dòng)中的調(diào)用ActivityStarter進(jìn)行啟動(dòng)悉稠。把業(yè)務(wù)分給他的小弟。

    /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java;
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        final ActiveServices mServices;
        ...
        // 這里的mServices是ActivityServices艘包,跳轉(zhuǎn)->
        res = mServices.startServiceLocked(caller, service,
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, userId);
        ...
    }
    
  1. ActivityServices類(lèi)是整個(gè)服務(wù)創(chuàng)建過(guò)程的主要邏輯類(lèi)的猛。基本上AMS接收到請(qǐng)求后就把事務(wù)直接交給ActivityServices來(lái)處理了想虎,所以整個(gè)流程都在這里進(jìn)行卦尊。ActivityServices主要是獲取Service的信息ServiceRecord,然后判斷各種信息如權(quán)限舌厨,進(jìn)程是否創(chuàng)建等岂却。然后再創(chuàng)建一個(gè)StartItem,這個(gè)StartItem是后續(xù)執(zhí)行onStartCommand的事務(wù)裙椭。這里要注意一下他躏哩。

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    // 方法中涉及到mAm就是AMS
    final ActivityManagerService mAm;
    
    // 直接跳下個(gè)方法
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        // 跳轉(zhuǎn)下個(gè)方法
        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
                callingPackage, userId, false);
    }
    
    // 這一步主要是獲取ServiceRecord。也就是服務(wù)的各種信息揉燃,來(lái)檢查服務(wù)的各個(gè)資源是否已經(jīng)完備
    // 同時(shí)會(huì)新建一個(gè)StartItem扫尺,這個(gè)Item是后面負(fù)責(zé)回調(diào)Service的onStartCommand事務(wù)
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            final int userId, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
        ...
        // 這里會(huì)去查找ServiceRecord,和ActivityRecord差不多炊汤,描述Service的信息正驻。
        // 如果沒(méi)有找到則會(huì)調(diào)用PackageManagerService去獲取service信息
        // 并封裝到ServiceLookResult中返回
        ServiceLookupResult res =
        retrieveServiceLocked(service, null, 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");
        }
     // 這里從ServiceLookResult中得到Record信息
        ServiceRecord r = res.record;    
        
        // 這里新建一個(gè)StartItem弊攘,注意他的第二個(gè)參數(shù)是false,這個(gè)參數(shù)名是taskRemove
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    service, neededGrants, callingUid));
        ...
        // 繼續(xù)跳轉(zhuǎn)
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }
    
  1. 這一步主要是檢查Service所在進(jìn)程是否已經(jīng)啟動(dòng)姑曙。如果沒(méi)有則先啟動(dòng)進(jìn)程襟交。

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ...
        // 繼續(xù)跳轉(zhuǎn)
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
        ...
    }
    
    // 此方法主要判斷服務(wù)所在的進(jìn)程是否已經(jīng)啟動(dòng),如果還沒(méi)啟動(dòng)那么就去創(chuàng)建進(jìn)程再啟動(dòng)服務(wù)伤靠;
    // 第一次綁定或者直接啟動(dòng)都會(huì)調(diào)用此方法
    // 進(jìn)程啟動(dòng)完了就調(diào)用realStartServiceLocked下一步
    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        ...
        // 這里獲取進(jìn)程名字婿着。在啟動(dòng)的時(shí)候可以指定進(jìn)程,默認(rèn)是當(dāng)前進(jìn)程
        final String procName = r.processName;
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);    
        ProcessRecord app;
        if (!isolated) {
            // 根據(jù)進(jìn)程名字獲取ProcessRecord
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            ...
            // 這里判斷進(jìn)程是否為空醋界。如果進(jìn)程已經(jīng)啟動(dòng)那就直接轉(zhuǎn)注釋1竟宋;否則轉(zhuǎn)注釋2
            // 創(chuàng)建進(jìn)程的流程這里不講,所以后面的邏輯直接進(jìn)入啟動(dòng)service
            if (app != null && app.thread != null) {
               ...
                // 1
                // 啟動(dòng)服務(wù)
                realStartServiceLocked(r, app, execInFg);
                return null;
            }
            ...
        }
        // 如果進(jìn)程為空形纺,那么執(zhí)行注釋2進(jìn)行創(chuàng)建進(jìn)程丘侠,再去啟動(dòng)服務(wù)
        if (app == null && !permissionsReviewRequired) {
            // 2
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, false, isolated, false)) == null) {
                ...
                bringDownServiceLocked(r);
            }
            ...
        }
        ...
    }
    
  1. 真正啟動(dòng)Service。分為兩步:創(chuàng)建Service逐样,回調(diào)Service的onStartCommand生命周期蜗字。是兩次不同的跨進(jìn)程通信。下面先講如何創(chuàng)建脂新,第四點(diǎn)會(huì)講onStartCommand的調(diào)用流程挪捕。

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        
        // app.thread就是ApplicationThread在AMS的代理接口IApplicationThread
        // 這里就把邏輯切換到service所在進(jìn)程去進(jìn)行創(chuàng)建了
        // 關(guān)于這方面的內(nèi)容,我在上一篇文章有描述争便,這里就不再贅述级零。
        app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                        app.getReportedProcState());
        
        ...
        // 這一步保證如果是直接啟動(dòng)不是綁定,但是r.pendingStarts.size() == 0
        // 也就是沒(méi)有startItem滞乙,那么會(huì)創(chuàng)建一個(gè)奏纪,保證onStartCommand被回調(diào)
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }    
        // 這個(gè)負(fù)責(zé)處理Item事務(wù)。前面我們?cè)趕tartServiceLocked方法里講到添加了一個(gè)Item
        // 此Item就在這里被處理斩启。這一部分內(nèi)容在Service被create之后講序调,下面先講Service的創(chuàng)建
        sendServiceArgsLocked(r, execInFg, true);
    }   
    

三、ActivityThread創(chuàng)建服務(wù)

圖解
image
源碼解析
  1. 這一步主要的工作就是Service所在進(jìn)程接收AMS的請(qǐng)求兔簇,把數(shù)據(jù)封裝起來(lái)后发绢,調(diào)用ActivityThread的sendMessage方法把邏輯切到主線(xiàn)程去執(zhí)行

    /frameworks/base/core/java/android/app/ActivityThread.java/ApplicationThread.class
    
    // 這里把Service的信息封裝成了CreateServiceData,然后交給ActivityThread去處理
    // 這里的sendMessage是ActivityThread的一個(gè)方法
    // ApplicationThread是ActivityThread的一個(gè)內(nèi)部類(lèi)
    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;
        // 跳轉(zhuǎn)
        sendMessage(H.CREATE_SERVICE, s);
    }
    
    /frameworks/base/core/java/android/app/ActivityThread.java;
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        ...
        // 這里的mH也是ActivityThread的一個(gè)內(nèi)部類(lèi)H垄琐,是一個(gè)Handle.負(fù)責(zé)把邏輯切換到主線(xiàn)程來(lái)運(yùn)行
        // 根據(jù)上述的參數(shù)边酒,查看Handle的處理
        mH.sendMessage(msg);
    }
    
  1. 這一步是Handle處理請(qǐng)求,直接調(diào)用ActivityThread的方法來(lái)執(zhí)行事務(wù)

    /frameworks/base/core/java/android/app/ActivityThread.java/H.class;
    public void handleMessage(Message msg) {
        ...
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                        ...
                    case CREATE_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj))); 
                        // 把service信息取出來(lái)此虑,調(diào)用方法進(jìn)行跳轉(zhuǎn)
                        handleCreateService((CreateServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        break;           
                        ...
                }
        ...
    }
    
  1. Activity處理事務(wù)甚纲,創(chuàng)建Service,并初始化Service等

    /frameworks/base/core/java/android/app/ActivityThread.java;
    private void handleCreateService(CreateServiceData data) {
        
        // 獲取LodeApk朦前,是apk描述類(lèi)介杆,主要用于獲取類(lèi)加載器等
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // 獲取類(lèi)加載器,并調(diào)用工廠(chǎng)類(lèi)進(jìn)行實(shí)例化
            // getAppFactory是一個(gè)工廠(chǎng)類(lèi)韭寸,使用類(lèi)加載器來(lái)實(shí)例化android四大組件
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } 
        ...
       
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
         // 創(chuàng)建上下文Context春哨,可以看到這個(gè)和activity的實(shí)例化對(duì)象是一致的
            // 都是contextImpl
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
    
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 初始化并回調(diào)onCreate方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            // 這里把服務(wù)放到ActivityThread的Map中進(jìn)行存儲(chǔ)
            mServices.put(data.token, service);
            ...
        }
        ...
    }  
    

四、AMS處理onStartCommand相關(guān)事務(wù)

圖解
源碼解析
  1. 不知道大家是否還有印象恩伺,前面講到說(shuō)在realStartServiceLocked方法中有一個(gè)sendServiceArgsLocked方法赴背,用來(lái)處理onStartCommand事務(wù)邏輯的。

    這里的講解要依賴(lài)于前面的流程晶渠,因?yàn)閯?chuàng)建Service事務(wù)和onStartCommand事務(wù)兩者在AMS中是并行進(jìn)行的凰荚,只有在最終執(zhí)行的過(guò)程中才是順序進(jìn)行的。遇到不理解的地方可以回去看一下上面的流程褒脯。

    最初的事務(wù)的創(chuàng)建在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, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
        
        // 這里新建一個(gè)StartItem,注意他的第二個(gè)參數(shù)是false番川,這個(gè)參數(shù)名是taskRemove
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    service, neededGrants, callingUid));
        ...
        // 繼續(xù)跳轉(zhuǎn)
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }
    

    這里詳細(xì)講一下到涂。rServiceRecordpendingStarts是一個(gè)List

    final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();

    泛型是StartItem颁督。下面我們看一下這個(gè)類(lèi):

    /frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java/StartItem.java;
    // 此類(lèi)是ServiceRecord的靜態(tài)內(nèi)部類(lèi)
    // 代碼雖然不多践啄,但是我們只關(guān)心我們關(guān)心的代碼
    static class StartItem {
    final ServiceRecord sr;
    // 注意這個(gè)屬性,后面在Service進(jìn)程執(zhí)行的時(shí)候會(huì)用到這個(gè)進(jìn)行判斷
    final boolean taskRemoved;
    final int id;
    final int callingId;
    final Intent intent;
    final NeededUriGrants neededGrants;
    ...
    
    StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
          NeededUriGrants _neededGrants, int _callingId) {
      sr = _sr;
      // 可以看到第二個(gè)屬性進(jìn)行賦值沉御,從上面的代碼可以看出來(lái)這里是false屿讽。(記住他)
      taskRemoved = _taskRemoved;
      id = _id;
      intent = _intent;
      neededGrants = _neededGrants;
      callingId = _callingId;
    }
    
  1. 然后中間經(jīng)過(guò)bringUpServiceLocked方法,負(fù)責(zé)創(chuàng)建進(jìn)程吠裆,前面講到這里就不贅述了聂儒。直接到realStartServiceLocked方法。onStartCommand的事務(wù)是在sendServiceArgsLocked被執(zhí)行的硫痰,可以看到創(chuàng)建和執(zhí)行onStartCommand事務(wù)確實(shí)是兩個(gè)不同的跨進(jìn)程通信衩婚,且是有先后順序的。

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        
        // app.thread就是ApplicationThread在AMS的代理接口IApplicationThread
        // 這里就把邏輯切換到service所在進(jìn)程去進(jìn)行創(chuàng)建了
        // 關(guān)于這方面的內(nèi)容效斑,我在上一篇文章有描述非春,這里就不再贅述。
        app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                        app.getReportedProcState());
        
        ...
        // 這一步保證如果是直接啟動(dòng)不是綁定缓屠,但是r.pendingStarts.size() == 0
        // 也就是沒(méi)有startItem奇昙,那么會(huì)創(chuàng)建一個(gè),保證onStartCommand被回調(diào)
        // 這里也可以看到第二個(gè)參數(shù)是false敌完,也就是taskRemove參數(shù)是false储耐。
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }    
        // 這個(gè)負(fù)責(zé)處理Item事務(wù)。前面我們?cè)趕tartServiceLocked方法里講到添加了一個(gè)Item
        // 此Item就在這里被處理滨溉。這一部分內(nèi)容在Service被create之后講什湘,下面先講Service的創(chuàng)建
        sendServiceArgsLocked(r, execInFg, true);
    }
    
  1. 這一步就是取出之前新建的StartItem长赞,然后逐一執(zhí)行。注意闽撤,Service綁定的流程也會(huì)走到這里得哆,但是他并沒(méi)有startItem,所以會(huì)直接返回哟旗。

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    
    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        // 這里判斷是否有startItem要執(zhí)行贩据。沒(méi)有的話(huà)直接返回。
        // 因?yàn)榻壎ǖ牧鞒桃彩菚?huì)調(diào)用bringUpServiceLocked方法來(lái)啟動(dòng)Service闸餐,但是并不會(huì)
        // 回調(diào)onStartCommand方法饱亮,綁定流程中并沒(méi)有添加startItem。后面講到綁定流程就知道了舍沙。
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }
        
        ArrayList<ServiceStartArgs> args = new ArrayList<>();
        while (r.pendingStarts.size() > 0) {
            // 取出startItem
            ServiceRecord.StartItem si = r.pendingStarts.remove(0);    
            ...
            // 然后保存在list中近上。看到item的taskRemoved變量被傳進(jìn)來(lái)了场勤。前面我們知道他是false戈锻。
            args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
        }
        
        // 把a(bǔ)rgs封裝成一個(gè)新的對(duì)象ParceledListSlice,然后調(diào)用ApplicationThread的方法
        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            // 跳轉(zhuǎn)
            r.app.thread.scheduleServiceArgs(r, slice);
        }   
        ...
    }
    
  1. 邏輯回到Service所在進(jìn)程和媳。這個(gè)時(shí)候取出內(nèi)容封裝成一個(gè)ServiceArgsData對(duì)象然后由Handle交給ActivityThread處理格遭。

    /frameworks/base/core/java/android/app/ActivityThread.java/ApplicationThread.class
    public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
        // 這里直接取出args
        List<ServiceStartArgs> list = args.getList();
    
        // 使用循環(huán)對(duì)每個(gè)事物進(jìn)行執(zhí)行
        for (int i = 0; i < list.size(); i++) {
            ServiceStartArgs ssa = list.get(i);
            ServiceArgsData s = new ServiceArgsData();
            s.token = token;
            // 這里的taskRemoved就是從最開(kāi)始的startItem傳進(jìn)來(lái)的,他的值是false留瞳,上面已經(jīng)講過(guò)了拒迅。
            s.taskRemoved = ssa.taskRemoved;
            s.startId = ssa.startId;
            s.flags = ssa.flags;
            s.args = ssa.args;
    
            // 封裝成一個(gè)ServiceArgsData后進(jìn)行處理
            // 熟悉的邏輯,使用H進(jìn)行且線(xiàn)程處理她倘。我們就直接看到最終的ActivityThread的執(zhí)行邏輯璧微。
            // 中間的流程上面講過(guò)是一樣的,這里不再贅述硬梁。
            sendMessage(H.SERVICE_ARGS, s);
        }
    }
    
  1. ActivityThread是最終的事務(wù)執(zhí)行者随常≌日酰回調(diào)service的onStartCommand生命周期苛吱。

    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ...
                // 之前一直讓你們注意的taskRemoved變量這個(gè)時(shí)候就用到了盟庞。
                // 還記得他的值嗎?沒(méi)錯(cuò)就是false跃巡,這里就開(kāi)始回調(diào)onStartCommand方法了危号。
                // 到這里的Service直接啟動(dòng)流程就講完了。
                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 {
                    // 通知AMS執(zhí)行事務(wù)完成
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                }
                ...
            }
    

綁定啟動(dòng)流程源碼講解

綁定的過(guò)程中涉及到很多的分支素邪。本文選擇的是第一次綁定的流程進(jìn)行講解外莲。其他的情況都是類(lèi)似的,讀者可自行查看源碼兔朦。

一偷线、ContentWrapper請(qǐng)求AMS綁定服務(wù)

圖解
image
源碼解析

和直接啟動(dòng)一樣磨确,首先會(huì)來(lái)到ContextWrapper中進(jìn)行處理,然后請(qǐng)求AMS進(jìn)行創(chuàng)建淋昭。

/frameworks/base/core/java/android/content/ContextWrapper.java
// 從上文可以知道這里的mBase是ContextImpl
Context mBase;
public boolean bindService(Intent service, ServiceConnection conn,
                           int flags) {
    // 第一個(gè)參數(shù)就是Service.class;第二個(gè)參數(shù)是一個(gè)ServiceConnection俐填,用來(lái)回調(diào)返回IBinder對(duì)象
    // 最后一個(gè)是flag參數(shù)安接。直接跳轉(zhuǎn)ContextImp的方法翔忽。
    return mBase.bindService(service, conn, flags);
}


/frameworks/base/core/java/android/app/ContextImpl.java;
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess();
    // 繼續(xù)跳轉(zhuǎn)方法
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
            getUser());
}


private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        String instanceName, Handler handler, Executor executor, UserHandle user) {
    // IServiceConnection是一個(gè)IBinder接口
    // 創(chuàng)建接口對(duì)象來(lái)支持跨進(jìn)程
    IServiceConnection sd;
    ...
    if (mPackageInfo != null) {
        if (executor != null) {
            // 1
            // 這里獲得了IServiceConnection接口。這里的mPackageInfo是LoadedApk類(lèi)對(duì)象盏檐。
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
        } else {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        }
    }
    ...
    // 熟悉的味道歇式,調(diào)用AMS的方法來(lái)進(jìn)行處理,后面的邏輯進(jìn)入AMS
    int res = ActivityManager.getService().bindIsolatedService(
    mMainThread.getApplicationThread(), getActivityToken(), service,
    service.resolveTypeIfNeeded(getContentResolver()),
    sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
}

這里我們深入了解一下IServiceConnection胡野。ServiceConnection并不支持跨進(jìn)程通信材失,所以需要實(shí)現(xiàn)IServiceConnection來(lái)支持跨進(jìn)程。

從上面的注釋1我們可以知道代碼在LoadedApk類(lèi)中硫豆,我們深入來(lái)看一下代碼:

/frameworks/base/core/java/android/app/LoadedApk.java;
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Executor executor, int flags) {
// 跳轉(zhuǎn)
return getServiceDispatcherCommon(c, context, null, executor, flags);
}

// mServices是一個(gè)Map龙巨,里面是一個(gè)context對(duì)應(yīng)一個(gè)map
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();

private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) { 
synchronized (mServices) {
// 這里可以看出來(lái)ServiceDispatcher確實(shí)是LoadedApk的內(nèi)部類(lèi)
LoadedApk.ServiceDispatcher sd = null;
// 先去找是否已經(jīng)存在ServiceConnection
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
 ...
// 找不到則新建一個(gè)
if (sd == null) {
if (executor != null) {
    sd = new ServiceDispatcher(c, context, executor, flags);
} else {
    sd = new ServiceDispatcher(c, context, handler, flags);
    }
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
         map = new ArrayMap<>();
        mServices.put(context, map);
     }
     map.put(c, sd);
 } else {
     sd.validate(context, handler, executor);
 }
 // 最后返回IServiceConnection對(duì)象
 return sd.getIServiceConnection();
}  
}

IServiceConnection的具體實(shí)現(xiàn)是InnerConnection,是ServiceDispatcher的靜態(tài)內(nèi)部類(lèi)熊响,而ServiceDispatcher是LoadedApk的靜態(tài)內(nèi)部類(lèi)旨别。ServiceDispacher內(nèi)部維護(hù)有ServiceConnection,IServiceConnection汗茄,起著聯(lián)系兩者之間的作用秸弛。

畫(huà)個(gè)圖幫助理解:


image

在LoadedApk的內(nèi)部維護(hù)有一個(gè)Map,這個(gè)Map的key是context洪碳,value是Map<ServiceConnection,ServiceDispatcher>递览。也就是一個(gè)應(yīng)用只有一個(gè)LoadedApk,但是一個(gè)應(yīng)用有多個(gè)context瞳腌,每個(gè)context可能有多個(gè)連接绞铃,也就是多個(gè)connection,每個(gè)connection就對(duì)應(yīng)一個(gè)ServiceDispatcher嫂侍。ServiceDispatcher負(fù)責(zé)維護(hù)ServiceConnection和IServiceConnection之間的關(guān)系 儿捧。

二、AMS處理綁定邏輯

圖解
image
源碼解析
  1. AMS接收請(qǐng)求簡(jiǎn)單處理后交給ActivityServices去處理
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java;

public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String instanceName,
        String callingPackage, int userId) throws TransactionTooLargeException {
    ...
    // 還是一樣使用ActivityServices來(lái)進(jìn)行處理
    synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    
}
  1. 這一部分要結(jié)合服務(wù)的生命周期來(lái)理解吵冒。
  1. 綁定的時(shí)候肯定會(huì)先創(chuàng)建服務(wù)纯命,如果還沒(méi)創(chuàng)建的話(huà)。
  2. 調(diào)用onBind方法返回IBinder對(duì)象痹栖,但是可能該服務(wù)的onBind已經(jīng)被調(diào)用過(guò)了亿汞,那么不會(huì)再調(diào)用一次,會(huì)把之前的代理對(duì)象直接返回揪阿。
  3. 這一步是怎么控制的疗我?Service的代理對(duì)象要先到AMS中咆畏,AMS會(huì)先緩存下來(lái),如果其他的客戶(hù)端需要綁定吴裤,會(huì)先去查看是否已經(jīng)存在該IBinder了旧找。如果存在,那么還要判斷他的onUnBind方法是不是已經(jīng)調(diào)用過(guò)了麦牺。
  4. 如果調(diào)用過(guò)onUnBind钮蛛,那么下一次綁定需要判斷前面的onUnBind的返回值。如果是true剖膳,則會(huì)調(diào)用onReBind魏颓,如果是false,則不會(huì)調(diào)用任何生命周期吱晒,且以后的任何綁定都不會(huì)再調(diào)用生命周期了甸饱,直到服務(wù)重建。(這里不理解沒(méi)關(guān)系仑濒,最后我會(huì)補(bǔ)充解綁的源碼講解給大家)
  5. 如果IBinder對(duì)象不存在叹话,也就是首次綁定,那么會(huì)調(diào)用onBind方法進(jìn)行獲取對(duì)象墩瞳。這里涉及到service的生命周期簡(jiǎn)單講述一下驼壶,下面兩個(gè)圖幫助大家理解。理解了生命周期可以方便我們閱讀源碼矗烛。

<img src="https://s1.ax1x.com/2020/08/07/aRsE6S.png" alt="服務(wù)綁定生命周期" border="0" width=30%/>

<img src="https://s1.ax1x.com/2020/08/06/aRtaxs.png" alt="服務(wù)同時(shí)綁定和啟動(dòng)生命周期.png" border="0" width=50%/>

這一部分源碼的內(nèi)容也是圍繞著生命周期來(lái)展開(kāi),這一部分源碼很重要辅柴,涉及到service生命中周期的實(shí)現(xiàn)。

/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;


int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String instanceName, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ...
    // 這里獲得ProcessRecord瞭吃,也就是進(jìn)程的描述類(lèi)
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);  
    ...
        
    //獲取Service描述類(lèi)ServiceRecord
    ServiceLookupResult res =
        retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
                callerFg, isBindExternal, allowInstant);
    ...
    ServiceRecord s = res.record;
    
    ...
    
    /**
    * 解釋幾個(gè)重要的類(lèi)
    * ConnectionRecord:應(yīng)用程序進(jìn)程和service之間的一次通信信息
    * IntentBindRecord: 綁定service的Intent的信息
    * AppBindRecord:維護(hù)應(yīng)用程序進(jìn)程和service之間的關(guān)聯(lián)碌嘀,包括應(yīng)用進(jìn)程ProcessRecord,
    *   服務(wù)ServiceRecord歪架,通信信息ConnectionRecord股冗,Intent信息IntentBindRecord
    */
    // 這里獲取到AppBindRecord對(duì)象,并創(chuàng)建ConnectionRecord
    // 后面會(huì)講到和蚪,記得留意一下
    AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
    ConnectionRecord c = new ConnectionRecord(b, activity,
            connection, flags, clientLabel, clientIntent,
            callerApp.uid, callerApp.processName, callingPackage);
    
    // 判斷標(biāo)志是否創(chuàng)建止状,和上面的直接啟動(dòng)服務(wù)類(lèi)似,調(diào)用此方法進(jìn)行啟動(dòng)攒霹。這里就不贅述
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
        s.lastActivity = SystemClock.uptimeMillis();
        if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
            return 0;
        }
    }
    ...
        
    // s是ServiceRecord怯疤,app是ProcessRecord,表示service已經(jīng)創(chuàng)建
    // b.intent.received表示當(dāng)前應(yīng)用程序進(jìn)程是否已經(jīng)收到IBinder對(duì)象
    // 總體意思:服務(wù)是否已經(jīng)建立且當(dāng)前應(yīng)用程序進(jìn)程收到IBinder對(duì)象
    // 是:直接返回IBinder對(duì)象催束,否集峦,轉(zhuǎn)注釋2
    if (s.app != null && b.intent.received) {
       
        try {
            // 如果已經(jīng)有這個(gè)IBinder對(duì)象了,那么就直接返回
            c.conn.connected(s.name, b.intent.binder, false);
        } catch (Exception e) {
            Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                    + " to connection " + c.conn.asBinder()
                    + " (in " + c.binding.client.processName + ")", e);
        }

        // 下面注釋1和注釋2的區(qū)別就是最后一個(gè)參數(shù)
        // 區(qū)別在于是否要調(diào)用onRebind方法。從服務(wù)的生命周期了解到綁定的時(shí)候第一次需要調(diào)用onBind
        // 如果onUnbind返回true塔淤,那么不會(huì)調(diào)用onBind而是調(diào)用onRebind摘昌。其他情況不會(huì)調(diào)用生命周期
        // 只是純粹的綁定
        // 方法,判斷是要執(zhí)行onBind還是reBind方法
        if (b.intent.apps.size() == 1 && b.intent.doRebind) {
            // 1
            requestServiceBindingLocked(s, b.intent, callerFg, true);
        }
    } else if (!b.intent.requested) {
        // 2
        requestServiceBindingLocked(s, b.intent, callerFg, false);
    }
    
}
  1. 這一步深入看看第一次綁定的時(shí)候怎么實(shí)現(xiàn)的高蜂。了解了第一次如何執(zhí)行的聪黎,其他的也就自然明白了。這一步是和reBind使用的是同個(gè)方法备恤,重點(diǎn)是在參數(shù)不同稿饰。但是道理和ReBind是差不多的,都是跨進(jìn)程到Service所在進(jìn)程進(jìn)行回調(diào)生命周期方法烘跺。不同的是第一次是調(diào)用onBind方法湘纵,而Rebind是調(diào)用onRebind方法脂崔。且第一次回調(diào)還需要回來(lái)AMS進(jìn)行記錄滤淳。后面會(huì)詳細(xì)講到。先看這一部分源碼:

    /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
    
    // 首先看到requestServiceBindingLocked砌左,在AMS還沒(méi)有IBinder對(duì)象的時(shí)候會(huì)先調(diào)用
    // 這個(gè)方法去獲取Service的IBinder對(duì)象脖咐,然后再回調(diào)客戶(hù)端的ServiceConnection。
    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        
        // i.requested表示是否已經(jīng)綁定過(guò)了汇歹,rebind表示是不是要進(jìn)行rebind屁擅,這些都和上面的
        // 條件判斷一一對(duì)應(yīng)。第一次綁定和重綁這里(!i.requested || rebind)都是等于true
        // i.app.size()這里一般不會(huì)<=0.在下面的引用中有詳細(xì)講
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // 這里就很熟悉了产弹,通過(guò)ApplicationThread來(lái)知性邏輯
                // ApplicationThread的所有schedule開(kāi)頭的方法派歌,最后都是會(huì)通過(guò)H切換到主線(xiàn)程去執(zhí)行
                // 后面的邏輯就切換到service的所在線(xiàn)程中了,AMS要去獲取IBinder
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            }
            ...
        }
        ...
    }
    
    

    i.apps.size() > 0 痰哨,這里的 i是IntentBindRecord胶果,上面我們介紹到他的作用是記錄每一個(gè)請(qǐng)求Intent的信息,因?yàn)椴煌倪M(jìn)程斤斧,可能使用同個(gè)Intent進(jìn)行請(qǐng)求綁定的早抠。看看IntentBindRecord的代碼:

    /frameworks/base/services/core/java/com/android/server/am/IntentBindRecord.java;
    
    // 通過(guò)官方的注釋我們也可以理解了
    // 它里面包含了對(duì)應(yīng)的ServiceRecord撬讽,還有根據(jù)進(jìn)程記錄對(duì)應(yīng)的AppBindRecord
    // 同個(gè)Intent可能給不同的進(jìn)程服務(wù)蕊连,所以要把不同的進(jìn)程的信息記錄下來(lái)
    final class IntentBindRecord {
     /** The running service. */
     final ServiceRecord service;
     /** The intent that is bound.*/
     final Intent.FilterComparison intent; // 
     /** All apps that have bound to this Intent. */
     final ArrayMap<ProcessRecord, AppBindRecord> apps
             = new ArrayMap<ProcessRecord, AppBindRecord>();
     ...
    }
    

    AppBindRecord前面也介紹了是用于記錄intent,service游昼,connection還有process信息的甘苍。也就是一切的綁定信息這里都有。在上面有一個(gè)方法代碼是AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);烘豌,來(lái)看看他是怎么實(shí)現(xiàn)的:

    // 這里的S是ServiceRecord類(lèi)型
    /frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java;
    final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
         = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
    public AppBindRecord retrieveAppBindingLocked(Intent intent,
         ProcessRecord app) {
     // 判斷綁定的intent是否已經(jīng)存在對(duì)應(yīng)的IntentBindRecord
     Intent.FilterComparison filter = new Intent.FilterComparison(intent);
     IntentBindRecord i = bindings.get(filter);
     if (i == null) {
         // 如果沒(méi)有則創(chuàng)建一個(gè)载庭,并存儲(chǔ)起來(lái)
         i = new IntentBindRecord(this, filter);
         bindings.put(filter, i);
     }
     // 判斷該IntentBindRecord是否有啟動(dòng)的進(jìn)程的綁定信息AppBindRecord
     AppBindRecord a = i.apps.get(app);
     if (a != null) {
         return a;
     }
     // 沒(méi)有就創(chuàng)建一個(gè),并放到IntentBindRecord中
     a = new AppBindRecord(this, i, app);
     i.apps.put(app, a);
     return a;
    }
    

    分析到這里就可以發(fā)現(xiàn)i.apps.size()肯定是大于0了。

    不知道你們會(huì)不會(huì)被各種Record給繞暈了昧捷,這里我整理個(gè)圖幫助你們理解(只涉及到我上面講的內(nèi)容):
    [圖片上傳失敗...(image-f3d53a-1605448549040)]

三闲昭、Service進(jìn)程調(diào)用onBind進(jìn)行綁定

圖解
image
源碼解析

這一步是ActivityThread處理綁定任務(wù)。主要是回調(diào)生命周期靡挥,然后得到服務(wù)的IBinder對(duì)象序矩,然后交給AMS。如果是reBind則不需要跋破,只需要回調(diào)生命周期簸淀。

/frameworks/base/core/java/android/app/ActivityThread.java/ApplicationThread.class;
// 和上面的類(lèi)似,直接到H的handleMessage方法
public final void scheduleBindService(IBinder token, Intent intent,
        boolean rebind, int processState) {
    updateProcessState(processState, false);
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;
    s.rebind = rebind;

    if (DEBUG_SERVICE)
        Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
}


/frameworks/base/core/java/android/app/ActivityThread.java/H.class;
public void handleMessage(Message msg) {
    ...
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                    ...
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    // 跳轉(zhuǎn)ActivityThread的方法
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                        
                    ...
            }
    ...
}


/frameworks/base/core/java/android/app/ActivityThread.java;
private void handleBindService(BindServiceData data) {
    // 得到Service實(shí)例
    // 這里的實(shí)例是在直接啟動(dòng)的時(shí)候存進(jìn)來(lái)的毒返,沒(méi)有印象的讀者可以再回去看一下啟動(dòng)流程
    Service s = mServices.get(data.token);
    if (DEBUG_SERVICE)
        Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                // 這里判斷是重綁還是第一次綁定租幕。
                // 第一次綁定需要把IBinder對(duì)象返回給AMS,然后讓AMS把IBinder對(duì)象回調(diào)給
                // 調(diào)用端的ServiceConnection
                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);
                }
            } 
    ...
}
    

四拧簸、AMS緩存onBind返回的IBinder對(duì)象劲绪,并把該對(duì)象回調(diào)到綁定端

圖解

<img src="https://s1.ax1x.com/2020/08/08/a5TqMT.png" alt="Service綁定流程-4.png" border="0" width=70%/>

源碼解析
  1. 這一步回到AMS主要就是把拿到的IBinder存儲(chǔ)一下,下次就不用再調(diào)用onBind了盆赤,直接返回即可贾富。然后回調(diào)ServiceConnection的方法。
  /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java;
  
  // AMS還是老樣子把任務(wù)交給ActivityServices去處理
  public void publishService(IBinder token, Intent intent, IBinder service) {
      // Refuse possible leaked file descriptors
      if (intent != null && intent.hasFileDescriptors() == true) {
          throw new IllegalArgumentException("File descriptors passed in Intent");
      }
  
      synchronized(this) {
          if (!(token instanceof ServiceRecord)) {
              throw new IllegalArgumentException("Invalid service token");
          }
          // 跳轉(zhuǎn)ActivityServices的方法
          mServices.publishServiceLocked((ServiceRecord)token, intent, service);
      }
  }
  
  /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java;
  void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
      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;
              // 這里設(shè)置為true牺六,還記得上面的條件判斷邏輯嗎颤枪?
              // 對(duì)的,下次就可以直接返回了淑际,不需要再去ActivityThread執(zhí)行onBind方法拿IBinder對(duì)象了
              b.received = true;
              ...
                  try {
                      // 這里拿到IBinder對(duì)象之后就執(zhí)行回調(diào)了
                      // 下面我們深入看看怎么回調(diào)的畏纲。我們知道這個(gè)回調(diào)的具體實(shí)現(xiàn)是InnerConnection
                      // 前面已經(jīng)介紹了不知道你是否還有印象。接下來(lái)我們就去InnerConnection看看
                      c.conn.connected(r.name, service, false);
                  } catch (Exception e) {
                      Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                             + " to connection " + c.conn.asBinder()
                             + " (in " + c.binding.client.processName + ")", e);
                  }
               ...
           
      }
  }
  
  1. 這一步主要是InnerConnection收到AMS的請(qǐng)求春缕,然后把請(qǐng)求交給ServiceDispatcher去處理盗胀,ServiceDispatcher再封裝成一個(gè)Runnable對(duì)象給ActivityThread的H在主線(xiàn)程中執(zhí)行,最后的真正執(zhí)行方法是ServiceDispatcher.doConnect()淡溯。最終ActivityThread會(huì)回調(diào)ServiceConnection的方法读整。

       /frameworks/base/core/java/android/app/LoadedApk.java/ServiceDispatcher.java/InnerConnection.java;
       public void connected(ComponentName name, IBinder service, boolean dead)
               throws RemoteException {
           LoadedApk.ServiceDispatcher sd = mDispatcher.get();
           if (sd != null) {
               // 和ApplicationThread熟悉的味道,直接調(diào)用外部的方法咱娶,繼續(xù)跳轉(zhuǎn)
               sd.connected(name, service, dead);
           }
       }
       
       
       /frameworks/base/core/java/android/app/LoadedApk.java/ServiceDispatcher.java;
       // 我們?cè)谡{(diào)用的時(shí)候并沒(méi)有傳入Executor米间,mActivityThread就是ActivityThread中的mH
       // 而post方法很明顯是Handle的post方法,也就是他的內(nèi)部類(lèi)H去執(zhí)行膘侮。
       // 所以這里就把任務(wù)丟給ActivityThread在主線(xiàn)程中執(zhí)行了屈糊。
       // 這個(gè)參數(shù)在我們調(diào)用bindService會(huì)作為參數(shù)傳入,不知你是否還有印象琼了。
       // 接下來(lái)我們?nèi)タ纯匆獔?zhí)行的這個(gè)任務(wù)是什么
       public void connected(ComponentName name, IBinder service, boolean dead) {
           if (mActivityExecutor != null) {
               mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
           } else if (mActivityThread != null) {
               mActivityThread.post(new RunConnection(name, service, 0, dead));
           } else {
               doConnected(name, service, dead);
           }
       }  
       /frameworks/base/core/java/android/app/LoadedApk.java/ServiceDispatcher.java/RunConnection.class;
       private final class RunConnection implements Runnable {
           ...
           // 上面實(shí)例化的時(shí)候參數(shù)是0逻锐,所以執(zhí)行doConnect方法
           public void run() {
               if (mCommand == 0) {
                   doConnected(mName, mService, mDead);
               } else if (mCommand == 1) {
                   doDeath(mName, mService);
               }
           }
           ...
       }
       
    /frameworks/base/core/java/android/app/LoadedApk.java/ServiceDispatcher.java;
    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        // 這里有兩個(gè)連接信息夫晌,一個(gè)是老的,另一個(gè)是新的昧诱。
        ServiceDispatcher.ConnectionInfo old;
        ServiceDispatcher.ConnectionInfo info;
        synchronized (this) {
            ...
                // 獲取是否有已經(jīng)有連接信息且IBinder!=null
                old = mActiveConnections.get(name);
            if (old != null && old.binder == service) {
                // 已經(jīng)擁有這個(gè)IBinder了晓淀,不需要做任何操作
                return;
            }
    
            if (service != null) {
                // A new service is being connected... set it all up.
                info = new ConnectionInfo();
                info.binder = service;
                info.deathMonitor = new DeathMonitor(name, service);
                try {
                    // 監(jiān)聽(tīng)service的生命周期,如果服務(wù)掛了就會(huì)通知
                    service.linkToDeath(info.deathMonitor, 0);
                    mActiveConnections.put(name, info);
                }
                ...
            }
            ...
        }
        // 如果連接信息存在且IBinder==null,說(shuō)明出現(xiàn)了意外服務(wù)被殺死了盏档,回調(diào)onServiceDisconnected凶掰。
        if (old != null) {
            mConnection.onServiceDisconnected(name);
        }
        // 這個(gè)dead參數(shù)由AMS傳入
        if (dead) {
            mConnection.onBindingDied(name);
        }
        // 正常情況下直接回調(diào)onServiceConnected
        if (service != null) {
            mConnection.onServiceConnected(name, service);
        } else {
            // The binding machinery worked, but the remote returned null from onBind().
            // 官方注釋翻譯過(guò)來(lái)就是綁定正常工作但是服務(wù)的onBind方法返回了null
            mConnection.onNullBinding(name);
        }       
    }
    

總結(jié)

我們通過(guò)總體流程概述+源碼解析的方式講了Service的兩種啟動(dòng)流程,詳細(xì)解析了啟動(dòng)過(guò)程中的源碼細(xì)節(jié)蜈亩∨尘剑可以看到Service的啟動(dòng)和Activity的啟動(dòng)是很像的,都是需要經(jīng)過(guò)AMS的協(xié)助完成稚配。

文章對(duì)于一些分支的流程沒(méi)有深入講畅涂,如onStartCommand方法何時(shí)被調(diào)用,reBind的流程是如何進(jìn)行的等等道川。感興趣的讀者可以自行閱讀源碼午衰。

希望文章對(duì)你有收獲。

參考文獻(xiàn)

《Android開(kāi)發(fā)藝術(shù)探索》

《Android進(jìn)階解密》

Service 的綁定原理

Service 詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愤惰,一起剝皮案震驚了整個(gè)濱河市苇经,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宦言,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件商模,死亡現(xiàn)場(chǎng)離奇詭異奠旺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)施流,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)响疚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瞪醋,你說(shuō)我怎么就攤上這事忿晕。” “怎么了银受?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵践盼,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宾巍,道長(zhǎng)咕幻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任顶霞,我火速辦了婚禮肄程,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己蓝厌,他們只是感情好玄叠,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拓提,像睡著了一般诸典。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崎苗,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天狐粱,我揣著相機(jī)與錄音,去河邊找鬼胆数。 笑死肌蜻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的必尼。 我是一名探鬼主播蒋搜,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼判莉!你這毒婦竟也來(lái)了豆挽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤券盅,失蹤者是張志新(化名)和其女友劉穎帮哈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體锰镀,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娘侍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泳炉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憾筏。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖花鹅,靈堂內(nèi)的尸體忽然破棺而出氧腰,到底是詐尸還是另有隱情,我是刑警寧澤刨肃,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布古拴,位于F島的核電站,受9級(jí)特大地震影響之景,放射性物質(zhì)發(fā)生泄漏斤富。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一锻狗、第九天 我趴在偏房一處隱蔽的房頂上張望满力。 院中可真熱鬧焕参,春花似錦、人聲如沸油额。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)潦嘶。三九已至涩嚣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掂僵,已是汗流浹背航厚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锰蓬,地道東北人幔睬。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像芹扭,于是被迫代替她去往敵國(guó)和親麻顶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容