申明:源码基于Android8.0,主要分析启动流程,会省略大量的细节代码、参数。
不管我们从手机的主菜单进入应用程序的根Activity还是在应用内跳转到某个Activity都会调用startActivity方法。
startActivity方法最终都会走到startActivityForResult方法。然后借助Instrumentation类的execStartActivity方法来执行startActivity的任务,需要注意的是该方法的第二个参数它是ApplicationThread类型的,该类是ActivityThread的内部类,它是一个Binder,会被注册到AMS(ActivityManagerService)。启动Activity会涉及跨进程通信(应用进程和AMS所在进程),AMS拿到了应用端的代理Binder就可以跨进程调用应用进程中ApplicationThread类中的业务方法。
Instrumentation#execStartActivity
ActivityManager.getService()这行代码会拿到AMS的Binder代理,然后调用这个Binder代理的startActivity方法会导致跨进程调用到AMS的startActivity方法,同时将应用进程的Binder代理(whoThread)发送给AMS,以后AMS想联系应用进程就可以使用这个Binder代理(whoThread)。
现在已经跨进程调用到AMS的startActivity方法,然后经过一系列调用会走到startSpecificActivityLocked。
重点看下startSpecificActivityLocked方法:
void startSpecificActivityLocked(...) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
//app所在进程已经创建&&app向AMS注册了Binder代理
if (app != null && app.thread != null) {
...
//如果上面条件满足就去启动Activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}
//如果不满足,也就是说app所在的进程还没创建,那就先去创建进程,等进程创建好了再去启动Activity。
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
如果我们app所在进程已经创建,一般是应用内跳转到某个Activity,就会执行realStartActivityLocked。如果应用进程还没创建,就会先去创建应用进程,比如我们从手机的主屏幕点击图标跳转到应用的根Activity时。关于realStartActivityLocked的逻辑等会再看,先看看 mService.startProcessLocked方法,该方法最终会调到AMS的startProcessLocked方法:
ActivityManagerService#startProcessLocked
private final void startProcessLocked(...) {
...
//Process.start从方法名称来看就是启动进程的
startResult = Process.start(...);
//应用进程启动后指定超时时间内必须向AMS报告,不然就会被销毁
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
Process的start方法执行流程如下:
最终会调用到zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote)这行代码,这行代码主要用来打开Socket和Zygote进程通信,然后向Zygote进程发送参数,获取结果。这样Zygote进程就会fork出一个应用进程,然后执行应用进程的入口函数也就是我们熟悉的ActivityThread.main()函数。
补充:
a:Android是基于Linux系统的,Linux启动后用户空间创建的第一个进程是init进程,而Zygote进程是init进程创建的,Zygote进程主要干两件事。1、孵化应用进程,我们app所在进程都是他fork出来的。2、创建SystemServer进程,我们常见的AMS、PMS、WMS等都是SystemServer进程中的服务。
b:app和AMS跨进程通信是通过Binder实现的,而AMS和Zygote的IPC过程是通过Socket实现的。
应用进程创建好后,就会执行它的入口函数,ActivityThread.main,现在我们又回到app端了,瞅瞅ActivityThread.main做了啥。
ActivityThread#main
public static void main(String[] args) {
//创建主线程的Looper和消息队列
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
// thread.attach用于向AMS报告
thread.attach(false);
//开启消息循环
Looper.loop();
}
可以看到在main函数中主要开启的消息循环,并调用了thread.attach(false)方法,刚刚说过AMS要求应用进程创建好后在指定超时时间内需要向其报告,这里的thread.attach(false);方法就是用来向AMS打报告的。
ActivityThread#attach
private void attach(boolean system) {
....
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
attach方法中先获取AMS的Binder代理,然后通过这个代理对象跨进程调用到AMS的attachApplication方法。通过异常的捕获也可以看出这是一个跨进程调用。这样程序就执行到AMS的attachApplication方法了,进去瞅瞅。
ActivityManagerService#attachApplication
@Override
public final void attachApplication(IApplicationThread thread) {
....
attachApplicationLocked(thread, callingPid);
}
attachApplication方法紧接着又调用了attachApplicationLocked方法:
ActivityManagerService#attachApplicationLocked
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
.....
//1
thread.bindApplication(...);
...
//2
mStackSupervisor.attachApplicationLocked(app)
......
}
ActivityManagerService的attachApplicationLocked方法做了很多事,因为这里主要是分析Activity的启动流程,所以只看这两行代码。在注释1会调用到应用进程的bindApplication,最终导致Appliction的创建,以及为Appliction赋予上下文。注释2才是和启动Activity相关的。
ActivityStackSupervisor#attachApplicationLocked
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
...
//首先拿到要启动的Activity记录。
ActivityRecord hr = stack.topRunningActivityLocked();
....
//
realStartActivityLocked(hr, app, true, true)
}
首先会拿到要启动的Activity记录,虽然一开始启动Activity的时候,由于应用进程没创建,先去创建进程了,但是要启动的Activity数据结构早就准备好了,然后就可以调用realStartActivityLocked去真正启动Activity了,终于又看到这个方法了。
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
app.thread.scheduleLaunchActivity(...);
}
app.thread中的thread其实就是应用进程注册到AMS的Binder代理,AMS可以通过这个Binder代理跨进程和app进程通信,这个一开始就说过了。然后会跨进程调用到应用进程中ActivityThread内部类ApplicationThread的scheduleLaunchActivity方法,继续跟进。
ActivityThread.ApplicationThread.scheduleLaunchActivity
由于scheduleLaunchActivity方法是AMS跨进程调用过来的,因此它是运行在Binder线程池中的,需要将启动Activity的工作转到主线程做,可以看到scheduleLaunchActivity方法会给H发送一条LAUNCH_ACTIVITY的信息,H也是ActivityThread的内部类,就是一个Handler,专门用来在主线程处理一些消息。这样启动Activity的任务就转到主线程了,然后调用getPackageInfoNoCheck方法,该方法获取一个LoadedApk对象,该对象封装了APK的一些信息,等会创建Activity会用到它,然后执行handleLaunchActivity方法。
ActivityThread#handleLaunchActivity
注释1的performLaunchActivity会导致Activity的创建,注释2的handleResumeActivity方法最终会调用到Activity的onResume回调。继续跟进performLaunchActivity方法:
ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//给Activity创建上下文
ContextImpl appContext = createBaseContextForActivity(r);
//通过反射创建activity对象
Activity activity = null;
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//尝试创建Application(事实上Application一开始就创建好了,所以直接返回了)
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//给activity赋予上下文,以及执行一些必要的初始化比如我们熟悉的PhoneWindow
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
//调用activity的生命周期方法OnCreate
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
r.activity = activity;
//调用activity的生命周期方法OnStart
activity.performStart();
}
可以看到performLaunchActivity还是做了不少事情的,创建activity上下文、通过反射创建activity、尝试创建Application、给activity赋予上下文、调用activity的部分生命周期(OnCreate和OnStart)。通过反射创建activity如下:
Instrumentation#newActivity
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
enmmm,这样activity的启动流程就分析完毕了。
参考:
包建强的无线技术空间
刘望舒的博客