多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
#### **参考文章**: [深入了解Android系统之系统开篇](https://www.kancloud.cn/alex_wsc/androidsystem/403521) [Google官方AndroidAPI指南之线程和进程](https://www.kancloud.cn/alex_wsc/android_google/488784) [进程线程](http://note.youdao.com/noteshare?id=de140840a1da668b7f2f7f3facb34620) [Android多线程的四种方式](http://mp.weixin.qq.com/s/Gv600dQgjqx5gQNM5_nm7Q) [android 中 任务、进程和线程的区别](https://www.2cto.com/kf/201606/518400.html) 关于进程中知识,可以参考Git袁大神的博客,鄙人整理的文章[进程](https://www.kancloud.cn/alex_wsc/androidsystem/403689) 如何查看手机中运行的进程,参考一下文章: 可以通过命令,也可以通过工具(DDMS、Android Device Monitor): [android查看当前手机中的进程](http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51373694) [adb 查看手机正在运行的进程](http://blog.csdn.net/xingchenxuanfeng/article/details/50386689) [Android中使用ps命令查看进程PID](http://blog.csdn.net/yin1031468524/article/details/60772562) [查看android进程信息](http://blog.csdn.net/ynnmnm/article/details/38417829) [在Android Studio中使用Method trace,查看某进程的所有线程trace的方法 ](https://segmentfault.com/a/1190000011084104) 下图是使用AS在它的终端栏使用`adb shell ps` 命令得到系统中存在的进程 :-: ![](https://box.kancloud.cn/1ad818e064e63e422da00b292f04d099_838x289.jpg) 图1 手机中的进程信息 各列参数意义: * USER        进程当前用户; * PID             Process ID,进程ID; * PPID          Process Parent ID,进程的父进程ID; * VSIZE        Virtual Size,进程的虚拟内存大小; * RSS           Resident Set Size,实际驻留"在内存中"的内存大小; * WCHAN    休眠进程在内核中的地址; * PC              Program Counter; * NAME        进程名; **可以跟findstr结合搜索,过滤得到自己想要找的进程**,如 ~~~ adb shell ps | findstr sina ~~~ :-: ![过滤手机中的进程信息](https://box.kancloud.cn/e11c1f5592a99aa7db9a0b372446ad76_985x169.jpg) 图 2 过滤手机中的进程信息 ### **进程** 我们以进程的角度来看一下系统启动流程: [点击查看大图](https://box.kancloud.cn/dfd42ed393f8add8418c5ff6d994b7ff_2904x1536.jpg) :-: ![](https://box.kancloud.cn/dfd42ed393f8add8418c5ff6d994b7ff_2904x1536.jpg) 图3 系统启动架构图 >[info] **注意**:上图我们是以**Android6.0源码**为准则来研究Android的系统架构,如果是其它版本的源码,流程可能会有细微差别,比如Android4.4W(API 20)以及其以下版本中的流程可能就会不一样,可能是因为Android虚拟机由Dalvik转换成Android Runtime,这一点还有待验证。 #### **Android系统的启动过程** >[warning] 注意:以Android2.3.7(API 10)源码来研究启动流程 Android系统的启动分为3个步骤: 1. Linux启动: * BootLoader 嵌入式系统的一个引导程序 * Kernel 驱动在这一层启动 2. Android系统启动 init.rc启动(系统启动的配置文件) - servicemanager(binder守护线程) - Runtime - Zygote [app_main.cpp](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/cmds/app_process/app_main.cpp)------->/frameworks/ base/ cmds/ app_process/ app_main.cpp - Start VM - System Server - Start Android Services Register to ServiceManager 实际真正起作用的是[AndroidRuntime.cpp](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/jni/AndroidRuntime.cpp)(\frameworks\base\core\jni\AndroidRuntime.cpp) - Start Launcher init.rc的源码在根目录: /system /core/ rootdir/ init.rc,可以参考网上的源码[init.rc](https://www.androidos.net.cn/android/2.3.7_r1/xref/system/core/rootdir/init.rc) 3. 应用程序启动 Running PackageManager 整体流程图如下图2所示 [点击查看大图](https://box.kancloud.cn/40971b42480183b0ff957cb05041200e_1943x1712.png) :-: ![Android系统启动流程](https://box.kancloud.cn/40971b42480183b0ff957cb05041200e_1943x1712.png) 图4 Android系统启动流程 接下来就是应用程序的启动过程了,可以参考老罗的系统源代码情景分析,也可以参考[老罗的博客老罗Android之旅之应用程序的完整显示过程](https://www.kancloud.cn/alex_wsc/androids/477738)。也可以参考下图APP的启动流程 :-: ![](https://box.kancloud.cn/d5004f56956928ceea19a35435c82405_1084x739.jpg) 图5 APP启动流程 >[warning] **注意**:上面这张图只是一个大致流程,具体的细节可能有所出入。 关于Zygote和System进程的启动过程的其他文章,同样可参考老罗的系统源代码情景分析,和他的博客文章——[Android系统进程Zygote启动过程的源代码分析](http://blog.csdn.net/luoshengyang/article/details/6768304) 在Android 系统中,存在如下3个十分重要的进程系统。 * Zygote 进程:被称为“孵化”进程或“孕育”进程,功能和Linux系统的fork类似,用于“孕育”产生出不同的子进程。 * System 进程:是系统进程,是整个Android Framework 所在的进程,用于启动Android系统。其核心进程是system_server,它的父进程就是Zygote * 应用程序进程:每个Android应用程序运行后都会拥有自己的进程,这和Windows 资源管理器中的体现的进程是同一个含义。 >[info] **注意**:Dalvik 虚拟机的实现离不开进程管理,其进程管理特别依赖于Linux 的进程体系。例如要为应用程序创建一个进程, 会使用Linux 的FORK机制复制一个进程,因为复制进程的过程比创建进程的效率要高。并且在Linux 中进程之间的通信方式有很多,例如通道、信号、报文和共享内存等,这样对进程管理将更加方便。 关于Zygote进程,还需要了解以下几点 1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android 应用程序框架层的其他进程的创建和启动工作。 2. Zygote进程会首先创建一个SystemServer进程,SystemServer 进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。 3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。 当Zygote进程在使用Linux的fork机制时有如下三种不同的方式。 * fork():孕育一个普通的进程,该进程属于Zygote进程。 * forkAndSpcecialize():孕育一个特殊的进程,该进程不再是Zygote进程。 * forkSystemServer():孕育一个系统服务进程。 :-: ![](https://box.kancloud.cn/ad48b52f02d89156b5fac7bd73ea82ff_750x692.png) 图5 fork进程的关系 Zygote进程可以再孕育出其他进程,非Zygote进程则不能孕育出其他进程。当终止系统服务进程后, 也必须终止其父进程。 Zygote 本身是一个应用层的程序,和驱动、内核模块没有任何关系。Zygote的启动由Linux的init启动。启动后看到的进程名叫zygote,其最初的名字是app_process,通过直接调用pctrl把名字给改成了“zygote ” 。 从总体架构上看,Zygote是一个简单的典型C/S结构。其他进程作为一个客服端向Zygote发出“孕育”请求,当Zygote接收到命令后就“孕育”出一个Activity进程。 #### **Dalvik虚拟机运行相关** **创建一个虚拟机** :-: ![创建运行Dalvik虚拟机](https://box.kancloud.cn/9cb14dabefe1eb51fe6dd91a78c8f928_912x212.png) 图 6 创建运行Dalvik虚拟机 * **使用工具** - dalvikvm 当Java 程序运行时,都是由一个虚拟机来解释Java 的字节码,将这些字节码翻译成本地CPU 的指令码,然后再执行。对Java 程序而言,负责解释并执行的就是一个虚拟机,而对于Linux 而言,这个进程只是一个普通的进程,它与一个只有一行代码的Hello World 可执行程序无本质的区别。所以启动一个虚拟机的方法就跟启动任何一个可执行程序的方法是相同的,那就是在命令行下输入可执行程序的名称,并在参数中指定要执行的Java 类。dalvikvm 的作用就是创建一个虚拟机并执行参数中指定的Java 类。 - dvz 在Dalvik 虚拟机中, dvz 的作用是从Zygote进程中孵化出一个新的进程,新的进程也是一个Dalvik虚拟机。该进程与dalvikvm 启动的虚拟机的区别在于该进程中已经预装了Framework的大部分类和资源。 * app_process dalvikvm 和dvz 是通用的两个工具, 然而Framework在启动时需要加载并运行如下两个特定Java类:ZygoteInit.java和SystemServer.java。 为了便于使用,系统才提供了一个app_process进程,该进程会自动运行这两个类,从这个角度来讲, app_process 的本质就是使用dalvikvm 启动ZygoteInit.java。并在启动后加载Framework中的大部分类和资源。 如何创建虚拟机并执行指定的class文件的。其源代码在文件frameworks/base/cmds/app_ main.cpp 中,该文件中的关键代码有如下两处: 第一处:先创建一个App Runtime 对象; 第二处:调用runtime 的start()方法启动指定的class 。 在系统中只有一处使用了app_process ,那就是在init.rc 中。因为在使用时参数包含了“ -zygote ” 及“ -start-system-server ",所以这里仅分析包含这两个参数的情况。start()方式是类AppRuntime 的成员函数,而AppRuntime 是在该文件中定义的-个应用类,其父类是AndroidRuntime,该类的实现在文件frameworkds/base/core/jni/AndroidRuntime.cpp 中。在函数start()中,首先调用startVm()创建了一个vm 对象,然后就和dalvikvm一样先找到Class(), 再执行class 中函数main(),使用startVm() 函数创建vm对象。 由上述过程可以看出,app_process和dalvikvm 在本质上是相同的,唯一的区别就是app_process可以指定一些特别的参数,这些参数有利于Framework启动特定的类,并进行一些特别的系统 环境参数设置。 **Dalvik虚拟机的初始化:** 1. 开始虚拟机的准备工作 2. 初始化跟踪显示系统 3. 初始化垃圾回收器 4. 初始化线程列表和主线程环境参数 5. 分配内部操作方法的表格内存 6. 初始化虚拟机的指令码相关的内容 7. 分配指令寄存器状态的内存 8. 分配指令寄存器状态的内存 9. 初始化虚拟机最基本用的Java 库 10. 进一步使用的Java 类库线程类 11. 初始化虚拟机使用的异常Java 类库 12. 释放字符串晗希表 13. 初始化本地方法库的表 14. 初始化内部本地方法 15. 初始化JNI 调用表 16. 缓存Java 类库里的反射类 #### **进程间通信** 对于IPC(Inter-Process Communication, 进程间通信),**Linux现有管道、消息队列、共享内存、套接字、信号量、信号**这些IPC机制,Android额外还有Binder IPC机制,Android OS中的**Zygote进程的IPC采用的是Socket机制**,在**上层System Server、Media Server以及上层App之间更多的是采用Binder IPC方式来完成跨进程间的通信**。对于Android上层架构中,很多时候是在同一个进程的线程之间需要相互通信,例如**同一个进程的主线程与工作线程之间的通信,往往采用的Handler消息机制。** * **Binder IPC原理** Binder通信**采用C/S架构**,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。 :-: ![](http://gityuan.com/images/binder/prepare/IPC-Binder.jpg) 图7 startService过程所涉及的Binder对象的架构图 * **Socket** **Socket通信方式也是C/S架构**,比Binder简单很多。在Android系统中采用Socket通信方式的主要: * zygote:用于孵化进程,系统进程system_server孵化进程时便通过socket向zygote进程发起请求; * installd:用于安装App的守护进程,上层PackageManagerService很多实现最终都是交给它来完成; * lmkd:lowmemorykiller的守护进程,Java层的LowMemoryKiller最终都是由lmkd来完成; * adbd:这个也不用说,用于服务adb; * logcatd:这个不用说,用于服务logcat; * vold:即volume Daemon,是存储类的守护进程,用于负责如USB、Sdcard等存储设备的事件处理。 等等还有很多,这里不一一列举,**Socket方式更多的用于Android framework层与native层之间的通信** * **Handler** **Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信**,Handler消息机制是由一组MessageQueue、Message、Looper、Handler共同组成的,为了方便且称之为Handler消息机制。 有人可能会疑惑,**为何Binder/Socket用于进程间通信,能否用于线程间通信呢?答案是肯定,对于两个具有独立地址空间的进程通信都可以,当然也能用于共享内存空间的两个线程间通信,这就好比杀鸡用牛刀**。接着可能还有人会疑惑,那**handler消息机制能否用于进程间通信?答案是不能,Handler只能用于共享内存地址空间的两个线程间通信,即同进程的两个线程间通信**。很多时候,Handler是工作线程向UI主线程发送消息,即App应用中只有主线程能更新UI,其他工作线程往往是完成相应工作后,通过Handler告知主线程需要做出相应地UI更新操作,**Handler分发相应的消息给UI主线程去完成。这只是Handler消息机制的一种处理流程,是不是只能工作线程向UI主线程发消息呢?其实不然,可以是UI线程向工作线程发送消息,也可以是多个工作线程之间通过handler发送消息。高焕堂老师说过,主线程内部也可以通过handler来传递消息** **主线程丢信息给自己** 如下面的代码----->主线程丢信息给自己 ~~~ // ac01.java //…….. public class ac01 extends Activity implements OnClickListener { private Handler h; public void onCreate(Bundle icicle) { //…….. h = new Handler(){ public void handleMessage(Message msg) { setTitle((String)msg.obj); }}; } public void onClick(View v) { switch (v.getId()) { case 101: h.removeMessages(0); Message m = h.obtainMessage(1, 1, 1, "this is my message."); h.sendMessage(m); // 将Message送入MQ里 break; case 102: finish(); break; } } } ~~~ #### 下面是**高焕堂老师的程序员到架构师课程关于进程的知识摘要** **IPC通信概念** * IPC(Inter-Process Communication)通信,是跨越两个不同进程(Process)之通信。 * 一般而言,一个Android应用程序里的各组件(如Activity、Service等)都在同一个进程里执行。这种在同一进程内的通信,又称为**短程通信**,意味着,两个Activity在同一个进程(Process)里执行。 * 相对地,**远程(Remote)通信**的意思是:两个组件(如Activity或Service)分别在不同的进程里执行;两者之间是IPC通信,又称远程通信。 **IPC通信的效率** * 当我们**启动某一支应用程序(App)时,Android系统里的Zygote服务孵化(Fork)一个新进程(Process)给它,然后将它(该App)加载到这个新诞生的进程里**。 * 基于Linux的安全限制,以及进程的基本特性(例如,不同进程的地址空间是独立的),如果两个类(或其对象)在同一个进程里执行时,两者沟通方便也快速 。但是,当它们分别在不同的进程里执行时,两者沟通就属于IPC跨进程沟通了,不如前者方便,也慢些 。 **Android的进程概念** * 一个进程是一个独立的执行空间,不会被正在其它进程里的程序所侵犯。这种保护方法是Android的重要安全机制。于是,得先认识进程的内涵,才能进一步了解跨进程IPC机制。 * 在**Android的进程里,有一个虚拟机(Virtual Machine,简称VM)的对象,可执行Java代码,也引导JNI本地程序的执行,实现Java与C/C++之间的沟通**;如下图: **每一进程有:一个VM对象、主线程、MQ和Looper** :-: ![](https://box.kancloud.cn/b1f9d2409b4350c1d40bd8a3760667dc_373x334.jpg) 图8 Android进程概念 * **每一个进程在诞生时,都会诞生一个主线程(Main Thread),以及诞生一个Looper类的对象和一个MQ(Message Queue)数据结构**。每当主线程作完事情,就会去执行Looper类。此时,不断地观察MQ的动态。如下图: **不同进程的地址空间是独立的** :-: ![](https://box.kancloud.cn/ad7b112bb4a165c597e19e259641b5ed_484x305.jpg) 图9 独立的进程空间 * 主线程最主要的工作就是处理UI画面的事件(Event),每当UI事件发生时,Android框架会丢信息(Message)到MQ里。主线程看到MQ有新的信息时,就取出信息,然后依据信息内容而去执行特定的函数。执行完毕,就再继续执行Looper类,不断地观察MQ的动态。 * 刚才说明了,当两个类都在同一个进程里执行时,两者之间的沟通,只要采取一般的函数调用(Function Call)就行了,既快速又方便。一旦两个类分别在不同的进程里执行时,两者之间的沟通,就不能采取一般的函数调用途径了,只好采取IPC沟通途径。 **IPC的IBinder接口 -- 定义与实现** Android框架的IPC沟通依赖单一的IBinder接口。此时Client端调用IBinder接口的transact()函数,透过IPC机制而调用到远方(Remote)的onTransact()函数。 在Android的源代码里,Java层的IBinder接口是定义于IBinder.java代码文档里。此程序文件如下: /frameworks/base/core/java/android/os/IBinder.java ~~~ public interface IBinder { ....................... public String getInterfaceDescriptor() throws RemoteException; public boolean pingBinder(); public boolean isBinderAlive(); public IInterface queryLocalInterface(String descriptor); public void dump(FileDescriptor fd, String[] args) throws RemoteException; public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException; public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException; public interface DeathRecipient { public void binderDied(); } public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException; public boolean unlinkToDeath(DeathRecipient recipient, int flags); } ~~~ IBinder接口定义了一些函数,可以让Client程序可以进行跨进程的調用(当然也能支持同进程的短程調用)。其中,最主要的一个函数就是:transact()函数。 **IBinder接口的实现类** 在Android的框架里,也撰写了Binder基类和BinderProxy类别来实作 IBinder接口。 Binder基类的很重要目的是支持跨进程调用Service,也就是让远程的Client可以跨进程调用某个Service。 Binder基类的主要函数是: * transact()函数 用来实作IBinder的transact()函数接口。 * execTransact()函数 其角色与transact()函数是相同的,只是这是用来让C/C++本地程序来調用的。 * onTransact()函数 这是一个抽象函数,让应用子类来覆写(Override)的。上述的transact()和execTransact()两者都是調用onTransact()函数来实现反向調用(IoC, Inversion of Control)的。 * init()函数 这是一个本地(Native)函数,让JNI模块来实现这个函数。Binder()构造函数(Constructor)会調用这个init()本地函数。 **Java层的BinderProxy基类定义** * 这个BinderProxy类也定义在Binder.java档案里 * 当我们看到类别名称是 XXXProxy时,就自然会联想到它是摆在Client进程里,担任Service端的分身(Proxy)。 * 由于跨进程沟通时,并不是从Java层直接沟通的,而是透过底层的Binder Driver驱动来沟通的,所以Client端的Java类别(如Activity)必须透过BinderProxy分身的IBinder接口,转而調用JNI本地模块来衔接到底层Binder Driver驱动服务,进而調用到正在另一个进程里执行的Service。 * 当Client透过IBinder接口而調用到BinderProxy的transact()函数,就調用到其 JNI本地模块的transact()函数,就能进而衔接到底层Binder Driver驱动服务了。 :-: ![](https://box.kancloud.cn/6648b4c5112b91540a3300499d5459a0_718x724.jpg) 图10 binder通信模型 在上图里,从JNI本地模块拉了一条红色虚线,表示这并非直接的通信途径。也就是,实际上是透过底层Binder Driver驱动才調用到BBinder的IBinder接口。