Luncher Activity启动
App安装时,PMS会解析AndroidManifest.xml,拿到组件信息。Launcher从PMS中拿到action为android.intent.action.MAIN
并且category为android.intent.category.LAUNCHER
的Activity信息并为他们创建桌面图标。
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
点击桌面图标后,Launcher通过AMS启动MainActivity,Launcher、AMS、MainActivity三者在不同进程,通过Binder通信。
一切从Launcher开始
1、点击桌面图标时,Launcher调用startActivitySafely,在startActivitySafely
方法里面,给intent添加Intent.FLAG_ACTIVITY_NEW_INTENT
,来设置根Activity在新的任务栈中,然后调用Launcher的startActivity(intent);
startActivity最终会调用startActivityForResult(intent , -1);
其中-1表示Launcher不需要知道Activity的返回结果。
2、startActivityForResult里通过Instrumentation的execStartActivity
来启动Activity。Instrumentation
用于监控应用和系统的交互。
3、跨进程通信,从Launcher到AMS
execStartActivity会调用ActivityManagerNative.getDefault().startActivity()
来拿到AMS的代理对象ActivityManagerProxy
,实际上就是Binder接口的客户端实现类,通过transact来调用服务端Binder,也就是ActivityManagerService
(AMS)的startActivity。
AMS所在进程
4、获取目标Activity信息
AMS的startActivity调用ActivityStack
的startActivityMayWait
,在这个方法里,PMS解析Intent里面的 目标Activity信息 并保存在ActivityInfo
里,然后通过同步方法执行startActivityLocked
5、一个Activity对应一个ActivityRecord,保存旧的,创建新的
startActivityLocked目的是拿到源Activity的进程信息,在AMS找到源Activity(也就是Launcher)的ActivityRecord,用sourceRecord保存,并且新建ActivityRecord保存目标Activity(MainActivity)的各种信息。然后调用startActivityUnCheckedLocked
6、需要新建任务栈 ?
startActivityUnCheckedLocked主要是判断是否需要新建任务栈,如果设置android:taskAffinity
属性,则AMS会新建TaskRecord,将目标Activity放到新的任务栈去执行,否则直接放入当前任务栈执行。
7、通知Resume状态的Launcher进入Pause状态,为MainActivity的启动做准备
新放入栈的MainActivity在栈顶,调用resumeTopActivityLocked
来判断栈顶的这个Activity是否已经启动,若已启动,则直接返回;否则看当前是否有Resume状态的Activity。
显然Launcher就是Resumed状态,然后ActivityStack使用startPausingLocked
通知Resume状态的Launcher进入Pause状态,以便把焦点让给即将启动的MainActivity
8、通知Launcher的进程中止Launcer,终止后进程向AMS再发送启动MainActivity组件的通知
startPausingLocked
通知Launcher的进程中止Launcher,并更新ActivityRecord和ActivityStack里面保存的Resume状态和Pause状态的Activity信息(当前没有resume状态的,而Pause状态的就是Launcher了)
9、AMS -> Launcher,进程间再次通信
AMS进程中,ApplicationThreadProxy类的schedulePauseActivity
,作为客户端Binder,向服务端Launcher进程发送通信请求。Launcher进程的ActivityThread收到客户端Binder传来的Message对象,给Launcher主线程发送PAUSE_ACTIVITY
的信息,让Launcher在主线程执行中止操作。
如果直接在服务端收到msg的线程中止Launcher,可能会耗时。而且可能会有涉及UI的操作,所以特意到Launcher主线程
10、Launcher执行onPause,以及执行前后的数据和状态保存
就像AMS里面一个Activity对应一个ActivityRecord一样,Launcher进程中,每个Activity也对应一个ActivityClientRecord
对象用于保存相关信息,然后调用onPause,然后做一些数据和状态的写入操作,做完后,再次拿到ActivityManagerProxy
的代理客户端,向服务端AMS发送通信请求,表示Launcher已经onPause完毕。
11、AMS收到Launcher的消息后,会再次调用resumeTopActivityLocked
,就是第7步,此时没有Resumed状态的Activity了,于是开始调用startSpecificActivityLocked
启动MainActivity。这个方法会根据进程名和用户ID,判断对应的进程是否存在了,如果存在则交给进程去启动,没有则调用startProcessLocked
来创建新的进程。
12、startProcessLocked创建ProcessRecord
,看名字就知道是保存进程信息的,然后添加到AMS里保存进程信息的ArrayMap里。创建新进程时,指定了进程入口是ActivityThread
里面的main方法:
public static void main(String[] args) {
//......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
在main方法里,通过prepareMainLooper
创建并启动消息循环。创建ActivityThread并且通过attach向AMS发送启动完成通知。
13、ActivityThread也就是MainActivity所在进程,创建完成后,又得需要跨进程通信去通知AMS创建成功,并把ApplicationThread保存到AMS里,ApplicationThread是Binder客户端,携带新创建的进程信息。
14、ActivityThread的attach
方法里,再次通过ActivityManagerNative.getDefault()
拿到AMS的代理ActivityManagerProxy,写入Parcel数据并调用服务端AMS的attachApplication
来保存信息到AMS。
15、进程成功创建,然后AMS通过ActivityStack的realStartActivityLocked
来请求进程启动第一个Activity,realStartActivityLocked里面实际调用的是ApplicationThreadProxy的scheduleLaunchActivity
,一看又是进程间通信了,ApplicationThreadProxy作为客户端Binder,而服务端肯定就是新建进程里的ActivityThread了。
16、ActivityThread调用queueOrSendMessage
来向当前进程的主线程的消息队列发送LAUNCH_ACTIVITY
消息,受到消息后调用handleLaunchActivity
来启动MainActivity :
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
}
break;
//......
}
}
17、handleLaunchActivity首先通过performLaunchActivity
启动MainActivity,然后调用handleResumeActivity
把MainActivity的状态设置为Resumed。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {//... }
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
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);
mInstrumentation.callActivityOnCreate(activity, r.state);
}
mActivities.put(r.token, r);
} catch { //...... }
return activity;
}
18、performLaunchActivity拿到ComponentName,比如"com.test.MainActivity",然后新建ClassLoader,在mInstrumentation的newActivity
方法里,通过ClassLoader来实例化Activity类。接着创建了Application Context。然后再用mInstrumentation的callActivityOnCreate
方法,来调用MainActivity的onCreate
方法。这就是我们所熟知的Activity启动流程了。
最后整理了一张汇总的图: