转载

Android从开机到打开第一个应用发生了什么?

序言

昨日阿里二面,跪的很惨,项目,算法,计算机基础不问,问Linux内核,我是投的android实习岗,要求是对于android底层有很深厚的基础,问了binder的实现机制,activity栈的管理回退等等,这都是android高级工程师进阶的书里才会讲的东西,这让我很慌呀。啃底层,再战。讲底层,先从系统启动流程开始,这个过程发生了什么,然后逐步分析这个每个流程又做了些什么,在我们的系统中起到一个什么作用。不打算深入代码细节去看,当然能力也是不够的,从整体上有个森林。

启动过程

先对启动的过程来一个概览,因为android是基于Linux,所以这里从Linux内核的启动开始到android中的相应服务的启动,对于具体应用的开启下面讲。

根据这个图,讲一下整个流程。

  1. 当我们开机的时候,此时通电了,这个时候就会触发CMOS(ROM的一种),上面的代码是基本输入输出系统,BIOS得到执行。

  2. BIOS从我们的磁盘中寻找我们操作系统引导程序,将引导程序加载到内存中,执行,然后将我们的Linux内核加载到内存中。

  3. 启动init进程,这个进程是用户态所有进程的祖先,内核态是叫做内核线程和用户进程差不多。

  4. init进程首先通过fork创建子进程,首先是Daemon进程也就是守护进程,包括USB守护进程,Debug进程,无线通信连接守护进程。

  5. fork出Context Manager,通过上图我们可以看出,android系统提供的服务都要向其进行注册,然后其它的进程才可以调用这个服务。

  6. Media Server,这个服务是本地服务,不是Java服务,不需要再通过dalvik虚拟机装载执行,本地服务单独开启了一个进程。这里包括Audio Flinger和Camera Service。

  7. Zygote,所有Android应用程序的祖先,其用来缩短应用程序的加载时间,具体怎么节省,下面详解。

  8. System Server是android系统中的一个核心进程,提供了管理应用程序生命周期,地理位置信息等各种服务。同时其需要将自身注册到Context Manager.但是我们的服务管理器是基于C语言的,所以我们需要JNI本地编程接口。这个时候Activity Manager Service会运行HOME应用。

大致我们已经了解了启动的流程Linux内核,init进程fork出多个进程,zygote用来孵化Java系统服务,同时孵化应用程序。接下来,我们再深入的去看一下。zygote是如何被创建出来的。

Zygote创建过程

对于Service的创建,在后面讲到Service的时候单独再说,先讲Zygote,因为这是我们的所有应用开启的基石。因为zygote是Java代码,所以需要装载到Dalvik VM上执行,所以在启动Zygote之前要启动Dalvik VM,所以这里要分为两步了,第一步启动Dalvik VM,第二步是启动Zygote。

  1. 首先生成了一个AppRuntime对象,该类是继承自AndroidRuntime的,该类用来初始化并且运行Dalvik 虚拟机,为运行Android应用做好准备。接受main函数传递进来的参数,然后初始化虚拟机。

  2. 虚拟机初始化之后,运行ZygoteInit类,通过路径查找找到,现在程序的执行转向了虚拟机Java代码的执行,首先执行器main函数,接下来就是Zygote的作用过程了,在下面部分。

Zygote启动应用过程

  1. Zygote执行之后,首先是绑定一个套接字,用来接收从Activity Manager来的应用启动请求(这里我们可以想到网络通讯中的Socket通信)

  2. 将应用程序框架中的类,平台资源(图像,XML信息,字符串)预先加载到内存中,借此提升程序的执行速度。Android也是通过在Zygote创建的时候加载资源,生成信息链接等,以后再有应用启动,fork出一个子进程和父进程共享这些信息,而不需要重新加载,同时也共享虚拟机,因为虚拟机在初始化和创建的过程是很耗时的。

  3. 前面也提到过一些system server也是java的,而且我们的应用启动等需要这些server的参与,所以在启动应用之前先启动了这些System server,然后启动Server Thread来执行android framework的服务,同时这些服务在启动的时候都是需要通过JNI向服务管理器Context Manager注册。经历了上述步骤的zygote处在轮询监听Socket,当有请求到达,读取请求,fork出子进程,加载进程所需要的类,然后执行要执行程序的main函数,代码转给了Dalvik Vm,我们的应用程序也就启动起来了。这个时候,将关闭套接字,删除请求描述符,防止出现重复启动。

上面只是对整体流程进行了一个概述,细节涉及不深,这里再提一下,虚拟机,究竟是什么呢?这里的虚拟机可以理解成,可以解析Java字节码的内存上的一条条指令,各个应用共享这个虚拟机,也就是都是知道虚拟机的内存中地址,传递进java字节码,然后解析字节码,将字节码实际代表的操作反应出来,多个应用程序可以交替使用,通过寄存器记录彼此执行后的状态。fork出一个进程之后,我们装载应用程序相应的类,然后执行。

原文  https://segmentfault.com/a/1190000004676352
正文到此结束
Loading...