Android进程框架:进程的创建、启动与调度流程

发表于:2018-1-23 14:49

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:郭孝星    来源:51Testing软件测试网采编

  文章目录
  ●一 进程的创建与启动流程
  ●二 进程的优先级
  ●三 进程的调度流程
  Android系统的启动流程如下图(点击查看大图)所示:
  Loader层
  1.当手机处于关机状态时,长按电源键开机,引导芯片开始从固化在Boot ROM里的预设代码开始执行,然后加载引导程序Boot Loader到RAM。
  2.Boot Loader被加载到RAM之后开始执行,该程序主要完成检查RAM,初始化硬件参数等功能。
  Kernel层
  3.引导程序之后进入Android内核层,先启动swapper进程(idle进程),该进程用来初始化进程管理、内存管理、加载Display、Camera Driver、Binder Driver等相关工作。
  4.swapper进程进程之后再启动kthreadd进程,该进程会创建内核工作线程kworkder、软中断线程ksoftirqd、thernal等内核守护进程,kthreadd进程是所有内核进程的鼻祖。
  Native层
  5.接着会启动init进程,init进程是所有用户进程的鼻祖,它会接着孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程,启动ServiceManager来管理系统
  服务,启动Bootnaim开机动画。
  6.init进程通过解析init.rc文件fork生成Zygote进程,该进程是Android系统第一个Java进程,它是所有Java进程父进程,该进程主要完成了加载ZygoteInit类,注册Zygote Socket
  服务套接字;加载虚拟机;预加载Class;预加载Resources。
  Framework层
  7.init进程接着fork生成Media Server进程,该进程负责启动和管理整个C++ Framwork(包含AudioFlinger、Camera Service等服务)。
  8.Zygote进程接着会fork生成System Server进程,该进程负责启动和管理整个Java Framwork(包含ActivityManagerService、WindowManagerService等服务)。
  App层
  Zygote进程孵化出的第一个应用进程是Launcher进程(桌面),它还会孵化出Browser进程(浏览器)、Phone进程(电话)等。我们每个创建的应用都是一个单独的进程。
  通过上述流程的分析,想必读者已经对Android的整个进程模型有了大致的理解。作为一个应用开发者我们往往更为关注Framework层和App层里进程的创建与管理相关原理,我们来
  一一分析。
  一 进程的创建与启动流程
  在正式介绍进程之前,我们来思考一个问题,何为进程,进程的本质是什么???
  我们知道,代码是静态的,有代码和资源组成的系统要想运行起来就需要一种动态的存在,进程就是程序的动态执行过程。何为进程?
  进程就是处理执行状态的代码以及相关资源的集合,包括代码端段、文件、信号、CPU状态、内存地址空间等。
  进程使用task_struct结构体来描述,如下所示:
  ●代码段:编译后形成的一些指令
  ●数据段:程序运行时需要的数据
  只读数据段:常量
  已初始化数据段:全局变量,静态变量
  未初始化数据段(bss):未初始化的全局变量和静态变量
  ●堆栈段:程序运行时动态分配的一些内存
  ●PCB:进程信息,状态标识等
  关于进程的更多详细信息,读者可以去翻阅Linux相关书籍,这里只是给读者带来一种整体上的理解,我们的重心还是放在进程再Android平台上的应用。
  在文章开篇的时候,我们提到了系统中运行的各种进程,那么这些进程如何被创建呢???
  我们先来看看我们最熟悉的应用进程是如何被创建的,前面我们已经说来每一个应用都运行在一个单独的进程里,当ActivityManagerService去启动四大组件时,
  如果发现这个组件所在的进程没有启动,就会去创建一个新的进程,启动进程的时机我们在分析四大组件的启动流程的时候也有讲过,这里再总结一下:
  ●ActivityActivityStackSupervisor.startSpecificActivityLocked()
  ●ServiceActiveServices.bringUpServiceLocked()
  ●ContentProviderActivityManagerService.getContentProviderImpl()
  = BroadcastBroadcastQueue.processNextBroadcast()
  这个新进程就是zygote进程通过复制自身来创建的,新进程在启动的过程中还会创建一个Binder线程池(用来做进程通信)和一个消息循环(用来做线程通信)
  整个流程如下图所示:
  1.当我们点击应用图标启动应用时或者在应用内启动一个带有process标签的Activity时,都会触发创建新进程的请求,这种请求会先通过Binder
  发送给system_server进程,也即是发送给ActivityManagerService进行处理。
  2.system_server进程会调用Process.start()方法,会先收集uid、gid等参数,然后通过Socket方式发送给Zygote进程,请求创建新进程。
  3.Zygote进程接收到创建新进程的请求后,调用ZygoteInit.main()方法进行runSelectLoop()循环体内,当有客户端连接时执行ZygoteConnection.runOnce()
  方法,最后fork生成新的应用进程。
  4.新创建的进程会调用handleChildProc()方法,最后调用我们非常熟悉的ActivityThread.main()方法。
  注:整个流程会涉及Binder和Socket两种进程通信方式,这个我们后续会有专门的文章单独分析,这个就不再展开。
  整个流程大致就是这样,我们接着来看看具体的代码实现,先来看一张进程启动序列图:
  从第一步到第三步主要是收集整理uid、gid、groups、target-sdk、nice-name等一系列的参数,为后续启动新进程做准备。然后调用openZygoteSocketIfNeeded()方法
  打开Socket通信,向zygote进程发出创建新进程的请求。
  注:第二步中的Process.start()方法是个阻塞操作,它会一直等待进程创建完毕,并返回pid才会完成该方法。
  我们来重点关注几个关键的函数。
  1.1 Process.openZygoteSocketIfNeeded(String abi)
  关于Process类与Zygote进程的通信是如何进行的呢???
  Process的静态内部类ZygoteState有个成员变量LocalSocket对象,它会与ZygoteInit类的成员变量LocalServerSocket对象建立连接,如下所示:
  客户端
  public static class ZygoteState {
      final LocalSocket socket;
  }
  服务端
  public class ZygoteInit {
      //该Socket与/dev/socket/zygote文件绑定在一起
      private static LocalServerSocket sServerSocket;
  }
  我们来具体看看代码里的实现。
   public static class ZygoteState {
      
      public static ZygoteState connect(String socketAddress) throws IOException {
          DataInputStream zygoteInputStream = null;
          BufferedWriter zygoteWriter = null;
          //创建LocalSocket对象
          final LocalSocket zygoteSocket = new LocalSocket();
          try {
              //将LocalSocket与LocalServerSocket建立连接,建立连接的过程就是
              //LocalSocket对象在/dev/socket目录下查找一个名称为"zygote"的文件
              //然后将自己与其绑定起来,这样就建立了连接。
              zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                      LocalSocketAddress.Namespace.RESERVED));
              //创建LocalSocket的输入流,以便可以接收Zygote进程发送过来的数据
              zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
              //创建LocalSocket的输出流,以便可以向Zygote进程发送数据。
              zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                      zygoteSocket.getOutputStream()), 256);
          } catch (IOException ex) {
              try {
                  zygoteSocket.close();
              } catch (IOException ignore) {
              }
              throw ex;
          }
          String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
          Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);
          return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                  Arrays.asList(abiListString.split(",")));
      }
  }
  建立Socket连接的流程很明朗了,如下所示:
  创建LocalSocket对象。
  将LocalSocket与LocalServerSocket建立连接,建立连接的过程就是LocalSocket对象在/dev/socket目录下查找一个名称为"zygote"的文件,然后将自己与其绑定起来,这样就建立了连接。
  创建LocalSocket的输入流,以便可以接收Zygote进程发送过来的数据。
  创建LocalSocket的输出流,以便可以向Zygote进程发送数据。

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号