文章目录
●一 进程的创建与启动流程
●二 进程的优先级
●三 进程的调度流程
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层
通过上述流程的分析,想必读者已经对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),我们将立即处理。