疫情似乎仍然沒有好轉的跡象,鄰居被查出來感染上了病毒,搞得人心惶惶的。待在家裏啥也做不了,就好好學習吧。
今天看了下service的啓動過程,然後將其捋一捋加深印象。
1.service的啓動流程
如下圖所示爲service的啓動流程
我們可以看到,我們調用的startService是ContextImpl的startService方法,然後會遠程調用AMS,AMS再調用ActiveServices類的方法去啓動一個service。
這裏我們重點看下bringUpServiceLocked方法。
在註釋1處,如果service已經啓動了,那麼就只會調用sendServiceArgsLocked方法,然後直接返回,這個方法會觸發service的onStartCommand方法,所以當一個service被start兩次,onCreate只會執行一次,而onStartCommand卻會執行兩次,原因就在這裏。
在註釋2處,如果service沒啓動,但是進程已經啓動了,那麼就會執行realStartServiceLocked方法,這個方法就會真正的啓動一個service,並執行service的周期函數。
在註釋3處,如果進程沒有啓動,那麼就會調用AMS的mAm.startProcessLocked方法去啓動進程。
在註釋4處,將serviceRecord添加到penddingServices裏面。如果當前進程沒有啓動,那麼這個serviceRecord就會添加到penddingServices列表裏面,當進程啓動之後,就會去處理這個列表。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//1.service已經啓動
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
......
if (!isolated) {
//2.service沒啓動,進程已經啓動
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
}
if (app == null && !permissionsReviewRequired) {
//3.進程沒啓動,調用startProcessLocked啓動進程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
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;
}
}
......
//4.將ServiceRecord添加到mPendingServices裏面
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
......
}
我們再來看下進程啓動的大致流程,看看這個pendingService是什麼時候被處理的。
如下圖所示爲應用的一個大致的啓動流程,AMS通過socket向Zygote進程發出啓動進程的請求,Zygote便會fork處一個應用進程,應用進程創建成功之後,便會向AMS發起binder調用,最終會執行attachApplication方法,將應用的binder對象註冊到AMS裏面,就是告訴AMS應用進程已經創建好了。
接着AMS就會調用bindApplication方法,嚮應用端發起binder調用,去通知應用進程做初始化。
我們來看下attachApplication的實現。
從註釋2中,我們可以看出最終調用了ActiveServices的attachApplicationLocked方法,而在這個方法裏面處理了pendingServices。
//ActivityManagerService
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
......
//1.調用attachApplicationLocked
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
......
}
}
//ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
......
//2.調用ActiveServices的attachApplicationLocked方法
mServices.attachApplicationLocked(app, processName);
......
}
//ActiveServices
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
//2.處理pendingServices
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
......
}
其實service的啓動流程也不復雜,下圖是service的啓動過程,可以幫助理解