整个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(){ spproc = 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》 邓凡平 著
Android启动过程深入解析
Android系统启动过程