文章目錄
本文基於的是Android 8.0源碼。
1、Activity中調用startService
我們啓動service的時候都是直接在Activity裏面調用startService
方法,這裏實際上調用的是ContextImpl#startService
方法。
我們知道,Activity繼承自ContextThemeWrappe
,ContextThemeWrapper又繼承自ContextWrapper
,ContextWrapper只是Context的靜態代理
,Context的實現類就是ContextImpl
。在創建Activity之後,系統會調用Activity#attach
方法,將創建好的ContextImpl實例對象設置給Activity,所以在Activity中調用的Context對象的方法基本上都會走ContextImpl中的實現。
2、ContextImpl#startService
ContextImpl#startService
--> ContextImpl#startServiceCommon
--> ActivityManagerService#startService(通過AMS的Binder對象調用)
3、ActivityManagerService#startService
我們接着看ActivityManagerService#startService
方法,
ActivityManagerService#startService
--> ActiveService#startServiceLocked(根據當前服務對象生成一個ServiceRecord.StartItem對象,添加進pendingStarts中,用於後面的onStartCommand方法調用)
--> ActiveService#startServiceInnerLocked
--> ActiveService#bringUpServiceLocked
這裏的ActiveService#bringUpServiceLocked
方法是核心,我們看下關鍵代碼:
這裏我們把代碼分爲四部分,註釋中說明了核心邏輯。
private String bringUpServiceLocked(ServiceRecord r, ...){
// 1
// 如果條件滿足,說明服務也已經啓動過,因此服務對應的進程已經啓動,該進程對應的ActivityThread也已經準備好,接下來直接通知應用進程調用service的onStartCommand方法即可。
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// 2
// 走到這裏說明服務沒有啓動過,我們先查看服務所在的進程是否已經啓動
// 如果進程已經啓動,並且ActivityThread也已經準備好,則啓動服務。
ProcessRecord app = mAm.getProcessRecordLocked(procName,...);
if (app != null && app.thread != null) {
realStartServiceLocked(r, app, execInFg);
}
// 3
// 如果服務所在的進程沒啓動,則啓動進程
if (app == null) {
app=mAm.startProcessLocked(procName,...)
}
// 4 將服務添加進mPendingServices列表中,等待應用啓動之後再啓動服務
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return null;
}
上面的流程可以用下面這個圖概括:
接下來我們講細節,如何啓動進程,以及進程啓動後如何啓動服務
。
4、啓動進程,執行mPendingServices中的服務
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
方法的主要作用就是將傳入的應用進程的啓動參數argsForZygote寫入ZygoteState中,ZygoteState是ZygoteProcess的靜態內部類,用於表示與Zygote進程通信的狀態。
再看下openZygoteSocketIfNeeded
方法,該方法內部會調用ZygoteState.connect(mSocket)
方法,與Zygote進程建立Socket連接。
Zygote進程的Socket——接收創建進程的消息,fork創建子進程
我們接下來看下Zygote進程裏面啓動的Socket,我們先看ZygoteInit#main函數:
這裏我們只看跟Socket相關的
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
String socketName = "zygote";
// 啓動名稱爲zygote的Socket
zygoteServer.registerServerSocket(socketName);
// 開啓while循環,接收Socket消息並處理
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
}
Socket接收消息的邏輯在ZygoteServer.runSelectLoop
方法中,接收到消息後會調用ZygoteConnection#runOnce方法,我們還是看關鍵代碼:
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 {
...
}
}
先調用Zygote#forkAndSpecialize方法啓動進程,fork方法會返回兩次,pid爲0表示是我們關心的子進程,然後調用Zygote#handleChildProc
方法進行處理,Zygote#handleChildProc
方法裏面會調用ZygoteInit.zygoteInit
方法,它的關鍵代碼如下:
public static final void zygoteInit(int targetSdkVersion,...){
RuntimeInit.commonInit();
// 給應用進程創建Binder線程池
ZygoteInit.nativeZygoteInit();
// 調用進程的ActivityThread#main方法
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
RuntimeInit#applicationInit
方法會調用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
方法的作用很清晰,就是調用其入參className的main(argv[])方法,這裏的className的值就是android.app.ActivityThread
。
ActivityThread#main——通知AMS進程創建完成,初始化Application,
Zygote在啓動我們的應用進程後,會調用進程的入口函數android.app.ActivityThread#main
。接下來我們看下ActivityThread#main
是如何啓動服務的。
ActivityThread#main
--> ActivityThread#attach
--> ActivityManagerService#attachApplication(mAppThread)
ActivityManagerService#attachApplication方法會將應用進程的ActivityThread的Binder對象上報給AMS,這樣AMS和應用進程就可以開始雙向調用了。接着往下看:
ActivityManagerService#attachApplication(mAppThread)
--> ActivityThread#bindApplication(通過Binder調用ActivityThread的方法)
--> ActivityThread#handleBindApplication(通過Handler切換到主線程)
初始化Application實例
在ActivityThread#handleBindApplication
方法中,通過調用LoadedApk#makeApplication
來創建Application對象,並調用其生命週期方法,LoadedApk#makeApplication的核心代碼如下:
public Application makeApplication(...) {
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(...);
appContext.setOuterContext(app);
// 調用Application#onCreate方法
instrumentation.callApplicationOnCreate(app);
return app;
}
創建Application對象的具體流程如下:
LoadedApk#makeApplication
--> Instrumentation#newApplication
--> Instrumentation#newApplication(重載方法) 初始化Application實例
--> Application#attach
--> Application#attachBaseContext
至此我們的應用進程和Application均初始化完畢,我們看下如何在進程啓動後啓動之前放置在mPendingServices中的服務的。
ActivityManagerService#attachApplicationLocked——進程啓動後啓動服務
前面說過,進程啓動以後,ActivityThread會向AMS上報,會調用到ActivityManagerService#attachApplicationLocked
方法,還是老規矩,我們只看相關的核心內容:
private final boolean attachApplicationLocked(IApplicationThread thread,...) {
// 調用應用端的ActivityThread#bindApplication方法,完成Application初始化
thread.bindApplication(processName, ...);
// Find any services that should be running in this process...
// 調用ActiveServices#attachApplicationLocked方法,執行mPendingServices中的服務
didSomething |= mServices.attachApplicationLocked(app, processName);
}
ActiveServices#attachApplicationLocked方法中,會遍歷mPendingServices,對每個service都執行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調用ActivityThread#scheduleCreateService
方法,告訴應用啓動Service;接着還會調用ActiveServices#sendServiceArgsLocked
方法,通過Binder調用ActivityThread#scheduleServiceArgs
方法,最終調用Service#onStartCommand方法,下面看下細節。
啓動服務——ActivityThread#scheduleCreateService
調用鏈如下:
ActivityThread#scheduleCreateService
--> 發送`H.CREATE_SERVICE`消息給主線程
--> ActivityThread#handleCreateService
在ActivityThread#handleCreateService
方法裏面會初始化Service類,調用其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);
// 獲取對應的Application對象
Application app = packageInfo.makeApplication(false, ...);
// 調用Service#onCreate()方法
service.onCreate();
}
調用服務的onStartCommand——ActivityThread#scheduleServiceArgs
調用鏈如下:
ActivityThread#scheduleServiceArgs
--> 發送`H.SERVICE_ARGS`消息給主線程
--> ActivityThread#handleServiceArgs
--> Service#onStartCommand
至此第一次啓動應用 + 啓動服務
的總體過程完成。
流程總結
至此,一次完整的startService過程的關鍵步驟分析完畢。