承接上篇文章Zygote进程的启动流程,我们继续分析System进程的启动流程。

Zygote进程在启动的过程中,除了会创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中来,以及注册一些Android核心类的JNI方法来前面创建的Dalvik虚拟机实例中去。注意,一个应用程序进程被Zygote进程孵化出来的时候,不仅会获得Zygote进程中的Dalvik虚拟机实例拷贝,还会与Zygote一起共享Java运行时库,这完全得益于Linux内核的进程创建机制(fork)。这种Zygote孵化机制的优点是不仅可以快速地启动一个应用程序进程,还可以节省整体的内存消耗,缺点是会影响开机速度,毕竟Zygote是在开机过程中启动的。不过,总体来说,是利大于弊的,毕竟整个系统只有一个Zygote进程,而可能有无数个应用程序进程,而且我们不会经常去关闭手机,大多数情况下只是让它进入休眠状态。

在ZygoteInit类的静态方法startSystemServer,代码如下:

public class ZygoteInit {......private static boolean startSystemServer()throws MethodAndArgsCaller, RuntimeException {/* 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,3001,3002,3003","--capabilities=130104352,130104352","--runtime-init","--nice-name=system_server","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {parsedArgs = new ZygoteConnection.Arguments(args);....../* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);//System进程uid为1000} catch (IllegalArgumentException ex) {......}/* For child process */if (pid == 0) {//子进程,System进程handleSystemServerProcess(parsedArgs);//System进程,后续再分析}return true;}......
}

我们继续分析handleSystemServerProcess,代码如下:

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)throws ZygoteInit.MethodAndArgsCaller {closeServerSocket();/** Pass the remaining arguments to SystemServer.* "--nice-name=system_server com.android.server.SystemServer"*/RuntimeInit.zygoteInit(parsedArgs.remainingArgs);/* should never reach here */}

由于System进程复制了Zygote进程的地址空间,因此,它就会获得Zygote进程在启动过程中所创建的一个Socket。System进程不需要使用这个Socket,因此调用closeServerSocket来关闭它。接下来调用RuntimeInit类的静态成员函数zygoteInit来进一步启动System进程。

public class RuntimeInit {  ......  public static final void zygoteInit(String[] argv)  throws ZygoteInit.MethodAndArgsCaller {  ......  zygoteInitNative();  ......  // Remaining arguments are passed to the start class's static main  String startClass = argv[curArg++];  String[] startArgs = new String[argv.length - curArg];  System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  invokeStaticMain(startClass, startArgs);  }  ......
}

首先调用RuntimeInit类的静态成员函数zygoteInitNative来启动一个Binder线程池,会调用一个JNI方法。

public static final native void zygoteInitNative();

Runtime类的静态成员函数zygoteInitNative是一个JNI方法,它是由C++层的函数com_android_internal_os_RuntimeInit_zygoteInit来实现的,如下:

static AndroidRuntime* gCurRuntime = NULL;
......
static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit();
}

gCurRuntime是一个全局变量,它是在AndroidRuntime类的构造函数中被初始化的,如下所示:

AndroidRuntime::AndroidRuntime()
{......assert(gCurRuntime == NULL);        // one per processgCurRuntime = this;
}

Zygote进程在启动时,会在进程中创建一个AppRuntime对象。由于AppRuntime类继承了AndroidRuntime类,因此,在创建一个AppRuntime对象时,会导致AndroidRuntime类的构造函数被调用。在调用的过程中,全局变量gCurRuntime就会被初始化,它指向的就是正在创建的AppRuntime对象。又由于每一个新创建的应用进程都复制了Zygote进程的地址空间,因此,在每个应用程序进程中,都会存在一个全局变量gCurRuntime。

回到函数com_android_internal_os_RuntimeInit_zygoteInit,调用了全局变量gCurRuntime的成员函数onZygoteInit来启动一个Binder线程池。全局变量gCurRuntime指向的是一个AppRuntime对象,并且AppRuntime类重写了父类AndroidRuntime的成员函数onZygoteInit,因此,接下来实际上调用的是AppRuntime类的成员函数onZygoteInit。

virtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();if (proc->supportsProcesses()) {LOGV("App process: starting thread pool.\n");proc->startThreadPool();}       }

首先判断是否支持Binder进程间通信机制,如果支持,那么就调用当前应用程序进程中的ProcessState对象的成员函数startThreadPool来启动一个Binder线程池,以便使得当前应用程序可以通过Binder进程间通信机制和其他进程通信。

void ProcessState::startThreadPool()
{AutoMutex _l(mLock);if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}
}

ProcessState类有一个成员变量mThreadPoolStarted,它的初始值等于false。在Android系统中,每一个支持Binder进程间通信机制的进程内部都有一个唯一的ProcessState对象。当这个ProcessState对象的成员函数startThreadPoll第一次被调用时,它就会在当前进程中启动一个Binder线程池,并且将它的成员变量mThreadPoolStarted的值设置为true,避免以后重复执行启动Binder线程池的操作。

void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {int32_t s = android_atomic_add(1, &mThreadPoolSeq);char buf[32];sprintf(buf, "Binder Thread #%d", s);LOGV("Spawning new pooled thread, name=%s\n", buf);sp<Thread> t = new PoolThread(isMain);t->run(buf);}
}

这里它会创建一个PoolThread线程类,然后执行它的run函数,最终就会执行PoolThread类的threadLoop函数了。

class PoolThread : public Thread
{
public:PoolThread(bool isMain): mIsMain(isMain){}protected:virtual bool threadLoop(){IPCThreadState::self()->joinThreadPool(mIsMain);return false;}const bool mIsMain;
};

有关 Native线程的创建过程,请参考Dalvik虚拟机进程和线程的创建过程分析。

返回到RuntimeInit类的静态方法zygoteInit,继续执行invokeStaticMain,代码如下:

private static void invokeStaticMain(String className, String[] argv)//className为com.android.server.SystemServerthrows ZygoteInit.MethodAndArgsCaller {// We want to be fairly aggressive about heap utilization, to avoid// holding on to a lot of memory that isn't needed.VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);Class<?> cl;try {cl = Class.forName(className);//首先将com.android.server.SystemServer类加载到当前进程中} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className,ex);}Method m;try {m = cl.getMethod("main", new Class[] { String[].class });//获取了它的静态函数main} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}/** This throw gets caught in ZygoteInit.main(), which responds* by invoking the exception's run() method. This arrangement* clears up all the stack frames that were required in setting* up the process.*/throw new ZygoteInit.MethodAndArgsCaller(m, argv);//把这个Method对象封装在一个MethodAndArgsCaller对象中,并且将这个MethodAndArgsCaller对象作为一个异常对象抛出来给当前进程处理}

我们知道System进程复制了Zygote进程的地址空间,因此,System进程的调用堆栈和Zygote进程的调用堆栈是一致的,从前面知道,Zygote进程最开始执行的是应用程序app_process的入口函数main,如下:

public class ZygoteInit {......public static void main(String argv[]) {try {......registerZygoteSocket();//创建一个Server端Socket,这个Server端Socket是用来等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程的<span style="white-space:pre">   </span>............if (argv[1].equals("true")) {startSystemServer();//启动System进程,以便它可以将系统的关键服务启动起来} else if (!argv[1].equals("false")) {......}......if (ZYGOTE_FORK_MODE) {//false......} else {runSelectLoopMode();}......} catch (MethodAndArgsCaller caller) {caller.run();} catch (RuntimeException ex) {......}}......
}

这个异常最后会被main函数里面的catch捕获,ZygoteInit类的静态成员函数main捕获了一个类型为MethodAndArgsCaller的异常之后,就会调用MethodAndArgsCaller类的成员run来进一步处理。

public class ZygoteInit {......public static class MethodAndArgsCaller extends Exceptionimplements Runnable {/** method to call */private final Method mMethod;/** argument array */private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {mMethod = method;mArgs = args;}public void run() {try {mMethod.invoke(null, new Object[] { mArgs });//调用了com.android.server.SystemServer的main函数} catch (IllegalAccessException ex) {......} catch (InvocationTargetException ex) {......}}}......
}

为什么要这么折腾呢?直接调用不行么,由于新创建的System进程一开始就需要在内部初始化运行时库,以及启动Binder线程池,因此com.android.server.SystemServer的main函数被调用时,System进程其实已经执行了相当多代码。为了使得新创建的System进程觉得它的入口函数就是com.android.server.SystemServer的main函数,系统不直接调用它,而是抛出一个异常回到ZygoteInit类的静态成员函数main中,然后再间接地调用它,这样就可以巧妙地利用Java语言的异常处理机制来清理它前面的调用堆栈了。

System进程的启动流程第一部分相关推荐

  1. Android 系统(246)---SystemServer进程的启动流程

    Android进程系列第四篇---SystemServer进程的启动流程 一.内容预览 内容预览.png 二.概述 前面进程系列已经更新了三篇,本文(基于Android O源码),第三篇中System ...

  2. Android系统(244)---Zygote进程的启动流程

    Android进程系列第二篇---Zygote进程的启动流程 内容预览.png 概述: 本文(基于Android O源码)主要讲解Zygote进程创建流程,线程容易创建,但进程的相关的东西都被系统很好 ...

  3. Android系统启动流程--init进程的启动流程

    这可能是个系列文章,用来总结和梳理Android系统的启动过程,以加深对Android系统相对全面的感知和理解(基于Android11).  1.启动电源,设备上电 引导芯片代码从预定义的地方(固化在 ...

  4. Zygote和System进程的启动过程

    ##init脚本的启动 +------------+ +-------+ +-----------+ |Linux Kernel+--> |init.rc+-> |app_process| ...

  5. Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application

    注册Activity应用进程到system_server以及创建Activity应用进程Application Android四大组件源码实现详解系列博客目录: Android应用进程创建流程大揭秘 ...

  6. 【Android】系统启动流程(zygote 进程启动流程)

    前言 先上图,大致了解一下 Android 设备点击电源键开机到创建出 system_server 进程的流程, 里面细化的子流程和 system_server 之后发生的事情我将会在后续的文章中详细 ...

  7. Android应用程序进程启动流程

    在学习应用程序进程启动流程前,先要弄清楚系统启动流程,如果有不清楚的同学,建议先看下以前博主的文章: Android系统启动(上篇)_AD钙奶-lalala的博客-CSDN博客 Android系统启动 ...

  8. Android系统完整的启动流程

    Android系统完整的启动过程,从系统层次角度可分为 Linux 系统层.Android 系统服务层.Zygote进程模型三个阶段:从开机到启动 Home Launcher 完成具体的任务细节可分为 ...

  9. Android:启动流程

    Android启动流程 第一步:启动电源以及系统启动 当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行.加载引导程序到RAM,然后 执行 第二步:引导程序 引导程序是在Android ...

  10. 深入分析Android 9.0源代码——Activity启动流程

    引言 点击此处查看<深入分析Android 9.0源代码>系列的组织结构和相关说明. 1 应用进程发起启动请求 本章的调用流程如下图所示: (Context) Activity Instr ...

最新文章

  1. 蓝桥杯练习系统算法训练习题加答案java版本
  2. 线程在Linux中的实现
  3. shell day01 : Shell概述 编写及执行脚本 、 Shell变量
  4. mybatis中自建的类型别名
  5. ACM 中常用的算法有哪些? 2014-08-21 21:15 40人阅读 评论(0) 收藏...
  6. 水印相机定位不准确怎么办_禄来的广角双反相机(2020版)
  7. [react] React组件的构造函数是必须的吗?
  8. 合同的不含税与税额怎么算
  9. pods报错修复方法
  10. 小米推出售价 19999 元的 MIX Alpha;高通已向华为重启供货;.NET Core 3.0 发布 | 极客头条...
  11. 安卓机顶盒运行linux,全志 Allwinner A20 机顶盒刷入原生 Debian
  12. 问个globle的问题,如何定时更新论坛的数据啊?
  13. 人脸识别、活体检测、人脸识别面临的挑战
  14. 电信光纤猫与无线路由器连接
  15. 微信公众号通过第三方平台完成授权
  16. GRE隧道配置实验(静态路由)
  17. 关于mavon-editor中iframe 的使用 和插入视频、音频的记录
  18. CDLinux U盘启动教程
  19. 新浪邮箱(@sina.com/@sina.cn):启用IMAP4/SMTP服务+授权码
  20. Java把xx年xx月xx日(星期x) 上午xx点xx分转换Date类型

热门文章

  1. 手机app端,token的详解
  2. 输入一个仅含十二进制数的字符串输出二进制
  3. android基础之Map系列
  4. Excel 电子表格文件格式剖析
  5. 将业务做到遍布全球,需要多大的IT运维团队?
  6. AI人工智能概念(机器学习,深度学习,强化学习)
  7. 为什么浏览器全面禁用三方 Cookie
  8. CAD注册表:Release Number、Product ID、Locale ID
  9. 解决Configure TrackPoint重启后不能保存的问题
  10. 使用谷歌浏览器自带的谷歌翻译提示“无法翻译此网页”