歡迎讀者閱讀我的個(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)容大綱:
總體工作流程思路概述
這一部分主要為大家有個(gè)整體的流程感知帜慢,不會(huì)在源碼中丟失自己笼裳。分為兩個(gè)部分:?jiǎn)?dòng)流程與綁定流程。
直接啟動(dòng)流程概述
概述
直接啟動(dòng)粱玲,也就是我們?cè)贏ctivity中調(diào)用startService來(lái)啟動(dòng)一個(gè)Service的方式躬柬。
圖解
簡(jiǎn)析
啟動(dòng)的步驟:
- Activity向AMS,即ActivityManagerService請(qǐng)求啟動(dòng)Service抽减。
- AMS判斷Service所在的進(jìn)程是否已經(jīng)創(chuàng)建允青,注意Service和Activity是可以同個(gè)進(jìn)程的。
- 如果還沒(méi)創(chuàng)建則通過(guò)Zygote進(jìn)程fork一個(gè)進(jìn)程卵沉。
- AMS請(qǐng)求Service所在進(jìn)程的ActivityThread創(chuàng)建Service和啟動(dòng)颠锉,并回調(diào)Service的onCreate方法。
- 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ù)雜姥宝,配合下面的解析一起看
簡(jiǎn)析
介紹一下步驟:
- Activity請(qǐng)求AMS綁定Service翅萤。
- AMS判斷Service是否已經(jīng)啟動(dòng)了。如果還沒(méi)啟動(dòng)會(huì)先去啟動(dòng)Service腊满。
- AMS調(diào)用Service的onBind方法獲取Service的IBinder對(duì)象套么。
- Service把自己的IBinder對(duì)象發(fā)布到AMS中保存,這樣下次綁定就不需要再調(diào)用onBind了碳蛋。
- 把拿到的IBinder對(duì)象返回給Activity胚泌。
- 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ò)程
圖解
源碼解析
-
我們?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); ... }
-
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ò)程
圖解
源碼解析
-
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); ... }
-
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); }
-
這一步主要是檢查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); } ... } ... }
-
真正啟動(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ù)
圖解
源碼解析
-
這一步主要的工作就是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); }
-
這一步是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; ... } ... }
-
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ù)
圖解
源碼解析
-
不知道大家是否還有印象恩伺,前面講到說(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ì)講一下到涂。
r
是ServiceRecord
,pendingStarts
是一個(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; }
-
然后中間經(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); }
-
這一步就是取出之前新建的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); } ... }
-
邏輯回到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); } }
-
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ù)
圖解
源碼解析
和直接啟動(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è)圖幫助理解:
在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處理綁定邏輯
圖解
源碼解析
- 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);
}
}
- 這一部分要結(jié)合服務(wù)的生命周期來(lái)理解吵冒。
- 綁定的時(shí)候肯定會(huì)先創(chuàng)建服務(wù)纯命,如果還沒(méi)創(chuàng)建的話(huà)。
- 調(diào)用onBind方法返回IBinder對(duì)象痹栖,但是可能該服務(wù)的onBind已經(jīng)被調(diào)用過(guò)了亿汞,那么不會(huì)再調(diào)用一次,會(huì)把之前的代理對(duì)象直接返回揪阿。
- 這一步是怎么控制的疗我?Service的代理對(duì)象要先到AMS中咆畏,AMS會(huì)先緩存下來(lái),如果其他的客戶(hù)端需要綁定吴裤,會(huì)先去查看是否已經(jīng)存在該IBinder了旧找。如果存在,那么還要判斷他的onUnBind方法是不是已經(jīng)調(diào)用過(guò)了麦牺。
- 如果調(diào)用過(guò)onUnBind钮蛛,那么下一次綁定需要判斷前面的onUnBind的返回值。如果是true剖膳,則會(huì)調(diào)用onReBind魏颓,如果是false,則不會(huì)調(diào)用任何生命周期吱晒,且以后的任何綁定都不會(huì)再調(diào)用生命周期了甸饱,直到服務(wù)重建。(這里不理解沒(méi)關(guān)系仑濒,最后我會(huì)補(bǔ)充解綁的源碼講解給大家)
- 如果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);
}
}
-
這一步深入看看第一次綁定的時(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)行綁定
圖解
源碼解析
這一步是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%/>
源碼解析
- 這一步回到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);
}
...
}
}
-
這一步主要是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)階解密》