前言
Service啟動(dòng)與上一篇說(shuō)的入口Activity啟動(dòng)類似气忠,主要分成ContextImpl到ActivityManagerService調(diào)用和ActivityThread啟動(dòng)Service這兩個(gè)過(guò)程
ContextImpl到AMS的調(diào)用過(guò)程
這個(gè)過(guò)程比較簡(jiǎn)單蛔六,如圖所示
啟動(dòng)Service肯定是從startService開(kāi)始,這個(gè)方法是在ContextWrapper中實(shí)現(xiàn)的苍在,在這個(gè)方法中調(diào)用了ContextImpl的startService方法。
在ContextImpl中經(jīng)過(guò)startServiceCommon没讲,最終通過(guò)IActivityManager的startService方法來(lái)通知AMS啟動(dòng)一個(gè)Service赠涮。
ActivityThread啟動(dòng)Service
這部分過(guò)程如圖:
上一個(gè)過(guò)程最終是調(diào)用了AMS的startService方法,這個(gè)過(guò)程就是從這開(kāi)始的梁厉,這里會(huì)調(diào)用ActiveService的startServiceLocked,代碼如下:
ComponentName startServiceLocked(...) throws TransactionTooLargeException {
...
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false); //1
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record; //1
...
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
代碼1處通過(guò)retrieveServiceLocked方法會(huì)先查找參數(shù)service對(duì)應(yīng)的ServiceRecord踏兜;如果沒(méi)有回調(diào)用PackageManagerService取獲取參數(shù)service對(duì)應(yīng)的Service信息并封裝到ServiceRecord词顾。最后將ServiceRecord封裝成ServiceLookupResult返回〖钭保可以看到這里與上一篇講的Activity很類似肉盹,ServiceRecord就像ActivityRecord一樣用來(lái)描述一個(gè)Service。
代碼2就是從ServiceLookupResult取出ServiceRecord疹尾,然后調(diào)用startServiceInnerLocked上忍。
startServiceInnerLocked方法會(huì)調(diào)用bringUpServiceLocked方法,這個(gè)方法代碼如下:
private String bringUpServiceLocked(...) throws TransactionTooLargeException {
...
final String procName = r.processName; //1
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); //2
...
if (app != null && app.thread != null) { //3
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg); //4
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
...
}
if (app == null && !permissionsReviewRequired) { //5
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, //6
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
...
return null;
}
代碼1得到進(jìn)程名稱纳本。代碼2調(diào)用AMS的getProcessRecordLocked查詢與該Service對(duì)應(yīng)的ProcessRecord窍蓝,ProcessRecord一看名字就應(yīng)該能猜出來(lái)了,主要是描述運(yùn)行的應(yīng)用程序進(jìn)程信息繁成。所以代碼2的目的就是獲取該Service對(duì)應(yīng)的應(yīng)用程序進(jìn)程吓笙。
代碼3處判斷如果應(yīng)用程序進(jìn)程存在,則執(zhí)行代碼4巾腕,通過(guò)realStartServiceLocked方法來(lái)啟動(dòng)Service面睛。
如果不存在就會(huì)跳到代碼5絮蒿,再次判斷不存在則在代碼6處調(diào)用AMS的startProcessLocked來(lái)創(chuàng)建對(duì)應(yīng)的應(yīng)用程序信息。
在realStartServiceLocked方法中調(diào)用了IApplicationThread的scheduleCreateService方法叁鉴,它的實(shí)現(xiàn)是ActivityThread內(nèi)部類ApplicatioinThread土涝,這塊跟Activity啟動(dòng)幾乎一樣。
scheduleCreateService將service的啟動(dòng)參數(shù)封裝后通過(guò)Handler進(jìn)行通知幌墓。最終會(huì)在ActivityThread處理但壮,處理方法是handleCreateService,代碼如下:
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo); //1
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader(); //2
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent); //3
} catch (Exception e) {
...
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService()); //5
service.onCreate(); //6
mServices.put(data.token, service); //7
...
} catch (Exception e) {
...
}
}
代碼2會(huì)獲取類加載器克锣,然后代碼3從之前封裝的對(duì)象中獲取Service信息茵肃,創(chuàng)建service;代碼4獲取上下文袭祟;代碼5通過(guò)service的attach方法來(lái)初始化service验残;代碼6則調(diào)用了service的onCreate方法;代碼7將service加入ActivithThread的成員變量mServices中巾乳,以便后續(xù)使用您没。