由于工作原因,需要通过一些安卓Demo来学习熟悉部门相关业务,配完环境后,看了下手头的电子书,内容很多,最近正好做一些学习笔记整理。
本文首先介绍Android的基本架构,接着介绍整体的启动流程,最后根据init进程所在的位置,展开介绍。
由于工作原因,需要通过一些安卓Demo来学习熟悉部门相关业务,配完环境后,看了下手头的电子书,内容很多,最近正好做一些学习笔记整理,我带大概分了下类:
Android是个很大的领域,相关书籍、博客、教程非常多,但是作为一个未接触过Android的小白,如此巨量的信息让我头疼不已,为了方便自己学习,同时也能帮助到其他类似的伙伴,我将自己的学习思路整理如下。也许笔记不会特别细致深入,但希望整理的内容能帮忙厘清思路。
图1 是官方给出的Android基本架构,一般可以简单概括为:内核、系统库(把ART也算进去)、系统框架、系统应用四个大类,尽管分层清晰,但在我学习过程中,发现很多机制、服务深究起来,还是会横跨多个层。
从Linux操作系统的角度来看,第2层是内核空间与用户空间的分界线,第1层运行于内核空间,第2、3、4层次运行于用户空间。
通过Android的系统架构,也可以看出在针对应用开发、系统开发、驱动开发时需要了解哪些知识:
Linux知识:Android是基于Linux内核的,编译Android源码也必须在Linux上,所以必须掌握Linux的基础知识(操作区别、简单指令、进程等)。
C/C++知识:Android大部分核心库是C/C++的动态链接库,系统大部分隐藏API都是在这里面的。
Java知识:Android是80%的Java package,IDE和语言都是Java,尤其是多线程、I/O流、面向对象思想、http和socket网络等。
T-SQL知识(可以只是基础的增删改查和子查询)。
图2 Android基本架构对应的工作领域
个人思考: Android的架构就像是一个总纲和字典,测试人员(感觉开发一样)根据需要随时翻看,虽然没有开发人员聚焦深入,但是广度要求比较高。
Android 系统框架可参考外网博文:Android 操作系统架构开篇-Gityuan
如图所示, Android启动中有很多资源需要逐步加载,进而一步一步从底层走向我们熟知的界面。
图3 Android启动基本流程
启动ROM代码从预先定义的位置开始执行。
它将引导加载程序加载到RAM中并开始执行。这是为了确定在何处找到引导加载程序的第一阶段。一旦引导媒体序列建立,引导ROM将尝试加载第一阶段的引导加载程序到内部RAM。一旦引导加载程序就位,引导ROM代码将执行跳转并继续在引导加载程序中执行。
类似于BIOS系统,包含两个阶段:1、是检测外部RAM,2、是帮助加载程序。
在第二个阶段Bootloader设置网络、内存等需要运行内核的时候,Bootloader可以为内核提供特定目的的配置参数或输入,这可能包含用于设置文件系统、额外内存、网络支持和其他内容的代码。一旦引导加载程序完成了任何特殊任务,它就会寻找要引导的Linux内核。它将从引导媒体(或其他取决于系统配置的源)加载此文件,并将其放在RAM中。它还将在内存中放置一些引导参数,以便内核在启动时读取。
Linux内核在Android上启动的方式与在其他系统上类似。
它将设置系统运行所需的一切。初始化中断控制器,设置内存保护,缓存和调度。一旦内存管理单元和缓存被初始化,系统将能够使用虚拟内存并启动用户空间进程。 内核将在根文件系统中查找init进程(在Android开源树的system/core/init下找到),并将其作为初始用户空间进程启动。
init进程有两个任务:
1、挂载挂载目录。参考: 史上最详细linux启动过程讲解—没有之一 ;
2、运行init.rc脚本(安卓命令):Android init.rc文件详解_。
严格讲,Android实际是运行于Linux内核上的一系列服务进程,而这些进程则是通过init逐步开启的。在 linux的init的基础上,通过解析一init.rc
脚本,执行 开启android需要的一系列服务。
Zygote是第一个虚拟机进程,是一个应用程序,原名为app_process,在启动中被修改Zygote。
单独的虚拟机(VMs)实例会在内存中为单独的应用程序弹出,在Android应用程序应该尽快启动的情况下,如果Android os为每个应用程序启动不同的Dalvik VM实例,那么它会消耗大量的内存和时间。因此直接通过Fork一个原始的虚拟机(Zygote),则可以快速得到多个虚拟机,这也是为什么使用Zygote。如图4所示。
图4 Zygote与其他应用进程的共享内存
Zygote有两个作用: 创建SystremServer; 孵化应用进程。
Zygote进程预加载系统资源后,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度。
Zygote进行fork的时候要是单线程,为了避免造成死锁或者状态不一致等问题
Zygote的跨进程通信没有采用Binder机制,而是采用本地socket
fork其他进程使用Zygote,而非systermserver,是因为Systemserver包含很多应用服务,应用程序不能继承。
Zygote的IPC通信机制采用的是Socket而不是binder。
具体参考:谈谈对Android中Zygote的理解-(知乎)
进程名为systerm_server,可以说是Zygote的长子。
图5 SystemServer的启动(《深入理解Android》第四章Zygote)
一般我们是通过桌面->图标->启动APP,这个过程涉及“三进程,六大类”。
首先,一开始看到的桌面,同样是一个Activity进程,是系统启动后,首先Lancher的一个进程,主要用于展现界面以及听用户的输入。显示桌面视图的Activity是com.xxxx(系统版本).home包下的名为Launcher的Activity。
应用启动中,由于Launcher是Activity,那点击桌面的事件可以表达为:呈现Android桌面视图(View)->点击View上某个应用图标->产生点击事件->点击事件被响应->通知Android系统的某个/某些进程->Android系统执行某些操作->启动App。
图6 APP启动流程
启动中的三大进程与六个大类如图6所示:
三大进程
六个大类:
具体内容可以参考:Android App启动流程详解_mysimplelove的博客-CSDN博客_android app启动流程
采用博客中的总结(APP启动):
通过学习Android的整体启动流程,我们可以看到,init最重要的就是创建Zygtoe进程(ServiceManager也很重要与Binder通信机制相关),从而进入Android世界,可以说init是衔接Linux内核与Android的重要节点,是这两个世界的分界线。
图7 Init进程的主要操作
init.rc是一系列操作命令,用于开启一系列重要的服务。服务本质是可执行程序,在命令特定项约束下,被init程序运行或者重启。init中陆续启动ServiceManager,Zygote, SystemServer。
到此为止,虽然没有对init这个1号进程展开非常详细的学习,但目前已经掌握init在整个启动中的位置与意义。
具体每个细节与技术(如:Zygote、Servicemanager、SystemService)在后续分别学习各个模块时展开。
init的源码学习可以参考: Android的init过程详解(一) - 银河使者 - 博客园
图8 RC命令主要操作(《深入理解Android内核设计思想第7章》)