整個Android系統的啟動分為Linux Kernel的啟動和Android系統的啟動。Linux Kernel啟動起來后,然后運行第一個用戶程序,在Android中就是init程序。
-------------------------------------------------
以下的內容應該算是學習筆記,特地整理成文。
-------------------------------------------------
1 init程序
init是linux系統中用戶空間的第一個進程。由於Android是基於linux內核的,所以init也是Android系統中用戶空間的第一個進程,它的進程號是1。init程序並不是由一個源文件組成的,而是由一組源代碼文件的目標文件鏈接而成,這些文件位於如下目錄:
<android source code directory>/system/core/init/
它的主要職責在於:
1)、掛載目錄,比如/sys, /dev, /proc
mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); ......
2)、初始化屬性,提供property service(屬性服務)管理Android系統中的屬性
3)、處理配置文件命令(主要是init.rc腳本文件)
4)、性能分析和執行其它進程
2.1 init分析
init進程的入口函數是main,主要做了這些工作:
1)、解析配置文件,主要是系統配置文件init.rc和與硬件平台相關的配置文件(如init.xxx.rc),在此階段,也會解析service。
init.rc文件包含五個類型的聲明:
- Actions(動作以命令流程命名,有一個觸發器決定動作是否發生)
-
on <trigger> <command> <command>
- Commands
-
class_start <serviceclass> Start all services of the specified class if they are not already running
- Services(是init進程啟動的程序,以及當服務退出時init進程會視情況重啟服務)
- Options(選項是對服務的描述,它們影響init進程如何以及何時啟動服務)
-
service <name> <pathname> [ <argument> ]* <option> <option>
- Imports
-
import <path> Parse an init config file, extending the current configuration.
Action | Service | 描述 |
on | early-init | 設置init進程以及它創建的子進程的優先級,設置init進程的安全環境 |
on | init | 設置全局環境,為cpu accounting創建cgroup(資源控制)掛載點 |
on | fs | 掛載mtd分區 |
on | post-fs | 改變系統目錄的訪問權限 |
on | post-fs-data | 改變/data目錄以及它的子目錄的訪問權限 |
on | boot | 基本網絡的初始化,內存管理等等 |
service | servicemanager | 啟動系統管理器管理所有的本地服務,比如位置、音頻、Shared preference等等 |
service | zygote | 啟動zygote作為應用進程 |
2)、執行各個階段的動作,創建zygote的工作就是在其中某個階段完成。
3)、調用property_init初始化屬性相關的資源,並且通過property_start_service啟動屬性服務。
4)、init進入一個無限循環,然后等待響應。
2.2 屬性服務
應用程序可以通過這個屬性機制,查詢或設置屬性。這個屬性服務是怎么實現的呢?其中與init.c和屬性服務有關的代碼:
property_init();
property_set_fd = start_property_service();
2.2.1 屬性服務初始化
首先創建存儲空間,property_service.c中有property_init函數
void property_init(void){ init_property_area(); // 初始化屬性存儲區域 // 加載default.prop文件 load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT); }
雖然屬性區域是由init進程創建的,但Android系統希望其它進程也能讀取這塊內存里的東西。為了做到這一點,它做了以下的工作:
1)、把屬性區域創建在共享內存上,而共享內存是可以跨進程的。
2)、Android利用gcc的constructor屬性,指明了一個__libc_prenit函數,當bionic libc庫被加載時,將自動調用這個__libc_preni,這個函數內部就將完成共享內存到本地進程的映射工作。這樣一來,其它進程就知道了這個共享內存。
接着,客戶端進程獲取存儲空間。
2.2.2 屬性服務器的分析
2.2.2.1 啟動屬性服務器
init進程會啟動一個屬性服務器,而客戶端只能通過與屬性服務器交互來設置屬性。
2.2.2.2 處理設置屬性請求
接受請求的地方在init進程中,當屬性服務器收到客戶端請求時,init會調用handle_property_set_fd進行處理。
if(ufds[1].revents == POLLIN){ handle_property_set_fd(property_set_fd); }
當客戶端的權限滿足要求時,init就調用property_set進行相關處理。
if(check_perms(msg.name, cr.uid, cr.gid)){ property_set((char *) msg.name, (char *) msg.value); }
2.2.2.3 客戶端發送請求
客戶端通過property_set發送請求,property_set由libcutils庫提供。
int property_set(const chatr *key, const char *value){ prop_msg msg; unsigned resp; // other code ...... msg.cmd = PROP_MSG_SETPROP; // 設置消息碼 strcpy((char *) msg.name, key); strcpy((char *) msg.value, value); // 發送請求 return send_prop_msg(&msg); }
static int send_prop_msg(prop_msg *msg){ int s; int r; // 建立和屬性服務器的socket鏈接 s = socket_local_client(PROP_SERVICE_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if(s < 0){ return -1; } // 通過socket發送 while((r = send(s, msg, sizeof(prop_msg), 0)) < 0){ if((errno == EINTR) || (errno == EAGAIN)){ continue; } break; } if(r == sizeof(prop_msg)){ r = 0; } else { r = -1; } close(s); return r; }
2 zygote分析
zygote本身是一個Native的應用程序,與驅動、內核等無關。它是由init進程根據init.rc文件中的配置創建的。zygote最初的名字叫“app_process”,這個名字是在Android.mk文件中指定的。在運行中,app_process通過linux下的pctrl系統調用將自己的名字換成了zygote。
在Java中,我們知道不同的虛擬機實例會為不同的應用分配不同的內存。假如Android應用應該盡可能快地啟動,但如果Android系統為每一個應用啟動不同的Dalvik虛擬機實例,就會消耗大量的內存以及時間。因此,為了克服這個問題,Android系統創造了”zygote”。zygote讓Dalvik虛擬機共享代碼、低內存占用以及最小的啟動時間成為可能。
zygote進程由init通過fork而來,在init.rc中設置的啟動參數如下:
-Xzygote /system/bin --zygote --start-system-server
zygote的原型app_process對應的源文件是App_main.cpp。
int main(int argc, const char* const argv[]){ ...... AppRuntime runtime; ...... int i = runtime.addVmArguments(argc, argv); if(i < argc){ runtime.mParentDir = argv[i++]; } if(i < argc){ arg = argv[i++]; if(0 == strcmp("--zygote", arg)){ bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0: false; setArgv0(argv0, "zygote"); set_process_name("zygote"); // 設置進程名 runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); } ...... } ...... }
2.1 AppRuntime分析
AppRuntime從AndroidRuntime類派生,它的聲明和實現在App_main.cpp中。AppRuntime重載了onStarted, onZygoteInit和onExit函數。其中AndroidRuntime::start(const char* className, const bool startSystemServer)函數做了幾件事情:
2.1.1 創建虛擬機--startVm
int AndroidRuntime::startVm(JavaVm** pJavaVM, JNIEnv** pEnv){ // JNI check是指Native層調用JNI函數時,系統所做的一些檢查工作。例如,調用NewUTFString函數時,系統會檢查傳入的字符串是不是符合UTF-8的要求。 property_get("dalvik.vm.checkjni", propBuf, ""); ...... // 設置虛擬機的heapsize,默認為16MB strcpy(heapsizeOptsBuf, "-Xmx"); property_get("dalvik.vm.heapsize", heapsizeOptsBuf + 4, "16m"); ...... if(checkJni){ opt.optionsString = "-Xcheck:jni"; mOptions.add(opt); // JNI check中的資源檢查,系統中創建的Global Reference個數不能超過2000 opt.optionString = "-Xjnigreflimit:2000"; mOptions.add(opt); } // 調用JNI_CreateJavaVM創建虛擬機,pEnv返回當前線程的JNIEnv變量 if(JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0){ goto bail; } return 0; bail: free(stackTraceFile); return result; }
2.1.2 注冊JNI函數--startReg
int AndroidRuntime::startReg(JNIEnv* env){ ...... if(register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0){ env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); return 0; }
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){ for(size_t i = 0; i < count; i++){ if(array[i].mProc(env) < 0){ return -1; } } return 0; }
statci const RegJNIRec gRegJNI[] = { REG_JNI(register_android_debug_JNITest), REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_android_os_SystemClock), ...... }
上面的mProc就是為Java類注冊JNI函數。
2.1.3 通過JNI調用Java函數,進入Java世界
env->CallStaticVoidMethod(startClass, startMeth, strArray);
CallStaticVoidMethod最終將調用com.android.internal.os.ZygoteInit的main函數。
public static void main(String argv[]){ try{ SamplingProfilerIntegration.start(); // 1. 注冊zygote用的socket. 基於AF_UNIX類型,是一個本機socket registerZygoteSocket(); // 2. 預加載類和資源 preloadClasses(); preloadResources(); ...... // 強制執行一次垃圾回收 gc(); if(argv[1].equals("true")){ startSystemServer(); // 3. 啟動system_server進程。該進程是framework的核心。 } else if(!argv[1].equals("false")){ throw new RuntimeException(argv[0] + USAGE_STRING); } if(ZYGOTE_FORK_MODE){ runForkMode(); } else { runSelectLoopMode(); // 4. zygote調用這個函數,進入等待喚醒的狀態 } closeServerSocket(); } catch(MethodAndArgsCaller caller){ caller.run(); } catch(RuntimeException ex){ closeServerSocket(); throw ex; } ...... }
3 SystemServer分析
SystemServer是由Zygote通過Zygote.forkSystemServer函數fork出來的。
pid = Zygote.forkSystemServer(); if(pid == 0){ // 子進程返回0,即systemServer handleSystemServerProcess(parseArgs); }
在handleSystemServerProcess函數中,首先會關閉從Zygote繼承下來的socket,並設置SystemServer進程的一些參數,然后調用RuntimeInit.java中的ZygoteInit函數。
public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { commonInit(); // native層的初始化 zygoteInitNative(); ...... invokeStaticMain(startClass, startArgs); // 調用com.android.server.SystemServer類的main函數 }
SystemServer調用了zygoteInitNative后,將與Binder通信系統建立聯系,這樣SystemServer就可以使用Binder了。zygoteInitNative中調用了onZygoteInit()
virtual void onZygoteInit(){ sp<ProcessState> proc = ProcessState::self(); if(proc->supportsProcesses()){ proc->startThreadPool(); // 啟動一個線程,用於Binder通信 } }
而另外一個關鍵函數invokeStaticMain
private static void invokeStaticMain(String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { // 參數傳入,className = "com.android.server.SystemServer" ...... Method m; try{ m = cl.getMethod("main", new Class[] { String[].class }); // 找到com.android.server.SystemServer類的main函數 } catch(NoSuchMethodException ex){ ...... } catch(SecurityException ex){ ...... } ...... throw new ZygoteInit.MethodAndArgsCaller(m, argv); // 主動拋出一個異常 }
拋出的異常在哪里被捕獲呢?上面已經給出過了。也就是在ZygoteInit.java中
...... catch(MethodAndArgsCaller caller){ caller.run(); // 調用caller的run函數 }
而MethodAndArgsCaller的run函數如下:
public void run(){ try{ mMethod.invoke(null, new Object[] { mArgs }); // mMethod為com.android.server.SystemServer的main函數 } catch(IllegalAccessException ex){ ...... } }
為什么要主動拋出這樣一個異常來執行main函數呢?
《深入理解Android 卷I》中是這樣解釋的:這個調用是在ZygoteInit.main中,相當於Native的main函數,也即入口函數,位於堆棧的頂層。如果不采用拋異常的方式,而是在invokeStaticMain那調用,則會浪費之前函數調用所占用的一些調用堆棧。
那么,這個main函數又做了什么工作呢?
public static void main(String[] args){ System.loadLibrary("android_servers"); // 加載libandroid_servers.so init1(args); // 調用native的init1函數 }
其中init1函數創建了一些系統服務,然后把調用線程加入到Binder通信中。期間還通過JNI調用了com.android.server.SystemServer類的init2函數,通過單獨創建一個線程,用以啟動系統的各項服務,如PowerManagerService, BatteryService, WindowManagerService, ActivityManagerService等。
public static final void init2(){ Slog.i(TAG, "Entered the Android system server!"); Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); }
這個函數的主要功能是創建新的線程ServerThread,它的override的run方法在SystemServer.java中,主要做了以下一些工作:
private void run() { ...... // Initialize native services. System.loadLibrary("android_servers"); ...... // Initialize the system context. createSystemContext(); ...... startCoreServices(); startOtherServices(); ...... }
/** * Starts some essential services that are not tangled up in the bootstrap process. */ private void startCoreServices() { // Tracks the battery level. Requires LightService. mSystemServiceManager.startService(BatteryService.class); // Tracks application usage stats. mSystemServiceManager.startService(UsageStatsService.class); mActivityManagerService.setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); // Update after UsageStatsService is available, needed before performBootDexOpt. mPackageManagerService.getUsageStatsIfNoPackageUsageInfo(); // Tracks whether the updatable WebView is in a ready state and watches for update installs. mSystemServiceManager.startService(WebViewUpdateService.class); }
/** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */ private void startOtherServices() { ...... try { Slog.i(TAG, "Reading configuration..."); SystemConfig.getInstance(); traceBeginAndSlog("StartSchedulingPolicyService"); ServiceManager.addService("scheduling_policy", new SchedulingPolicyService()); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); mSystemServiceManager.startService(TelecomLoaderService.class); traceBeginAndSlog("StartTelephonyRegistry"); telephonyRegistry = new TelephonyRegistry(context); ServiceManager.addService("telephony.registry", telephonyRegistry); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
...... } ...... }
至此,讓我們總結一下SystemServer
1)、ZygoteInit調用startSystemServer創建system_server進程。
2)、SystemServer調用handleSystemServerProcess完成自己的使命。
3)、handleSystemServerProcess拋出異常,最終調用com.android.server.SystemServer的main函數。
4)、main函數加載libandroid_server.so並調用native的init1函數。
5)、init1函數通過JNI調用com.android.server.SystemServer類的init2函數。init2函數創建一個線程,用於加載各種service。
6)、init1函數最終加入到Binder通信系統。
4 Zygote的分裂
zygote分裂出system_server后,就等待runSelectLoopMode等待並處理來自客戶的請求。那么,誰會向zygote發送消息呢?這里以一個activity的啟動為例作分析。
4.1 ActivityManagerService發送請求
ActivityManagerService由SystemServer創建。假設通過startActivity來啟動一個新的acitivity,而這個activity屬於一個還未啟動的進程,那么這個進程又如何啟動呢?先看ActivityManagerService中的startProcessLocked函數
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr){ ...... int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null, uid, uid, gids, debugFlags, null); ...... }
Process.start位於android.os.Process中,而它又調用了startViaZygote, zygoteSendArgsAndGetPid。而在zygoteSendArgsAndGetPid中,首先打開了和zygote通信的socket,接着把請求的參數發到zygote,然后讀取zygote處理完的結果,得知是某個進程的pid。
由於ActivityManagerService駐留於SystemServer進程中,所以正是SystemServer向Zygote發送了消息。
還記得前面提過的runSelectLoopMode函數么?它在里面又調用了ZygoteConnection的runOnce
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { try{ args = readArgumentList(); // 讀取SystemServer發送過來的參數 descriptors = mSocket.getAncillaryFileDescriptors(); } ...... pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits); ...... if(pid ==0){ handleClientProc(parsedArgs, descriptors, newStderr); //子進程處理 return true; } else { return handleParentProc(pid, descriptors, parsedArgs); } }
由此可見,zygote分裂子進程后,自己將在handleParentProc中做一些掃尾工作,然后繼續等待請求進行下一次分裂。
4.2 zygote響應請求的流程
1)、Zygote進程調用runSelectLoopMode
2)、SystemServer進程發送消息到Zygote
3)、Zygote通過fork創建子進程
4)、子進程調用android.app.ActivityThread的main函數
5 Home界面啟動
待Application Framework層的ActivityManagerService准備就緒后,就會通知各個模塊,繼續執行上層應用。
先附一張體系結構圖:
// We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state // where third party code can really run (but before it has actually // started launching the initial applications), for us to complete our // initialization. mActivityManagerService.systemReady(new Runnable() { @Override public void run() { Slog.i(TAG, "Making services ready"); ...... try { mActivityManagerService.startObservingNativeCrashes(); } catch (Throwable e) { reportWtf("observing native crashes", e); } ...... try { if (networkScoreF != null) networkScoreF.systemReady(); } catch (Throwable e) { reportWtf("making Network Score Service ready", e); } ...... try { if (networkManagementF != null) networkManagementF.systemReady(); } catch (Throwable e) { reportWtf("making Network Managment Service ready", e); } ...... try { if (networkStatsF != null) networkStatsF.systemReady(); } catch (Throwable e) { reportWtf("making Network Stats Service ready", e); } ...... try { if (networkPolicyF != null) networkPolicyF.systemReady(); } catch (Throwable e) { reportWtf("making Network Policy Service ready", e); } ...... try { if (connectivityF != null) connectivityF.systemReady(); } catch (Throwable e) { reportWtf("making Connectivity Service ready", e); } ...... try { if (audioServiceF != null) audioServiceF.systemReady(); } catch (Throwable e) { reportWtf("Notifying AudioService running", e); } ...... } });
public void systemReady(final Runnable goingCallback) { ...... // Start up initial activity. mBooting = true; startHomeActivityLocked(mCurrentUserId, "systemReady"); ...... }
這樣一來,就啟動了Home界面,完成了整個Android啟動流程。
下面是啟動流程圖:
參考:
《深入理解Android 卷I》 鄧凡平 著