前言
2022年的第一篇分享文章,整整一周,利用晚上下班时间梳理了桌面点击APP到打开的流程,可以说看似简简单单的一个操作,里边的过程相当复杂,各种进程间通信等等,下面我们一起看看整个流程是怎么样的。
正文
我们先通过一张图来看整个流程的一个概览:
startActivity
桌面点击app到打开,涉及了三个进程,分别如下:
Launcher进程:它是一个Activity,可以把桌面看成是一个app,里边有多个啊、其他app的入口,当点击app图标时,就会去启动对应的app,并且跳转至页面。
SystemServer进程:在Android系统中有着重要的作用,由Zygote进程fork出来,许多重要的服务,都是在此进程开启的,例如ActivityManagerService、InputManagerService和WindowManagerService等等。
APP进程:我们要启动的app的进程。
startActivity
首先我们从startActivity开始,startActivity最终会调用startActivityForResult:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
//...
} else {
//...
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在这里我们先了解一下Instrumentation,每个Activity都会持有一个Instrumentation引用,整个进程只会有一个Instrumentation的实例,它主要是完成对Application和Activity初始化和生命周期的工具类。
我们可以看到,里边调用了mInstrumentation的execStartActivity方法,其中的核心代码如下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//...
try {
//...
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
()返回的是一个ActivityManagerProxy,它就是用来与AMS进行通信的,AMS是运行在system_server进程中的,这一次的调用,实际是通过Binder的方式,调用到了AMS的startActivity方法。
fork创建新进程
调用了ActivityManagerService的startActivity方法后,经过一系列的调用,来到了startProcesslocked方法,然后会通过()方法,这次使用的是socket通信方式向zygote进程发送一个创建新进程的请求,也就是请求Zygote去创建App进程。
Zygote进程监听到有创建新进程的请求后,便会fork新的进程,并返回对应的pid。新进程创建后,然后会执行ActivityThread的main()方法。
这里说一下Zygote进程:由init进程fork出来的,当创建app进程时,都是由zygote进程fork而来的。
不知你会不会有两个疑问:
为什么SystemServer进程与Zegote进程通信不是使用Binder而是使用Socket?下面整理了网友的几点回答。
- zegote比serviceManager先启动,这点从先后顺序看,没有serviceManager可以注册,没法用Binder。
- 假设它们谁先启动这个顺序不确定,但是如果serviceManager先启动,但没法保证它先初始化完。
- 在安全性上,socket的所有者是root,group是system,只有系统权限用户才能进行读写。
为什么APP进程需要由Zegote进程fork出来?
我们知道每个APP都运行在独立的Dalvik虚拟机中,如果每启动一个APP就得去单独启动跟初始化,那么是比较耗时的。Zegote进程会把已经加载好的虚拟机代码和内存信息共享,通过它fork会起到一个预加载作用,加快了app的启动。
绑定Application
创建线程后,便会执行ActivityThread的main函数,main函数里边会启动主线程的Looper。在我们初学Java的时候可以知道,main函数是一个应用程序的入口。
main函数里边会调用ActivityThread的attach方法。
//由于在main方法里边调用传进来的system为false,所以我们只看第一个分支。
private void attach(boolean system, long startSeq) {
//...
if (!system) {
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {
//...
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
attach方法中,会远程调用ActivityManagerService的attachApplication方法,ActivityManagerService最后会通过远程调用ActivityThread的bindApplication,bindApplication会发送一个BIND_APPLICATION的消息,
public final void bindApplication(String processName, ApplicationInfo appInfo,
ProviderInfoList providerList, ComponentName instrumentationName,/*省略n个参数*/) {
//...
sendMessage(H.BIND_APPLICATION, data);
}
- 1
- 2
- 3
- 4
- 5
接收到此消息后,通过handleBindApplication方法进行处理,然后调用LoadedApk的makeApplication方法,由Instrumentation加载Application实例出来,
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
//...
Application app = null;
//...
try {
final java.lang.ClassLoader cl = getClassLoader();
//...
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
//...
}
//...
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
//...
}
}
return app;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
newApplication方法里边会去加载出Application对象,并且调用它的attach方法。
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
创建完之后,回到ActivityThread的handleBindApplication方法,会通过Instrumentation去调用Application的onCreate方法。
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
//...
}
- 1
- 2
- 3
- 4
- 5
到这里Application的创建就完成了。
启动Activity
经过一连串的调用,最后会向H发送一个消息,这里的H是一个Handler,由于版本不同,所以这里会有不一样,它们最终都会调用到handleLaunchActivity方法:
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
//...
final Activity a = performLaunchActivity(r, customIntent);
//...
return a;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
performLaunchActivity方法里边会创建Activity,并且走onCreate
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//...
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//...
} catch (Exception e) {
//...
}
try {
//...设置一些参数等,还有attach进Application
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
//...
}
r.setState(ON_CREATE);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
//...
}
return activity;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
可以看到,又有Instrumentation的身影,此方法里边通过mInstrumentation去创建Activity,然后设置参数、校验等操作后,再继续调用callActivityOnCreate方法,里边会去调用Activity的onCreate方法,至此,Activity被创建好了。
接下来就是继续通过Handler,然后去调用Activity的onStart、onResume,到这里,Activity就可见了。
小结
最后我们回顾一下整个流程:
- 在桌面点击app图标,Launcher响应点击事件,然后经过调用,通过Binder的方式告诉在system_server进程中的ActivityManagerService去startActivity
- ActivityManagerService收到调用后,便会去请求创建一个新的进程,它通过Socket的方式,告诉Zygote进程去启动一个新的进程。
- 新的进程启动后,会执行ActivityThread的main方法,这是程序的入口,并且会开始Looper。
- 在main中,会去请求ActivityManagerService进行attach Application,再经过一系列的调用,会回到app进程,创建Application,并且让Application进行attach。
- Application创建绑定完,便开始创建Activity,由AMS告诉APP进程去scheduleLaunchActivity,APP进程会发送一个Handler的消息,收到这个消息后由Instrumentation去创建Activity,接着继续去调用Activity的onCreate、onStart和onResume的生命周期,至此,从桌面点击APP的图标到APP启动至可见已完成。
结语
到这里我们便把APP的启动流程过了一遍,看似很简单的一个操作,实际上系统帮我们做了很多的事情。当然在源码上不同版本会存在不一样,但它们的流程基本是一样的,只是一些方法或者细节做了改变。