目录

  • 第一节 Android系统启动流程
    • init进程
  • 第二节 init.rc 解析
  • 第三节 Zygote进程的启动过程
    • 3.1 AndroidRuntime.start 做了三件事:
      • 3.1.1 startVm:
      • 3.1.2 startReg:
        • 3.1.2.1 设置创建可访问Java的线程方法
        • 3.1.2.2 注册所有的JNI方法
      • 3.1.3 callMain()
    • 3.2 (Java世界开始)ZygoteInit.main()
  • 第四节 SystemServer 启动流程
  • 第五节 其他小点
    • 5.1 什么情况下 Zygote 进程会重启呢?
    • 5.2 fork函数
    • 5.3 写时拷贝(copy-on-write)
    • 5.4 内核空间、用户空间
    • 5.5 epoll
    • 5.6 内核的异常级别

第一节 Android系统启动流程

Boot Rom —— Bootloader —— Linux Kernel —— init进程 —— Zygote进程(dalvik/ art)—— systemServer —— Apps

init进程

init 进程是Linux系统中,用户空间启动的第一个进程。

  1. 创建并挂载一些文件目录
  2. 启动属性服务
  3. 解析 init.rc 配置文件,启动 Zygote 进程

挂载 seLinux 文件目录,创建seLinux,加载 安全策略
启动内核日志
启动属性系统,从文件读取属性
创建epoll

第二节 init.rc 解析

包含五种类型语句:

  1. Action(包含command)
  2. Commands
  3. Services(将由 init进程 启动的服务)
  4. Options(服务的选项)
  5. Import (其他配置文件)

Zygote服务 也在init.rc中配置:
//进程名为Zygote,执行的真正程序是 /system/bin/app_process

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main//classname为mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks

第三节 Zygote进程的启动过程

zygote受精卵,用于孵化子进程。所有APP及Systemserver进程 都由zygote 通过Linux的fork() 函数孵化出来的。
Zygote进程是Android系统中第一个带有art 虚拟机的进程,Zygote 与 SystemServer 进程以socket的方式进行通信。
Zygote是C/S模型的服务端,主要负责创建 Java 虚拟机,加载系统资源,启动 SystemServer 及其他进程。

启动一个应用的流程:
点击应用图标 —— AMS —— 发出socket —— Zygote —— linux fork() 新进程

/frameworks/base/cmds/app_process/app_main.cpp
App_main.main() 有两种启动模式:

  1. Zygote初始化模式
  2. application模式

  • Zygote初始化模式,会启动 SystemServer ,并指定自己的 socket 名字为 zygote
  • application模式,就是启动普通应用,参数有 class 名字及参数

(C++世界)(Zygote Service)App_main() —— AndroidRumtime.start() 【startVm() —— startReg() —— callMain() 】—— (Java世界开始)ZygoteInit.main() 【registerZygoteSocket() —— preload() —— gc() —— startSystemServer() —— runSelectLoop()】

  1. AndroidRumtime.start() —— startVm() —— startReg():AndroidRumtime::Start() 函数中将启动 JavaVM,并注册所有FWK相关的系统 JNI 接口。为 Java 世界做好准备。
  2. ZygoteInit.main() registerZygoteSocket() —— preload() —— gc() —— startSystemServer() —— runSelectLoop():第一次进入Java世界,运行 ZygoteInit.java::main() 初始化Zygote,并创建 Socket 的 Server 端。preload 常用的 Java 类库、系统 resources,执行 gc() 清理内存,为 fork 子进程做好准备。然后 fork 出子进程,在子进程中 初始化 SystemServer,初始化的过程中 启动 Android 系统所有的 Service。
  3. (与此同时,Zygote 继续在后台监听 Socket 等待新的应用启动请求。)
  4. (与此同时,Zygote 监听 SystemServer 的 SIGHID信号,一旦SystemServer挂掉,立即 kill 掉 Zygote 自己。init 会重启 Zygote,再启动 SystemServer,使系统恢复正常。 )
  5. AMS ready后,寻找系统的 “Startup” Application,向 Zygote 发请求。
  6. Zygote fork 出“Startup” Application,也就是启动 Launcher 应用,然后显示出Home页面。

在fork SystemServer之前执行了 gc 操作,使得被 fork 出来的子进程有尽可能少的垃圾内存。


ZygoteInit的启动入口是:
app_main.cpp(也就是Zygote的C++进程) ::main() —— AppRuntime.start(“com.android.internal.os.ZygoteInit”)

AndroidRuntime包括了:从下到上 libc、JNI、Java-VM、Java-lib

3.1 AndroidRuntime.start 做了三件事:

  1. startVm():
  2. startReg():
  3. callMain():

3.1.1 startVm:

cmds/app_process.cpp
base/core/jni/AndroidRuntime.cpp startvm()
art/runtime/java_vm_ext.cc JNI_CreateJavaVM() 返回JniEnv JavaVm给Native代码,这样就可以访问java接口了
art/runtime/runtime.cc 提供art虚拟机运行时:创建堆管理对象gc::Heap、创建Java虚拟机对象JavaVmExt、为vm添加JniEnvHandler、连接主线程、创建类连接器

3.1.2 startReg:

主要做两件事:

  1. 设置创建可访问Java的线程方法
  2. 注册所有的JNI方法

3.1.2.1 设置创建可访问Java的线程方法

system/core/libutils/Threads.cpp::run() native层可以创建两种Thread:一种可以调用java方法的线程,一种是纯native的线程。
可调用java的线程,会调用vm 将线程与 JNIEnv 绑定,使之可通过JNIEnv调用java方法。

// base/core/jni/androidRuntime.cpp/* * Makes the current thread visible to the VM. * * The JNIEnv pointer returned is only valid for the current thread, and * thus must be tucked into thread-local storage. */static int javaAttachThread(const char* threadName, JNIEnv** pEnv){JavaVMAttachArgs args;JavaVM* vm;vm = AndroidRuntime::getJavaVM();result = vm->AttachCurrentThread(pEnv, (void*) &args);if (result != JNI_OK)ALOGI("NOTE: attach of thread '%s' failed\n", threadName);return result;}

从数据结构上看,thread.h 类中,有一个 JNIEnvExt* 的指针变量 jni_env, 表明一个thread与一个jni_env关联。

// runtime/thread.hstruct PACKED(sizeof(void*)) tls_ptr_sized_values {// Every thread may have an associated JNI environmentJNIEnvExt* jni_env;}

3.1.2.2 注册所有的JNI方法

除了系统的JNI接口(javacore nativehelper)FWK还有大量的Native实现,所有这些接口一次性通过startReg()来完成
base/core/jni/androidRuntime.cpp::startReg()

/* * Register android native functions with the VM. *//*static*/ int AndroidRuntime::startReg(JNIEnv* env){......register_jni_procs(gRegJNI, NELEM(gRegJNI), env)}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) { ... }}}static const RegJNIRec gRegJNI[] = {REG_JNI(register_com_android_internal_os_RuntimeInit),REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),REG_JNI(register_android_os_SystemClock),REG_JNI(register_android_util_EventLog),REG_JNI(register_android_util_Log),REG_JNI(register_android_util_MemoryIntArray),REG_JNI(register_android_util_PathParser),REG_JNI(register_android_util_StatsLog),REG_JNI(register_android_app_admin_SecurityLog),REG_JNI(register_android_content_AssetManager),REG_JNI(register_android_content_StringBlock),REG_JNI(register_android_content_XmlBlock),REG_JNI(register_android_content_res_ApkAssets),REG_JNI(register_android_text_AndroidCharacter), ... ...}// frameworks/base/core/jni/android_util_Log.cppint register_android_util_Log(JNIEnv* env){jclass clazz = FindClassOrDie(env, "android/util/Log");levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));}/* * Register native methods using JNI. *//*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,const char* className, const JNINativeMethod* gMethods, int numMethods){return jniRegisterNativeMethods(env, className, gMethods, numMethods);}// libnativehelper/JNIHelp.cppextern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, constJNINativeMethod* gMethods, int numMethods){JNIEnv* e = reinterpret_cast<JNIEnv*>(env);(*env)->RegisterNatives(e, c.get(), gMethods, numMethods)... ...}

3.1.3 callMain()

// frameworks/base/core/java/com.android.internal.os.RuntimeInit.javapublic static final void main(String[] argv) {....../* * Now that we're running in interpreted code, call back into native code * to run the system. */nativeFinishInit();if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");}
// frameworks/base/core/jni/AndroidRuntime.cpp/* * Code written in the Java Programming Language calls here from main(). */static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz){gCurRuntime->onStarted();}// frameworks/base/cmds/app_process/app_main.cppvirtual void onStarted(){AndroidRuntime* ar = AndroidRuntime::getRuntime();ar->callMain(mClassName, mClass, mArgs);}

callMain() 将调起Java世界的 com.android.internal.os.ZygoteInit 类的main()方法。

3.2 (Java世界开始)ZygoteInit.main()

public static void main(String argv[]) {ZygoteServer zygoteServer = new ZygoteServer();final Runnable caller;try {boolean startSystemServer = false;String socketName = "zygote";String abiList = null;boolean enableLazyPreload = false;for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true;} else if ("--enable-lazy-preload".equals(argv[i])) {enableLazyPreload = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {socketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}// 注册Server socketzygoteServer.registerServerSocketFromEnv(socketName); if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");// 加载类到内存preload(bootTimingsTraceLog); }preloadTextResources();// 垃圾回收gcAndFinalize();if (startSystemServer) {Runnable r = forkSystemServer(abiList, socketName, zygoteServer);// {@code r == null} in the parent (zygote) process, and {@code r != null} in the// child (system_server) process.if (r != null) {r.run();return;}}Log.i(TAG, "Accepting command socket connections");// The select loop returns early in the child process after a fork and// loops forever in the zygote.caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);throw ex;} finally {zygoteServer.closeServerSocket();}}

preload是Android 启动最耗时的部分之一

/** * Prepare the arguments and forks for the system server process. * * Returns an {@code Runnable} that provides an entrypoint into system_server code in the * child process, and {@code null} in the parent. */private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {/* Hardcoded command line to start the system server */String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {parsedArgs = new ZygoteConnection.Arguments(args);ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);boolean profileSystemServer = SystemProperties.getBoolean("dalvik.vm.profilesystemserver", false);if (profileSystemServer) {parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;}/* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.runtimeFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}/* For child process */if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}zygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);}return null;}

第四节 SystemServer 启动流程

SystemServer 是 Zygote fork出来的第一个 Java 进程,此进程非要重要,提供了 Android 系统所有的核心服务。
SystemServer 中运行着AMS,WMS 等系统服务,Binder-x 之类的服务线程,UI-thread InputReader

SystemServer 创建:ActivityThread、SystemContext、SystemUIContext
ContextImpl 是 Context 的实现类,其中封装了生成 4 种常用的 createContext 方法:

  • createSystemContext()
  • createSystemUiContext()
  • createAppContext()
  • createActivityContext()

启动Service

startBootstrapServices();startCoreServices();startOtherServices();
  • startBootstrapServices():启动系统启动所需的一小堆关键服务(AMS,PMS,RecoverySystemService,LightsService,DisplayManagerService,UserManagerService,OverlayManagerService)。这些服务具有复杂的相互依赖关系,这就是为什么我们在这里将它们全部初始化的原因。除非您的服务也与这些依赖关系纠缠在一起,否则它应该在其他函数中进行初始化。
  • startCoreServices():启动一些在引导过程中没有互相交互的基本服务(BatteryService, UsageStatsService, WebViewUpdateService, BinderCallsStatsService)。
  • startOtherServices():启动一些杂七杂八的东西(ConnectivityService,WMS,InputManagerService,TelephonyRegistry)

Zygote会在后台观察 SystemServer ,一旦 System 挂掉了,将其回收,然后重启 Zygote 自己。
Watchdog 也可能因某种原因,将 SystemServer Kill 掉,并重启。屏幕会黑屏一段时间。

在 Unix-like 系统,父进程必须用 waitpid 等待子进程退出,否则子进程将变成 Zombie(僵尸)进程,不仅系统资源泄漏,而且系统将崩溃。没有 SystemServer 所有 Android 应用程序都无法运行。
waitpid() 是一个阻塞函数,所以通常处理是 在 signal 函数里无阻塞调用。
每个子进程退出时 —— 发出 SIGCHID 信号 —— Zygote 会杀掉自己 —— 系统给所有子进程发送 SIGHUP 信号 —— 各子进程杀掉自己退出当前进程(子进程中的 Daemon 进程设置 SIG_IGN参数忽略 SIGHUP 信号继续运行)。

第五节 其他小点

5.1 什么情况下 Zygote 进程会重启呢?

ServiceManager、SystemServer、SurfaceFlinger、Zygote自己 进程被杀

5.2 fork函数

返回值 == 0:成功创建子进程,并进入子进程执行
返回值 > 0:成功创建子进程,返回子进程id,并继续沿原父进程执行
返回值 < 0:创建失败
失败原因主要有:进程数超过系统上限(EAGAIN),系统内存不足(ENOMEM)
fork() 出的子进程,是父进程的一个copy,继承了整个进程的地址空间:包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。与父进程不同的只有进程号、计时器等少量信息。由上可见,fork() 函数的开销是很大的。

5.3 写时拷贝(copy-on-write)

Linux 的 fork 采用写时拷贝。写时拷贝是一种可能推迟甚至避免拷贝的技术。内核此时并不复制整个进程的地址空间,而是让子进程共享父进程的地址空间。只有在需要写入时,才会复制地址空间,使子进程拥有自己的地址空间。

panic
内核出现异常会导致1 进程死亡,如果是中断上下文的异常或系统关键资源受到破坏,通常会导致2 内核挂起,不再响应任何事件。

5.4 内核空间、用户空间

在linux中, 将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)
内核非法使用了用户空间的地址故存在问题。

5.5 epoll

epoll
epoll_create、epoll_wait、epoll_ctl

5.6 内核的异常级别

1. bug2. Oops3. panic
  • Bug:是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运行不会产生影响的问题,比如在原子上下文中休眠。
  • Oops:程序在内核态时,进入一种异常情况,比如引用非法指针导致的数据异常,数组越界导致的取指异常,此时异常处理机制能够捕获此异常,并将系统关键信息打印到串口上,正常情况下Oops消息会被记录到系统日志中去。
    Oops发生时,进程处在内核态,很可能正在访问系统关键资源,并且获取了一些锁,当进程由于Oops异常退出时,无法释放已经获取的资源,导致其他需要获取此资源的进程挂起,对系统的正常运行造成影响。通常这种情况,系统处在不稳定的状态,很可能崩溃。
  • panic:当Oops发生在中断上下文中或者在进程0和1中,系统将彻底挂起,因为中断服务程序异常后,将无法恢复,这种情况即称为内核panic。另外当系统设置了panic标志时,无论Oops发生在中断上下文还是进程上下文,都将导致内核Panic。由于在中断复位程序中panic后,系统将不再进行调度,Syslogd将不会再运行,因此这种情况下,Oops的消息仅仅打印到串口上,不会被记录在系统日志中。