Android應用程式程序啟動過程(後篇)
前言
在前篇中我們講到了Android應用程式程序啟動過程,這一篇我們來講遺留的知識點:在應用程式程序建立過程中會啟動Binder執行緒池以及在應用程式程序啟動後會建立訊息迴圈。
1.Binder執行緒池啟動過程
我們首先來看RuntimeInit類的zygoteInit函式,如下所示
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();//1
applicationInit(targetSdkVersion, argv, classLoader);
}
註釋1處會在新建立的應用程式程序中建立Binder執行緒池,來檢視nativeZygoteInit函式:
private static final native void nativeZygoteInit();
很明顯nativeZygoteInit是一個jni方法,它對應的函式是什麼呢。在 AndroidRuntime.cpp的JNINativeMethod陣列中我們得知它對應的函式是com_android_internal_os_RuntimeInit_nativeZygoteInit,如下所示。
frameworks/base/core/jni/AndroidRuntime.cpp
static const JNINativeMethod gMethods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
{ "nativeSetExitWithoutCleanup", "(Z)V",
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};
接著來檢視 com_android_internal_os_RuntimeInit_nativeZygoteInit函式:
frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
gCurRuntime是在AndroidRuntime初始化就建立的。如下所示。
frameworks/base/core/jni/AndroidRuntime.cpp
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
...
gCurRuntime = this;
}
在Android系統啟動流程(二)解析Zygote程序啟動過程這篇文章我們得知AppRuntime繼承AndroidRuntime,AppRuntime建立時就會呼叫AndroidRuntime的建構函式,gCurRuntime就會被初始化,它指向的是AppRuntime,因此我們來檢視AppRuntime的onZygoteInit函式,AppRuntime的實現在app_main.cpp中,如下所示。
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
最後一行會呼叫ProcessState的startThreadPool函式:
frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
支援Binder通訊的程序中都有一個ProcessState類,它裡面有一個mThreadPoolStarted 變數,來表示Binder執行緒池是否已經被啟動過,預設值為false。在每次呼叫這個函式時都會先去檢查這個標記,從而確保Binder執行緒池只會被啟動一次。如果Binder執行緒池未被啟動則設定mThreadPoolStarted為true,最後呼叫spawnPooledThread函式來建立執行緒池中的第一個執行緒,也就是執行緒池的main執行緒,如下所示。
frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());//1
}
}
可以看到Binder執行緒為一個PoolThread。註釋1呼叫PoolThread的run函式來啟動一個啟動一個新的執行緒。來檢視PoolThread類裡做了什麼:
frameworks/native/libs/binder/ProcessState.cpp
class PoolThread : public Thread
{
..
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);//1
return false;
}
const bool mIsMain;
};
PoolThread類繼承了Thread類。註釋1處會將呼叫IPCThreadState的joinThreadPool函式,將當前執行緒註冊到Binder驅動程式中,這樣我們建立的執行緒就加入了Binder執行緒池中,這樣新建立的應用程式程序就支援Binder程序間通訊了,Binder執行緒池啟動過程就講到這,接下來我們來學習訊息迴圈建立過程。
2.訊息迴圈建立過程
首先我們回到上篇最後講到的RuntimeInit的invokeStaticMain函式,程式碼如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
invokeStaticMain函式在上篇已經講過,這裡不再贅述,主要是看最後一行,會丟擲一個MethodAndArgsCaller異常,這個異常會被ZygoteInit的main函式捕獲,如下所示。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...
try {
...
} catch (MethodAndArgsCaller caller) {
caller.run();//1
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
註釋1處捕獲到MethodAndArgsCaller 時會執行caller的run函式,如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static class MethodAndArgsCaller extends Exception
implements Runnable {
private final Method mMethod;
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });//1
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
...
throw new RuntimeException(ex);
}
}
}
根據上一篇文章我們得知,mMethod指的就是ActivityThread的main函式,mArgs 指的是應用程式程序的啟動引數。在註釋1處呼叫ActivityThread的main函式,程式碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
...
Looper.prepareMainLooper();//1
ActivityThread thread = new ActivityThread();//2
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//3
throw new RuntimeException("Main thread loop unexpectedly exited");
}
註釋1處在當前應用程式程序中建立訊息迴圈,註釋2處建立ActivityThread,註釋3處呼叫Looper的loop,使得Looper開始工作,開始處理訊息。可以看出,系統在應用程式程序啟動完成後,就會建立一個訊息迴圈,用來方便的使用Android的訊息處理機制。
歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。