XJBX-6-Android启动App进程

一、应用进程启动

Android应用程序的载体是APK文件,说白了就是一堆资源文件,SO库,Class文件的一个压缩包。Android进程本质也是Java虚拟机去执行的这一堆文件。应用开发很少接触进程这种概念,都是已组件的形式,Activity代表界面,Service代表后台,ContentProvider代表数据库,BroadCast代表通信,这种组件的形式刻在每个开发同学的婶婶的脑海里,弱化了进程的概念。BUT,进程有main函数的入口,就在ActivityThread类。源码路径/frameworks/base/core/java/android/app/ActivityThread.java

应用进程的组成

对于一个APP进程,有以下核心的成员类需要关注一下。Activity,Service,Provider都是以ArrayMap的形式来保存。BroadcastReceiver生命周期很短,一次性调用,所以不用保存。mInitialApplication是进程唯一的Application对象。Application提供一些应用进程变化的回调接口:

  • onCreate() 应用创建。
  • onTerminate() 应用销毁时。
  • onConfigurationChanged() 系统配置变化时。
  • onLowMemory() 在系统内存不足时调用。
  • onTrimMemory(int level) 在系统要求应用释放多余内存时调用。

ApplicationThread是个Binder类型的实体对象,AMS可以通过此对象调用APP接口,将BInder调用转化成消息来排队处理,搭配一个Handler类H,所有的消息都在此处理。 另外有两个保存APK信息的对象:mResourcePackages保存只含有资源的APK文件,mPacakge保存包含代码的APK文件。所以更加坐实,APP进程其实就是运行了几个Java类和一些资源文件。

linux进程启动的方式

启动进程有两种方式。调用fork函数启动子进程,pid为0时代表在子进程返回值,否则是父进程。左边启动方式,默认继承父进程的系统资源。右边execve方式传入启动参数,父进程资源全被清空掉。Android系统采用了Linux内核,因此,Android应用进程的创建与Linux如出一辙。 ps: path代表二进制程序的路径,argv代表需要设置的参数,env代表需要设置的环境变量。

Android 应用进程启动的基本流程与原理

在这里要明白两个问题:

1、什么时候才会触发进程启动?

2、进程是谁来启动?怎么启动?

Android系统里面没有接口可以调用去主动启动一个进程,全是被动的启动。启用组件的时候,发现组件发在的进程不存在,才会去启动进程。这些功能都是在Framework中去做的,AMS在此流程中扮演了很重要的的角色。

java 复制代码
//ActivityStackSupervisor.java
//查找组件所在的进程
ProcessRecord app = getProcessRecordLocked();
if (app != null && app.thread != null) {
 	//进程已经启动,可以启动组件
 	realStartActivityLocked(...); 
}
startProcessLocked(r.processname);//发起启动进程

这里重点 app.thread != null条件,这是判断IApplicationThread(AMS拿到的应用binder句柄),实现双向的binder调用。

那IApplicationThread句柄是怎么传给AMS的呢?AMS通过配置Zygote启动的参数,最终通过socket写入到Zygote进程,Zygote进程收到socket请求后会处理请求参数,同时对于该进程,也指定了一个类作为执行的入口类,这个类就是ActivityThread。ActivityThread中main方法,作为应用进程的入口,所有的应用进程的初始化都会走这重要的四行代码。

java 复制代码
//ActivityThread.java
public static void main(String[] args) {
     Looper.prepareMainLooper();//创建主线程looper
     ActivityThread thread = new ActivityThread();
     thread.attach(false);//让AMS持有应用端的binder句柄。
     Looper.loop();
}

//获取ActivityManager句柄
 final IActivityManager mgr = ActivityManager.getService(); 
 //告诉AMS应用进程已经启动,并传入应用进程自己的binder句柄IApplicationThread              
 mgr.attachApplication(mAppThread);

因此,对一个应用进程启动完成的标志就是以下两点:

1、AMS向Zygote发起启动进程的请求,zygote启动完进程之后会给AMS返回进程pid。

2、应用启动后,向AMS注册IApplicationThread。

会不会有一种可能,进程已经启动,但是还没有来得及注册Thread,然后另外一个组件去启动,会不会重复启动进程呢?

java 复制代码
//startProcessLocked
if(app != null && app.pid > 0){
//如果进程信息不为空,并且已经拿到了Zygote进程返回的应用进程pid
//app.pid > 0 说明AMS已经请求过了,并且Zygote已经响应请求然后fork出进程了
	if(app.thread ==. null){
//但是app.thread还是空,说明应用进程还没来得及注册自己的binder句柄给AMS
//即此时进程正在启动,那就直接返回,避免重复创建
		return app;
	}
}

综上,Android应用进程的启动可以总结成以下步骤:

1、AMS判断APP进程是否存在,不存在则发起socket请求。

2、Zygote进程接收请求并处理参数。

3、Zygote进程fork出应用进程,应用进程继承得到虚拟机实例。

4、应用进程启动binder线程池、运行ActivityThread类的main函数、启动Looper循环。

二、应用中启用的binder机制

在何处启用binder机制。

startProcessLocked方法除了判断进程判断,还会负责进程启动的核心逻辑。

前边可知,AMS通过Socket与Zygote发送请求参数,Zygote收到socket请求后会通过ZygoteConnection,核心逻辑在runOnce方法中,会调用handleChildProc。

java 复制代码
//ZygoteConnection.java部分代码
boolean runOnce(){
	String[] args = readArgumentList();
	int pid = Zygote.forkAndSpecialize(...)
	if(pid == 0){
		handleChildProc(...);
		return true;
	}else {
		return handleParentProc(pid,...);
	}
}

handleChildProc方法调用了ZygoteInit的zygoteInit方法,里边主要做了3件事:

1、启动binder线程池;

2、读取请求参数拿到ActivityThread类并执行他的main函数,执行thread.attach告知AMS并回传自己的binder句柄;

3、执行Looper.loop启动消息循环;

怎么启用binder机制

1、打开binder驱动。 2、映射内存,分配缓冲区。 3、注册binder线程。 4、进入binder loop 详细内容后续Binder模块会单独讲解。

源码好无聊,有兴趣自己去看吧,说了那么多,面试的时候你知道该怎么吹了吧......

相关推荐
千里马-horse1 小时前
android vlc播放rtsp
android·media·rtsp·mediaplayer·vlc
難釋懷1 小时前
Android开发-文本输入
android·gitee
志存高远663 小时前
(面试)Android各版本新特性
android
IT从业者张某某3 小时前
信奥赛-刷题笔记-队列篇-T3-P3662Why Did the Cow Cross the Road II S
android·笔记
未来之窗软件服务4 小时前
Cacti 未经身份验证SQL注入漏洞
android·数据库·sql·服务器安全
BXCQ_xuan4 小时前
handsome主题美化及优化:10.1.0最新版 - 2
android
圈圈编码4 小时前
MVVM框架
android·学习·kotlin
橙子199110166 小时前
在 Kotlin 中,什么是解构,如何使用?
android·开发语言·kotlin
androidwork7 小时前
Android 中使用通知(Kotlin 版)
android·kotlin
Digitally8 小时前
如何从 Android 设备打印短信(5 种方法)
android