本文基于的是Android 8.0源碼。
1炫掐、Activity中調(diào)用startService
我們啟動service的時候都是直接在Activity里面調(diào)用startService
方法崭歧,這里實際上調(diào)用的是ContextImpl#startService
方法。
我們知道秤茅,Activity繼承自ContextThemeWrappe
彻秆,ContextThemeWrapper又繼承自ContextWrapper
,ContextWrapper只是Context的靜態(tài)代理
蛇耀,Context的實現(xiàn)類就是ContextImpl
辩诞。在創(chuàng)建Activity之后,系統(tǒng)會調(diào)用Activity#attach
方法纺涤,將創(chuàng)建好的ContextImpl實例對象設(shè)置給Activity译暂,所以在Activity中調(diào)用的Context對象的方法基本上都會走ContextImpl中的實現(xiàn)。
2撩炊、ContextImpl#startService
ContextImpl#startService
--> ContextImpl#startServiceCommon
--> ActivityManagerService#startService(通過AMS的Binder對象調(diào)用)
3外永、ActivityManagerService#startService
我們接著看ActivityManagerService#startService
方法,
ActivityManagerService#startService
--> ActiveService#startServiceLocked(根據(jù)當前服務(wù)對象生成一個ServiceRecord.StartItem對象拧咳,添加進pendingStarts中伯顶,用于后面的onStartCommand方法調(diào)用)
--> ActiveService#startServiceInnerLocked
--> ActiveService#bringUpServiceLocked
這里的ActiveService#bringUpServiceLocked
方法是核心,我們看下關(guān)鍵代碼:
這里我們把代碼分為四部分呛踊,注釋中說明了核心邏輯砾淌。
private String bringUpServiceLocked(ServiceRecord r, ...){
// 1
// 如果條件滿足,說明服務(wù)也已經(jīng)啟動過谭网,因此服務(wù)對應(yīng)的進程已經(jīng)啟動汪厨,該進程對應(yīng)的ActivityThread也已經(jīng)準備好,接下來直接通知應(yīng)用進程調(diào)用service的onStartCommand方法即可愉择。
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// 2
// 走到這里說明服務(wù)沒有啟動過劫乱,我們先查看服務(wù)所在的進程是否已經(jīng)啟動
// 如果進程已經(jīng)啟動,并且ActivityThread也已經(jīng)準備好锥涕,則啟動服務(wù)衷戈。
ProcessRecord app = mAm.getProcessRecordLocked(procName,...);
if (app != null && app.thread != null) {
realStartServiceLocked(r, app, execInFg);
}
// 3
// 如果服務(wù)所在的進程沒啟動,則啟動進程
if (app == null) {
app=mAm.startProcessLocked(procName,...)
}
// 4 將服務(wù)添加進mPendingServices列表中层坠,等待應(yīng)用啟動之后再啟動服務(wù)
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return null;
}
上面的流程可以用下面這個圖概括:
接下來我們講細節(jié)殖妇,如何啟動進程,以及進程啟動后如何啟動服務(wù)
破花。
4谦趣、啟動進程,執(zhí)行mPendingServices中的服務(wù)
Zygote啟動進程
在ActiveService#bringUpServiceLocked
方法中座每,啟動進程的代碼如下:
app=mAm.startProcessLocked(procName,...)
接著往下看:
ActivityManagerService#startProcessLocked
--> ActivityManagerService#startProcessLocked(重載方法)
--> ActivityManagerService#startProcessLocked(重載方法)
--> Process.start
--> ZygoteProcess.start
--> ZygoteProcess.startViaZygote
我們看下ZygoteProcess.startViaZygote
方法前鹅,代碼如下:
private Process.ProcessStartResult startViaZygote(final String processClass,...){
ArrayList<String> argsForZygote = new ArrayList<String>();
...
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
zygoteSendArgsAndGetResult
方法的主要作用就是將傳入的應(yīng)用進程的啟動參數(shù)argsForZygote寫入ZygoteState中,ZygoteState是ZygoteProcess的靜態(tài)內(nèi)部類峭梳,用于表示與Zygote進程通信的狀態(tài)舰绘。
再看下openZygoteSocketIfNeeded
方法,該方法內(nèi)部會調(diào)用ZygoteState.connect(mSocket)
方法,與Zygote進程建立Socket連接捂寿。
Zygote進程的Socket——接收創(chuàng)建進程的消息口四,fork創(chuàng)建子進程
我們接下來看下Zygote進程里面啟動的Socket,我們先看ZygoteInit#main函數(shù):
這里我們只看跟Socket相關(guān)的
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
String socketName = "zygote";
// 啟動名稱為zygote的Socket
zygoteServer.registerServerSocket(socketName);
// 開啟while循環(huán)者蠕,接收Socket消息并處理
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
}
Socket接收消息的邏輯在ZygoteServer.runSelectLoop
方法中窃祝,接收到消息后會調(diào)用ZygoteConnection#runOnce方法掐松,我們還是看關(guān)鍵代碼:
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
Arguments parsedArgs = null;
pid = Zygote.forkAndSpecialize(parsedArgs.uid,...);
if (pid == 0) {
// in child
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
...
}
}
先調(diào)用Zygote#forkAndSpecialize方法啟動進程踱侣,fork方法會返回兩次,pid為0表示是我們關(guān)心的子進程大磺,然后調(diào)用Zygote#handleChildProc
方法進行處理抡句,Zygote#handleChildProc
方法里面會調(diào)用ZygoteInit.zygoteInit
方法,它的關(guān)鍵代碼如下:
public static final void zygoteInit(int targetSdkVersion,...){
RuntimeInit.commonInit();
// 給應(yīng)用進程創(chuàng)建Binder線程池
ZygoteInit.nativeZygoteInit();
// 調(diào)用進程的ActivityThread#main方法
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
RuntimeInit#applicationInit
方法會調(diào)用RuntimeInit#invokeStaticMain
方法杠愧,具體代碼如下:
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new Zygote.MethodAndArgsCaller(m, argv);
}
RuntimeInit#invokeStaticMain
方法的作用很清晰待榔,就是調(diào)用其入?yún)lassName的main(argv[])方法,這里的className的值就是android.app.ActivityThread
流济。
ActivityThread#main——通知AMS進程創(chuàng)建完成锐锣,初始化Application,
Zygote在啟動我們的應(yīng)用進程后绳瘟,會調(diào)用進程的入口函數(shù)android.app.ActivityThread#main
雕憔。接下來我們看下ActivityThread#main
是如何啟動服務(wù)的。
ActivityThread#main
--> ActivityThread#attach
--> ActivityManagerService#attachApplication(mAppThread)
ActivityManagerService#attachApplication方法會將應(yīng)用進程的ActivityThread的Binder對象上報給AMS糖声,這樣AMS和應(yīng)用進程就可以開始雙向調(diào)用了斤彼。接著往下看:
ActivityManagerService#attachApplication(mAppThread)
--> ActivityThread#bindApplication(通過Binder調(diào)用ActivityThread的方法)
--> ActivityThread#handleBindApplication(通過Handler切換到主線程)
初始化Application實例
在ActivityThread#handleBindApplication
方法中,通過調(diào)用LoadedApk#makeApplication
來創(chuàng)建Application對象蘸泻,并調(diào)用其生命周期方法琉苇,LoadedApk#makeApplication的核心代碼如下:
public Application makeApplication(...) {
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(...);
appContext.setOuterContext(app);
// 調(diào)用Application#onCreate方法
instrumentation.callApplicationOnCreate(app);
return app;
}
創(chuàng)建Application對象的具體流程如下:
LoadedApk#makeApplication
--> Instrumentation#newApplication
--> Instrumentation#newApplication(重載方法) 初始化Application實例
--> Application#attach
--> Application#attachBaseContext
至此我們的應(yīng)用進程和Application均初始化完畢,我們看下如何在進程啟動后啟動之前放置在mPendingServices中的服務(wù)的悦施。
ActivityManagerService#attachApplicationLocked——進程啟動后啟動服務(wù)
前面說過并扇,進程啟動以后,ActivityThread會向AMS上報抡诞,會調(diào)用到ActivityManagerService#attachApplicationLocked
方法穷蛹,還是老規(guī)矩,我們只看相關(guān)的核心內(nèi)容:
private final boolean attachApplicationLocked(IApplicationThread thread沐绒,...) {
// 調(diào)用應(yīng)用端的ActivityThread#bindApplication方法俩莽,完成Application初始化
thread.bindApplication(processName, ...);
// Find any services that should be running in this process...
// 調(diào)用ActiveServices#attachApplicationLocked方法,執(zhí)行mPendingServices中的服務(wù)
didSomething |= mServices.attachApplicationLocked(app, processName);
}
ActiveServices#attachApplicationLocked方法中乔遮,會遍歷mPendingServices扮超,對每個service都執(zhí)行ActiveServices#realStartServiceLocked
方法,具體代碼如下:
boolean attachApplicationLocked(ProcessRecord proc, String processName){
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
mPendingServices.remove(i);
i--;
realStartServiceLocked(sr, proc, sr.createdFromFg);
}
}
}
在ActiveServices#realStartServiceLocked
方法中,會通過Binder調(diào)用ActivityThread#scheduleCreateService
方法出刷,告訴應(yīng)用啟動Service璧疗;接著還會調(diào)用ActiveServices#sendServiceArgsLocked
方法,通過Binder調(diào)用ActivityThread#scheduleServiceArgs
方法馁龟,最終調(diào)用Service#onStartCommand方法崩侠,下面看下細節(jié)。
啟動服務(wù)——ActivityThread#scheduleCreateService
調(diào)用鏈如下:
ActivityThread#scheduleCreateService
--> 發(fā)送`H.CREATE_SERVICE`消息給主線程
--> ActivityThread#handleCreateService
在ActivityThread#handleCreateService
方法里面會初始化Service類坷檩,調(diào)用其onCreate方法却音。核心代碼如下:
private void handleCreateService(CreateServiceData data) {
// 初始化Service對象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
Service service = (Service) cl.loadClass(data.info.name).newInstance();
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
// 獲取對應(yīng)的Application對象
Application app = packageInfo.makeApplication(false, ...);
// 調(diào)用Service#onCreate()方法
service.onCreate();
}
調(diào)用服務(wù)的onStartCommand——ActivityThread#scheduleServiceArgs
調(diào)用鏈如下:
ActivityThread#scheduleServiceArgs
--> 發(fā)送`H.SERVICE_ARGS`消息給主線程
--> ActivityThread#handleServiceArgs
--> Service#onStartCommand
至此第一次啟動應(yīng)用 + 啟動服務(wù)
的總體過程完成。
流程總結(jié)
至此矢炼,一次完整的startService過程的關(guān)鍵步驟分析完畢系瓢。