Activity启动

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调用ActivityStackstartActivityMayWait,在这个方法里,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启动流程了。

最后整理了一张汇总的图:


根Activity启动.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容