zoukankan      html  css  js  c++  java
  • 【系统之音】Android进程的创建及启动简述

           Android系统中的进程(这里不包括init等底层的进程)都是通过Zygote fork而来的,那这些进程的启动流程都是怎样的呢?

           这里将Android进程分为两个部分:

        (1)系统框架进程SystemServer进程。它是Zygote创建的第一个进程,是在系统启动过程中,Zygote进程启动时直接fork而来的。

        (2)应用程序进程。比如Launcher、SystemUI,其它应用程序等的进程。这些应用程序进程的启动大致包含两个步骤:

                1)AMS向Zygote进程发送创建进程的请求;

                2)Zygote接受请求,创建并启动应用程序进程。

            本文将围绕上述几点,基于Android P(API28)的源码,来梳理Android进程的创建与启动过程。内容的主要对象是应用开发者,所以力求简洁和完整,内容大体如下:

     

    1、Zygote进程启动简述

           在理解这一部分前,建议先阅读【系统之音】Android系统启动篇

           系统在启动时,会启动一个名为“init”的系统进程,然后该进程会创建并启动Zygote进程。创建和启动Zygote进程的过程,先后从Nativie层跨入Java层,在Native层会创建虚拟机实例(即ART实例),然后通过JNI的方式调用ZygoteInit类的main方法。Native层的代码咱们不深究,这里看看main方法:

     1 //(代码1.1)=========ZygoteInit.java=====
     2 public static void main(String argv[]) {
     3       ZygoteServer zygoteServer = new ZygoteServer();
     4       ......
     5       String socketName = "zygote";
     6       ......
     7       //创建一个名为“zygote”的Server端Socket,在后续会一直监听AMS发起的创建新进程的请求。
     8       zygoteServer.registerServerSocketFromEnv(socketName);
     9       ......
    10       //①通过fork方式创建SystemServer进程并启动
    11       if (startSystemServer) {
    12                 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//fork创建SystemServer进程
    13                 ......
    14                 if (r != null) {
    15                     r.run();//启动SystemServer进程
    16                     return;
    17                 }
    18             }
    19        //②该方法中使用了一个while(true)的无限循环来实现一直监听AMS的请求
    20        caller = zygoteServer.runSelectLoop(abiList);
    21        ......
    22        //③这里是会执行子进程(应用程序进程)的ActivityThread的main方法,后文会讲到
    23        if (caller != null) {
    24             caller.run();
    25         }
    26 }

    我抽取了关键的代码,主要是关注Zygote启动期间所做的主要工作,这里先给出结论(有必要牢记于心):

        (1)创建虚拟机实例;

        (2)创建一个名为“zygote”的Server端Socket,用于后续监听AMS的请求;

        (3)通过fork的方式创建SystemServer进程并启动它,该过程会启动各种系统服务,AMS就是在这个阶段启动的;

        (4)在runSelectLoop方法中通过一个while(true)无限循环来实现对AMS的监听;

        (5)启动非SystemServer进程。

    2、Zygote创建与启动SystemServer

           实际上SystemServer是Zygote创建出的第一个进程,我们从代码1.1中的注释②处的forkSystemServer方法来深入了解:

     1 //代码2.1==========ZygoteInit.java=======
     2 private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
     3       ......
     4       int pid;
     5       ......
     6       //fork的过程发生在Native层
     7       pid = Zygote.forkSystemServer(...);
     8       ......
     9       //④pid为0表示子进程(即SystemServer进程)创建成功,逻辑进入到子进程中。下面的逻辑会启动SystemServer进程
    10       if (pid == 0) {
    11             ......
    12             return handleSystemServerProcess(parsedArgs);
    13        }
    14 }
    15 
    16 public static int forkSystemServer(...){
    17       ......
    18       int pid = nativeForkSystemServer(...);
    19       ......
    20 }
    21 
    22 native private static int nativeForkSystemServer(...)

    可见,forkSystemServer进程是发生在Native层的,接着继续从注释④处看看SystemServer进程的启动:

     1 //代码2.2 =========ZygoteInit.java========
     2 private static Runnable handleSystemServerProcess(...){
     3       ......
     4       return ZygoteInit.zygoteInit(...);
     5 }
     6 
     7 public static final Runnable zygoteInit(...) {
     8        ......
     9        //该处用于创建Binder线程池,此后SystemServer进程就可以使用Binder来实现IPC了。该过程也是在Native层实现,Binder在ServiceManager中进行注册。
    10         ZygoteInit.nativeZygoteInit();
    11         return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    12     }
    13 
    14 private static final native void nativeZygoteInit();
    15 
    16 //==========RuntimeInit.java=======
    17 protected static Runnable applicationInit(...){
    18       ......
    19       //通过上下文可以得知这里的args.startClass值为“com.android.server.SystemServer”
    20       return findStaticMain(args.startClass, args.startArgs, classLoader);
    21 }
    22 
    23 /**
    24  * Invokes a static "main(argv[]) method on class "className".
    25  * ......
    26  */
    27 protected static Runnable findStaticMain(String className, String[] argv,
    28         ClassLoader classLoader) {
    29     Class<?> cl;
    30     try {
    31         cl = Class.forName(className, true, classLoader);
    32     } catch (ClassNotFoundException ex) {
    33         throw new RuntimeException(
    34                 "Missing class when invoking static main " + className,
    35                 ex);
    36     }
    37     Method m;
    38     try {
    39         m = cl.getMethod("main", new Class[] { String[].class });
    40     } catch (NoSuchMethodException ex) {
    41         throw new RuntimeException(
    42                 "Missing static main on " + className, ex);
    43     } catch (SecurityException ex) {
    44         throw new RuntimeException(
    45                 "Problem getting static main on " + className, ex);
    46     }
    47     int modifiers = m.getModifiers();
    48     if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    49         throw new RuntimeException(
    50                 "Main method is not public and static on " + className);
    51     }
    52     ...... //毫无疑问,这里的m就是SystemServer类的main方法了
    53     return new MethodAndArgsCaller(m, argv);
    54 }
    55 
    56 static class MethodAndArgsCaller implements Runnable {
    57     /** method to call */
    58     private final Method mMethod;
    59     /** argument array */
    60     private final String[] mArgs;
    61     public MethodAndArgsCaller(Method method, String[] args) {
    62         mMethod = method;
    63         mArgs = args;
    64     }
    65     public void run() {
    66         try {
    67             mMethod.invoke(null, new Object[] { mArgs });
    68         }
    69         ......
    70     }
    71 }

           一步步跟进时,我们会发现该过程中主线都是返回的Runnable类型的对象,回到代码1.1的注释②处的第12行,这里的 r 就是MethodAndArgsCaller对象,第13行r.run()执行,就是调用的上述代码第67行,跟踪上下文可知这里就是执行的SystemServer.main方法。紧接着第14行是return,Zygote就完成了创建和启动SystemServer进程。此时你是否会有疑问:这里就return了,那后面监听AMS请求和启动非SystemServer进程的逻辑又如何实现呢?这里我们需要理解“fork”,后面我们会详细介绍。

            这里进一步看看SystemServer进程中都做了些什么:

     1 //=========SystemServer.java===========
     2 public static void main(String[] args) {
     3     new SystemServer().run();
     4 }
     5 private void run() {
     6     ......
     7     //创建消息Looper
     8     Looper.prepareMainLooper();
     9     // 加载动态库libandroid_servers.so,初始化native服务
    10     System.loadLibrary("android_servers");
    11     ......
    12     //初始化系统context
    13     createSystemContext();
    14     //创建SystemServiceManager
    15     mSystemServiceManager = new SystemServiceManager(mSystemContext);
    16     ......
    17     //启动引导服务,如AMS等
    18     startBootstrapServices();
    19     //启动核心服务
    20     startCoreServices();
    21     //启动其它服务,如WMS,SystemUI等
    22     startOtherServices();
    23     ....
    24     // Loop forever.
    25     Looper.loop();
    26 }

    到这里Zygote就创建并启动了SystemServe进程,总结一下这个过程中主要做了些什么工作:

        (1)通过fork得到一个虚拟机实例副本;

        (2)创建Binder线程池,SystemServer可以通过Binder来实现IPC(跨进程通信);

        (3)启动系统服务,比如AMS,WMS等;

        (4)创建消息循环,Looper.loop()中是一个无限循环,SystemServer将持续运行。

    3、fork简介

           在前文中提到了使用fork的方式来创建进程,也提到了一个疑问:

           “此时你是否会有疑问:这里就return了,那后面监听AMS请求和启动非SystemServer进程的逻辑又如何实现呢?”

           这里先看看百度百科的介绍:

        “复刻(英语:fork,又译作派生、分支)是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,
    每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。 fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,
    两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。”

           所以,在代码1.1中forkSystemServer时,Zygote进程会分化为两个一模一样的进程来,其中一个是父进程,另外一个是子进程,它是主进程的副本。当SystemServer fork成功后其流程就进入到了子进程中,即代码1.1中的第15、16行是在子进程中执行的。而与此同时,父进程还会继续往下执行,不断监听AMS的请求以及启动新的进程。

           要更好地理解fork后Zygote进程和子进程的工作,可以参考阅读:https://www.cnblogs.com/jiangzhaowei/p/11023098.html

    4、Zygote监听AMS的请求

            在代码1.1中注释②处,会通过调用runSelectLoop方法来监听AMS的请求,我们看看该方法的实现:

     1 //代码4.1======ZygoteServer.java======
     2 Runnable runSelectLoop(String abiList) {
     3       ......
     4       ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
     5       ......
     6       while (true) {
     7            ......
     8            //⑤当监听到AMS请求的数据时会执行这里
     9            ZygoteConnection connection = peers.get(i);
    10            final Runnable command = connection.processOneCommand(this);
    11            ......
    12            return command;
    13       }
    14 }

    这其中包含了一个while(true)的无限循环,以此来一直监听AMS的请求,直到注释⑤处监听到了AMS的请求,fork出新的子进程(应用程序进程),随后在子进程中return,结束监听。和fork SystemServer一样,父进程Zygote仍然继续监听着,继续相应AMS新的请求,fork出新的子进程。

    5、AMS向Zygote进程发起创建进程的请求

           要启动一个程序时,系统首先会判断该程序所在的进程是否存在,如果不存在就需要先创建并启动目标程序对应的进程。这一点在四大组件组件启动流程的源码中都有体现,当发现目标进程还不存在时,AMS都会向Zygote进程申请创建目标进程。这个过程分为两步:(1)AMS向Zygote进程发起创建进程的请求;(2)Zygote收到请求,创建并启动进程。这一节我们先看看第(1)步:

     1 //==============ActivityManagerService.java============
     2 private final boolean startProcessLocked(ProcessRecord app, String hostingType,
     3             String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
     4        ......
     5        final String entryPoint = "android.app.ActivityThread";
     6        return startProcessLocked(hostingType, hostingNameStr, entryPoint...);
     7 }
     8 private boolean startProcessLocked(...String entryPoint...) {
     9        ......
    10        final ProcessStartResult startResult = startProcess(...entryPoint...);
    11  }
    12  private ProcessStartResult startProcess(...String entryPoint...){
    13        ......
    14        final ProcessStartResult startResult;
    15        ......
    16        startResult = Process.start(entryPoint,
    17                          app.processName, uid, uid, gids, runtimeFlags, mountExternal,
    18                          app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
    19                          app.info.dataDir, invokeWith,
    20                          new String[] {PROC_START_SEQ_IDENT + app.startSeq});
    21        ......
    22  }
    23  //================Process.java==============
    24  public static final ZygoteProcess zygoteProcess = new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
    25  public static final ProcessStartResult start(final String processClass,...) {
    26           return zygoteProcess.start(processClass, ...);
    27  }
    28  //==============ZygoteProcess.java==========
    29   public final Process.ProcessStartResult start(final String processClass...) {
    30          try {
    31              return startViaZygote(processClass...);
    32          }......
    33     }
    34  private Process.ProcessStartResult startViaZygote(final String processClass...){       
    35        argsForZygote.add(processClass);
    36        ......
    37        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    38  }
    39  private ZygoteState primaryZygoteState;
    40  ......
    41  private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    42        ......
    43        //追踪代码,容易得知mSocket值为"zygote",这里的作用是连接名为“zygote”的Socket
    44        primaryZygoteState = ZygoteState.connect(mSocket);
    45        ......
    46  }

            从上述代码可以看出,该过程的逻辑其实挺简单,通过层层调用后走到第50行。这一行的作用就是和名为“zygote”的Socket服务端建立连接,这样就向Zygote进程发起了请求。这里的ZygoteState类中的

    6、Zygote收到AMS的请求,创建并启动进程

           在代码4.1中,我们讲过,其中while(true)循环一直监听AMS的请求,直到收到请求。

     1 //===========ZygoteConnection.java=======
     2 Runnable processOneCommand(ZygoteServer zygoteServer) {
     3       ......
     4       //⑥fork方式创建应用程序进程
     5       pid = Zygote.forkAndSpecialize(...);
     6       ......
     7       //pid为0表示当前的代码逻辑运行在新创建的子进程(即应用程序进程)中
     8       if (pid == 0) {
     9                 // in child
    10                  ......
    11                  //处理应用程序进程
    12                  return handleChildProc(parsedArgs, descriptors, childPipeFd,
    13                          parsedArgs.startChildZygote);
    14              } else {
    15                  ......
    16              }
    17  }
    18 
    19  private Runnable handleChildProc(...){
    20         ......
    21         return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
    22  }
    23  //=====ZygoteInit.java========
    24  public static final Runnable zygoteInit(...) {
    25        ......
    26        //创建Binder线程池,此后新的子进程就能够使用Binder进行IPC了
    27        ZygoteInit.nativeZygoteInit();
    28        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    29  }
    30 
    31 //============Zygote.java==========(补充注释⑥处)
    32 public static int forkAndSpecialize(...) {
    33     ........
    34     int pid = nativeForkAndSpecialize(...);
    35     ......
    36     return pid;
    37 }
    38 native private static int nativeForkAndSpecialize(...);

    流程走到第26行就比较清晰了,和代码2.2中启动SystemServer进程一致了,只不过这里启动的是ActivityThread的main方法。

     1 //=======ActivityThread.java=====
     2 static volatile Handler sMainThreadHandler;
     3 
     4 public static void main(String[] args) {
     5       ......
     6       Looper.prepareMainLooper();
     7       ......
     8       ActivityThread thread = new ActivityThread();
     9       ......
    10       if (sMainThreadHandler == null) {
    11             sMainThreadHandler = thread.getHandler();
    12        }
    13       ......
    14        Looper.loop();
    15 }
    16 
    17 final Handler getHandler() {
    18         return mH;
    19     }
    20 
    21 final H mH = new H();
    22 
    23 class H extends Handler {
    24       ......
    25 }

           ActivityThread类是主线程的管理类,其main方法中会创建消息循环,其中Looper.loop()方法中通过无限循环的方式,保持主线程一直运行。同时还会创建主线程的H类,这是一个包含主线程looper的Handler,四大组件启动过程中都需要通过这个H类对象来从Binder线程中切换到主线程中。

           这里总结一下普通应用程序进程创建时的关键工作:

        (1)通过fork得到一个虚拟机实例副本;

        (2)创建Binder线程池,应用程序进程就可以通过Binder来实现IPC;

        (3)创建消息循环,创建主线程的H类。

    7、疑问

        (1)为什么AMS(SystemServer进程)与Zygote进程通讯采用Socket而不是Binder?

           答:因为fork不允许存在多线程,而Binder通信偏偏就是多线程。(不知道该答案是否准确,目前还没找到权威答案)。

           可以参考:https://blog.csdn.net/qq_39037047/article/details/88066589

     参考及推荐阅读:

           https://www.cnblogs.com/andy-songwei/p/11429421.html

           https://www.cnblogs.com/jiangzhaowei/p/11023098.html

           https://www.jianshu.com/p/ab9b83a77af6

           https://blog.csdn.net/qq_39037047/article/details/88066589

           刘望舒《Android进阶解密》

  • 相关阅读:
    pycharm中出现unresolved reference的解决办法
    MVC4中基于bootstrap和HTML5的图片上传Jquery自定义控件
    Demo中的IOC自定义实现
    MVC 导出Excel 的其中一方法(View导出excel)
    MVC 定时执行任务
    Bootstrap.css 中请求googleapis.com/css?family 备忘录
    JqueryUI Dialog 加载动态页 部分页
    Android中EditText的常见属性
    安卓程序崩溃异常处理
    获取鼠标句柄
  • 原文地址:https://www.cnblogs.com/andy-songwei/p/13677429.html
Copyright © 2011-2022 走看看