安卓啟動相關以及架構設計相關
我們知道安卓大多數是服務等的啟動是伴随着init程序啟動一起啟動,這個init程序類似于linux的init,程序pid為1。
讀過安卓源碼的人都應該很熟悉init會讀取init.rc和init.xxx.rc等,想必也讀取過關于rc的相關readme。文檔中介紹了Actions、Service、Command、Options。其中我隻摘取Service的一段原文介紹(此service非framework層的service,安卓把每個由init運作的程式或者程序叫做服務,):
Services
----------------------------------------------------------------------------------------------------------------
Services are programs which init launches and(optionally) restarts when they exit. Services take the form of:
service<name> <pathname> [ <argument> ]* <option>
<option>
...
Options
----------------------------------------------------------------------------------------------------------------
介紹的很明了,服務是init運作起來的程式或者可選地重新開機當它們退出的時候。服務格式如下:
service <name> <pathname> [<argument> ]*
<option>
<option>
...
Options其中option是選項
在init中service結構體(隻顯示重要部分):
struct service {
struct listnode slist;服務連結清單,核心結構應該是雙向連結清單
const char *name;服務名稱
const char *classname;服務對應的class類
unsigned flags;
pid_t pid;程序id
uid_t uid;使用者uid
gid_t gid;組id
char *seclabel;
struct socketinfo *sockets;
struct svcenvinfo *envvars;
struct action onrestart;
};
好我們現在了解了服務,那在看看init.rc中包含的一個我們比較關注的服務(也算一個例子):
service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote 666
啟動一個名字為zygote的服務,它的路徑名為/system/bin/app_process,參數為
-Xzygote /system/bin--zygote --start-system-server,選項為socket zygote 666(打開socket)
// Everything upto '--' or first non '-' arg goes to the vm這句摘自app_main.cpp
這句是對參數-Xzygote /system/bin --zygote的一個很好的诠釋,-Xzygote是傳遞給vm的參數,而--zygote --start-system-server是傳遞給/system/bin的參數,意思是啟動system_server,其父程序是zygote。
zygote作為一個service底層通過相應的alloc和fork實作。
用adb連接配接我自己的htc裝置,然後ps顯示zygote和system_server程序如下:
從上圖看到system_server的ppid為1527,zygote的pid為1527而ppid為1,得出zygote是由init程序fork出來的,而system_server由zygote程序fork出來的。
Service啟動的四種模式
Zygote、SystemServer、Application、Tool
所有這一切構成了安卓系統的服務,在init啟動時會都被啟動起來。
從Zygote開始
zygote代碼集合
檢視過源碼的人可以了解到,zygote重要的相關代碼包含如下:
framework/base/cmds/app_main.cpp
fremework/base/core/java/com/android/internal/os/ZygoteInit.java
fremework/base/core/java/com/android/internal/os/ZygoteConnection.java
libcore/dalvik/java/dalvik/system/Zygote.java
dalvik/vm/native/ dalvik_system_Zygote.cpp
frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp
當然zygote相關代碼比顯示的要多,但是上面這些已經足夠你了解zygote了。
現在我們來講解一下zygote到底做了什麼,當然這些講解的依據是上面講到的相關zygote源碼。但是我不會具體列出流程出自哪個檔案,因為這樣講起來比較費力氣,是以我這裡隻是講解流程邏輯。
app_process創造了zygote
可以從上面的init.rc和相關Readme介紹得到,zygote是由/system/app_process這個bin加一些參數創造出來的,是以你不用在糾結什麼zygote和app_process關系。
另外一方面init程序fork出來了zygote程序,而zygote程序又相繼孵化出來了system_server程序等其他程序。
那是不是可以了解app_process就是init程序呢?這個問題我用一個例子回答你。我們從7歲開始上學到20多歲畢業,這段時間中我們經曆了國小九年義務教育,經曆了高中三年教育,經曆了大學四年教育。然後我問你,你讀高一,那麼這個高一能代表你的所有學習經曆嗎?學習就好比init程序,我們學習經曆的國小中學高中大學,就好比init一點一點一步一步做的事情,那麼通過一個可執行bin app_process啟動zygote也是其中之一的工作,當然init的工作可遠不止如此。同樣app_process也不隻創造了zygote,還做了其他事情。
看一段代碼(摘自app_main.cpp):
classAppRuntime:publicAndroidRuntime{……}
AppRuntimeruntime;
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server":"");
} elseif(className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application":"tool");
}
上面代碼(app_process)說明了AppRuntime繼承自AndroidRuntime,同時獲得AndroidRuntime執行個體。如果是zygote啟動它,怎麼啟動runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server":"");
如果不是通過傳遞過來的類的參數啟動它runtime.start("com.android.internal.os.RuntimeInit",
application ? "application":"tool");
做完這些事情app_process就壽終正寝了。
Zygote做了些什麼,ZygoteInit
init程序啟動的時候zygote被作為一種服務啟動起來,并且賦予了程序名字為zygote。
所做之事:
n SamplingProfilerIntegration.start();開啟性能監控,這個對講解沒什麼意義
n registerZygoteSocket();注冊socket
n preloadClasses();在preloaded-classes檔案中,這裡面包名了所有安卓環境需要的服務和工具和所有類,有興趣的可以去看看這個檔案。
n preloadResources();準備preloadClasses()需要的資源。
n startSystemServer();啟動system_server
n 如果是zygote 模式,runForkMode();
n 否則runSelectLoopMode();
n closeServerSocket();關閉socket
n Exception執行caller.run();
上面proloadclasses實際上并沒有真正的執行個體化類,而是僅僅加載類的vm中。
runForkMode
while (true) {
ZygoteConnection peer = acceptCommandPeer();
int pid;
pid = Zygote.fork();
if (pid == 0) {
……
peer.run();
break;
}
runForkMode 方法首先fork新的程序,并且對fork出來的程序執行run方法,那麼Zygote.fork做了什麼呢?
首先它執行nativeFork然後調用dalvik native代碼forkAndSpecializeCommon這裡我隻選擇了最重要的大家能看懂的一行代碼,其他代碼有興趣的可以去源碼中研究:
pid = fork();Linux中的經典fork。
從上面代碼可以看出Zygote确實是fork出來了程序,其中包含system_server,而且zygote作為背景程序無限的從socket接收到fork請求,來fork出新的程序。
fork出來的程序執行run方法,run方法執行runOnce,runOnce做了什麼,請看下一節。實際這裡調用這個方法它什麼都沒做。
runSelectLoopMode
這裡最主要的是它調用了runOnce,而runOnce最核心的一行代碼是:
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);
這個方法調用nativeForkAndSpecialize在調用Dalvik_dalvik_system_Zygote_fork,這裡隻是正常的fork。
SystemServer為一切安卓環境做準備
zygote啟動完成之後,它啟動了system_server,然後自己進入了fork模式等待fork新的程序。
啟動system_server
n Zygote.forkSystemServer//最終調用forkAndSpecializeCommon fork出system_server
n handleSystemServerProcess//因為invokeWith為空是以它執行了RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs)-------------------->
redirectLogStreams();//重置輸入錯誤流
commonInit();//設定時區,http代理,安裝NetworkManagementSocketTagger
nativeZygoteInit();//最終調用onZygoteInit
||sp<ProcessState>proc = ProcessState::self();
||proc->startThreadPool();//建立線程,啟動
applicationInit(targetSdkVersion,argv);//執行SystemServer的main函數,看到了沒才剛剛開始哦。
進入SystemServer類的main函數,其中主要執行了以下方法:
n System.loadLibrary("android_servers");//加載libandroid_servers.so
n init1(args);//掉用system_init();
調用system_init
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
獲得processstate執行個體,獲得servicemanager執行個體。
……
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
獲得啟動安卓的vm
JNIEnv* env = runtime->getJNIEnv();
jclass clazz = env->FindClass("com/android/server/SystemServer");
jmethodID methodId = env->GetStaticMethodID(clazz, "init2","()V");
env->CallStaticVoidMethod(clazz, methodId);
加載SystemServer類并執行init2方法
ProcessState::self()->startThreadPool();
建立一個線程,不知道為什麼google的工程師把它命名為startThreadPool
,pool很容易影響人的思維,但是當你檢視代碼的時候發現它最終就調用了一個pthread_create無非就是建立一個線程。
IPCThreadState::self()->joinThreadPool();
joinThreadPool實作有點複雜,我摘幾行最重要的代碼:
do {
……
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
result = executeCommand(cmd);
}
……
if(result == TIMED_OUT &&!isMain) {
break;
}
……
} while (result != -ECONNREFUSED && result != -EBADF);
talkWithDriver(false);
這個函數在循環中重複執行下列動作:
1.talkWithDriver 通過ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)讀取請求和寫回結果。
2.executeCommand 執行相應的請求,反正也是和binder相關的
凡是程式中包含有joinThreadPool這段代碼,它就具備和binder通訊的能力了。
有些人總是看到pool就喜歡和什麼池聯系起來,但是我看了幾遍源碼都沒看見對于池的操作,至于google為什麼這麼設計我不知道。
init2
代碼來源于SystemServer
Thread thr = new ServerThread();
thr.start();
首先ServerThread是繼承自Thread的,那麼上面這兩行我們已經很清楚了就是啟動一個線程。
線上程裡做了什麼呢,記得之前zygote啟動的時候proload中的proclasses嗎,當時隻是加載了所有的class到vm中,但是并沒有執行個體化并投入到工作中,而且zygote啟動之後進入了loop模式等待socket請求來fock新的程序,其他的事情它就撒手不管了,就交給了system_server。到現在為止,安卓的環境還沒有準備充足,什麼我們平時常常聽到了ActivityManagerService呀,什麼PackageManagerService呀,各種服務各種應用吧,凡是為安卓大多數安卓的環境這裡幾乎都準備了。
run方法
下面讓我們看一些重要的源碼吧(感興趣的可以自己仔細研習代碼):
……
Looper.prepareMainLooper();
準備loop,進入loop
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
BinderInternal.disableBackgroundScheduling(true);
設定程序優先權,設定binder禁止内部背景排程
……
HandlerThread uiHandlerThread = newHandlerThread("UI");
uiHandlerThread.start();
Handler uiHandler = new Handler(uiHandlerThread.getLooper());
uiHandler.post();
HandlerThread wmHandlerThread = newHandlerThread("WindowManager");
wmHandlerThread.start();
Handler wmHandler = newHandler(wmHandlerThread.getLooper());
wmHandler.post();
UI和WindowManager進入handle狀态
下面就是執行個體化各種服務了,其中包含執行個體化,向ServiceManager中注冊服務,調用各種服務類的核心方法等。代碼太一目了然了,順着代碼你可以去相關類去看具體方法,進而能得知所有啟動過程和調用方法執行了什麼。
installer = new Installer();
installer.ping();
ServiceManager.addService("entropy",newEntropyMixer());
power = new PowerManagerService();
//電源管理
ServiceManager.addService(Context.POWER_SERVICE,power);
context =ActivityManagerService.main(factoryTest);
display = newDisplayManagerService(context, wmHandler, uiHandler);
ServiceManager.addService(Context.DISPLAY_SERVICE,display, true);
telephonyRegistry = newTelephonyRegistry(context);
ServiceManager.addService("telephony.registry",telephonyRegistry);
ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
new SchedulingPolicyService());
……
pm =PackageManagerService.main(context, installer,
factoryTest !=SystemServer.FACTORY_TEST_OFF,
onlyCore);
//包管理
ActivityManagerService.setSystemProcess();
ServiceManager.addService(Context.USER_SERVICE,
UserManagerService.getInstance());
mContentResolver= context.getContentResolver();
accountManager = newAccountManagerService(context);
ServiceManager.addService(Context.ACCOUNT_SERVICE,accountManager);
……實在是太多ManagerService和太多的Service了,不寫了自己去看吧
power.systemReady(twilight, dreamy);
pm.systemReady();
……各種ready各種初始化各種調用主要函數不寫了
startSystemUi(contextF);
context.startServiceAsUser(intent,UserHandle.OWNER);
啟動系統UI
Looper.loop();
進入loop模式,handleMessage去了。後面略。
至此SystemServer就算講完了,通過上面你應該知道它是什麼時候被啟動的已經啟動後它做了些什麼。
ServiceManager
ServiceManager是做什麼的呢,其實它就是一個管理framework層各種服務的。它内部有一個結構體,是一個連結清單結構,每個節點對應一個服務,當執行SystemServer時它的run方法裡面的所有服務都會向ServiceManager進行注冊。
一個服務本身并不完全由純java編寫,也許有一些是這樣,因為我并沒有看過所有代碼不敢妄斷,但是通常一個服務是由java和jni和native代碼一起編寫。而且通常狀态下如果一個service會為上層應用提供服務那麼這個service通常會有一個binder的stub,這個stub叫做樁,類似于代理但是又不能說是代理,這是rpc協定和機理所緻。如果做過java rpc的人或許會對此并不陌生。
通用規則:
所有的XXXManager都是作為XXX的管理者。
所有的XXXManagerService或者XXXService幾乎都是作為XXX類型對上層通過binder通訊而為其服務的獨立程序。
svcinfo結構體
struct svcinfo
{
structsvcinfo *next;下一個服務
void*ptr;服務指向的位址
structbinder_deathdeath;
intallow_isolated;
unsignedlen;
uint16_t name[0];服務名稱
};
structsvcinfo *svclist = 0;
這個結構體就是一個對應service list的結構體,它裡面包含所有服務。初始時這個連結清單為0也就是NULL。
servicemanager提供的方法
查找服務、添加服務、釋放svc結構、處理svc其中包含(查找服務、添加服務、檢查服務、列出所有服務、獲得服務)。
通過讀取servicemanager的main函數我們得知它首先打開了binder,并且把自己變成了BINDER_SERVICE_MANAGER,然後進入了無限循環狀态,等待其他service的binder通訊,它負責各個service之間的通訊通過binder,它作為了一個橋梁。
binder相關
首先binder作為一種驅動設計,用于程序間通訊,使用rpc協定。遵循linux驅動設計。在類unix世界一切皆檔案,所有你能在binder相關源檔案看到,通路binder和通路檔案一樣通過一個open就可以了,使用者層和binder的通訊指令借助底層實作的ioctl函數。
因為安卓世界裡,幾乎每一個service都是作為獨立程序運作的,都是由zygote程序fork出來的,所有各個程序是獨立的,他們有自己的程序空間,是以為了彼此通訊,安卓設計了有别的binder機制。