總結(jié)了幾篇系統(tǒng)底層相關(guān)的文章掩缓,終于要接觸到應(yīng)用層了揽浙,不過需要提前掌握 Binder架構(gòu)料仗,系統(tǒng)啟動流程湾盗,進(jìn)程啟動流程 的相關(guān)姿勢,不然很難理清整個流程立轧。相對于 startAcitivity()格粪,startService() 的流程相對簡單,因為不涉及界面相關(guān)的操作氛改,便于理清用戶進(jìn)程帐萎,AMS 所在進(jìn)程(也即 SystemServer 進(jìn)程)和 服務(wù)所在進(jìn)程三者之間的關(guān)系。
1. 整體流程
這里借用 gityuan 的一篇文章 里的圖:
這個圖畫的非常好胜卤,關(guān)鍵點基本上都標(biāo)注出來了疆导,涉及到三個進(jìn)程的交互(當(dāng)然Remote Service 進(jìn)程也可以和 Process A 進(jìn)程是同一個,那樣就省略2葛躏、3創(chuàng)建進(jìn)程的步驟)澈段。重點注意整個流程中涉及到通過 Binder 進(jìn)行跨進(jìn)程交互的部分,如果不熟悉 Binder 架構(gòu)舰攒,很難理解败富。下面以從一個 Activity 里面調(diào)用 startActivity() 啟動服務(wù)為例,進(jìn)行詳細(xì)分析摩窃。
2. ContextImpl.startService()
Activity -> ContextThemeWrapper -> ContextWrapper兽叮,ContextWrapper 是個代理類,實際功能都由其成員變量 Context mBase 實現(xiàn)偶芍,mBase 實際上是一個 ContextImpl 對象(具體怎么來的充择,以后的文章會講到,簡單的說是啟動Activity 時注入的)匪蟀。在 Application 或者 Service 里面啟動 startService 也是一樣椎麦,最終都調(diào)用到 ContextImpl.startService():
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
...
// Binder 調(diào)用 AMS
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
...
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
這里有兩個關(guān)鍵點:
- ActivityManagerNative.getDefault() 獲取了 ActivityManagerService (AMS)的遠(yuǎn)程代理對象 ActivityManagerProxy,并發(fā)起了 startService 的請求
- mMainThread.getApplicationThread()材彪,這里 mMainThread 是一個 ActivityThread 對象观挎,getApplicationThread() 返回 ActivityThread 的成員變量 ApplicationThread mAppThread琴儿,ApplicationThread 是 ActivityThread 的一個內(nèi)部類,看定義:
private class ApplicationThread extends ApplicationThreadNative {
...
}
明顯也是一個 Binder 架構(gòu)嘁捷,把這個 Binder 對象傳遞給 AMS造成,是為了 AMS 與發(fā)起 startService 的調(diào)用進(jìn)程通信,后面會具體分析雄嚣。
到這里晒屎,發(fā)起 startService 請求的部分就完成了,接下來會通過 Binder 跨進(jìn)程調(diào)用缓升,進(jìn)入到 AMS 中繼續(xù)分析鼓鲁。
3. AMS.startService()
通過 Binder
機(jī)制,ActivityManagerProxy.startService ----跨進(jìn)程---> ActivityManagerNative.onTransact() --> AMS.startService()港谊,AMS 是 AMN 的子類骇吭,實現(xiàn)了其 startService 方法。
AMS 中的 startService 方法:
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, 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 = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
...
return res;
}
}
這里 IApplicationThread caller 就是發(fā)起進(jìn)程在 AMS 所在的進(jìn)程中的代理歧寺。mService 是 一個 ActiveServices 類型的成員變量燥狰,其持有 AMS 的引用。
4. ActiveServices
4.1 startServiceLocked()
這個方法源碼比較長斜筐,這里只保留關(guān)鍵部分:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); // 1. 查找調(diào)用進(jìn)程是否存在
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
...
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false); // 2. 查找要啟動的服務(wù)是否已經(jīng)存在
...
ServiceRecord r = res.record;
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting)
兩個關(guān)鍵點已經(jīng)用注釋中標(biāo)記出來龙致,retrieveServiceLocked() 內(nèi)部流程也比較復(fù)雜,有各種條件奴艾、權(quán)限的檢查等净当,這里不深入分析了,簡單說就是有一個 Map 用來保存用戶所有已啟動的服務(wù)蕴潦,如果不存在符合條件的 ServiceRecord像啼,就新建一個并保存在 Map 中。最后流程進(jìn)入到 startServiceInnerLocked() --> bringUpServiceLocked()
4.2 bringUpServiceLocked()
仍然先貼出簡化后的代碼:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
//1. Service 所在的進(jìn)程和 Service 線程都已經(jīng)啟動的情況
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
if (!isolated) {
// 2.查找服務(wù)對應(yīng)的進(jìn)程是否存在
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
...
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 3. 如果進(jìn)程已經(jīng)存在潭苞,直接啟動服務(wù)
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
}
...
if (app == null && !permissionsReviewRequired) {
// 4. 如果進(jìn)程不存在忽冻,啟動進(jìn)程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
...
}
...
}
幾個關(guān)鍵點已經(jīng)注釋標(biāo)明:
- 如果服務(wù)所在進(jìn)程和線程都已經(jīng)啟動(r.app != null && r.app.thread != null),那么調(diào)用 sendServiceArgsLocked()此疹,這個方法里的關(guān)鍵代碼只有一句:
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
r.app.thread 就是發(fā)起 startService 的進(jìn)程在 AMS 中的遠(yuǎn)程代理對象僧诚,這里又通過了 Binder 跨進(jìn)程調(diào)用,最終調(diào)用到 ApplicationThreadNative.onTransact() --> ApplicationThread.scheduleServiceArgs():
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
調(diào)用該方法后蝗碎,ApplicationThread 會把消息 post 到主線程的 handler 處理湖笨,對應(yīng) SERVICE_ARGS 的處理函數(shù)是 handleServiceArgs(),在這個方法里蹦骑,終于看到了我們熟悉的 Service.onStartCommand() 慈省!這也是為什么當(dāng)反復(fù)啟動 Service 的時候,只有 onStartCommand() 會被反復(fù)調(diào)用眠菇。
- 如果服務(wù)所在進(jìn)程已經(jīng)存在边败,那么進(jìn)入 realStartServiceLocked() 啟動服務(wù)袱衷,這里也不貼出大段源碼了,關(guān)鍵代碼有兩處:
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
sendServiceArgsLocked(r, execInFg, true);
和第一種情況類似笑窜,這里也是兩個 Binder 跨進(jìn)程調(diào)用致燥,最終分別調(diào)用到 Service 的 onCreate() 和 onStartCommand 生命周期,這又是我們非常熟悉的部分了排截。
- 如果服務(wù)所在進(jìn)程不存在嫌蚤,那么調(diào)用 AMS.startProcessLocked 啟動進(jìn)程。在上一篇 Android 進(jìn)程啟動流程總結(jié) 中已經(jīng)分析了從 AMS.startProcessLocked 開始的流程断傲,這里終于找到了它的調(diào)用的源頭之一搬葬,就是當(dāng)啟動的服務(wù)所在進(jìn)程還不存在時,就要調(diào)用 AMS.startProcessLocked 先啟動對應(yīng)的進(jìn)程艳悔。在上篇文章的最后提到,進(jìn)程啟動后會調(diào)用 ActivityThread.main() 方法 -->ActivityThread.attach() --> ActivityManagerProxy.attachApplication() --Binder跨進(jìn)程調(diào)用--> AMS.attachApplication() --> AMS.attachApplicationLocked() --> ActiveServices.attachApplicationLocked() --> ActiveServices.realStartServiceLocked()女仰,終于殊途同歸猜年!回到了和第2種情況一樣的函數(shù)。
至此疾忍,startService() 的整個流程就走完了乔外。
5. 總結(jié)
startService() 的流程看起來有些復(fù)雜,但是只要先建立了如第一節(jié)所示的三個進(jìn)程間交互的整體結(jié)構(gòu)圖一罩,那么整體思路還是很清晰的杨幼,這中間涉及了 Binder 和 Socket 兩種跨進(jìn)程調(diào)用(上一篇介紹的進(jìn)程啟動流程里講到),是把前面學(xué)習(xí)的 Android 底層架構(gòu)知識融會貫通的一個非常好的學(xué)習(xí)范例聂渊,也為后面分析更為復(fù)雜的 startActivity() 流程打好了基礎(chǔ)差购。