源码分析->Activity启动流程

https://www.jianshu.com/p/0b12937581b0文章分析了从fork应用进程到Application onCreate执行的过程,有兴趣的同学可以看下。

下面主要想分析Activity的启动流程
源码分析基于Android-23

startActivity(new Intent(this,MainActivity.class))这个启动Activity的代码相信大家应该都很熟悉,它最终会调到

1.Activity.startActivityForResult

主要工作:
判断options是否为空,调用相应的方法,其实两个方法都差不多;这里注意到requestCode为-1,有别于我们平时写的requestCode>=0,-1表示不需要回调到onActivityResult方法;

   @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }
上述startActivityForResult会调到下述重载的startActivityForResult;
2.Activity.startActivityForResult

主要工作:
通过Instrumentation来启动Activity;

Tips:Instrumentation是一个很有意思类,查看源码可以发现,Activity和Application生命周期的调用都会通过它,它最后会调到AMS当中,设想可以通过反射或者在AndroidManifest配置,利用它来对Activity生命周期进行监控;
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
            ......
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ......
}
3.Instrumentation.execStartActivity

主要工作:
(1)ActivityManagerNative.getDefault,从ServiceManager中获取AMS,然后通过asInterface构建AMS代理对象ActivityManagerProxy并返回;
(2)通过代理来启动Activity,这里面涉及到单例模式Singleton,到此就会转到AMS中;

Tips:SystemServer启动AMS以后,调用AMS.setSystemProcess方法,将AMS注册到ServiceManager中。
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
            ......
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            ......
    }
AMS.startActivity最终会调到4.ActivityStackSupervisor.realStartActivityLocked

主要工作:
scheduleLaunchActivity,通过app.thread跨进程调用Activity所属的ApplicationThread,

Tips:app.thread是ProcessRecord的ApplicationThread属性,负责进程间通讯;
   final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
           ......
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
                 ......
    }
5.ApplictionThread.scheduleLaunchActivity

主要工作:
创建ActivityClientRecord ,最后sendMessage往主线程发送启动Activity的消息(我猜测这里应该是在binder线程,要不然为什么需要转到主线程);

Tips:ApplictionThread是ActivityThread的内部类;
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
            ......
            ActivityClientRecord r = new ActivityClientRecord();
            ......
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
ActivityThread.H.handleMessage会调用到6.ActivityThread.handleLaunchActivity

主要工作:
(1)WindowManagerGlobal.initialize,初始化WMS客户端代理,为后续添加窗口做准备;
(2)performLaunchActivity,主要是创建Activity、调用onCreate以及onStart方法;
(3)handleResumeActivity,调用onResume,还包括一个很关键的,通知绘制界面,它涉及点比较多,这里就不展开了。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        WindowManagerGlobal.initialize();
        Activity a = performLaunchActivity(r, customIntent);
            ......
        handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
         ......
    }
7.ActivityThread.performLaunchActivity

主要工作:
(1)getPackageInfo,获取包信息,返回类型是LoadedApk,它封装了Application信息、资源路径、lib路径;
(2)mInstrumentation.newActivity,根据类型反射实例化Activity对象;

Tips:反射调用的是无参的构造函数,如果给Activity定义了一个有参的构造函数,一定要再定义的一个无参的构造函数,要不然这里会报错;

(3)r.packageInfo.makeApplication,会调到LoadedApk.makeApplication,如果当前Activity的Application为空,则反射构建Application对象并调用其onCreate方法,否则直接返回;
(4)activity.attach,这方法很重要,给Activity mBase属性赋值以及创建PhoneWindow;
(5)mInstrumentation.callActivityOnCreate,调用Activity onCreate方法;
(6)activity.performStart,最终也是通过Instrumentation来调用onStart方法;
(7)当r.state不为空,则调用mInstrumentation.callActivityOnRestoreInstanceState;
(8)mActivities.put(r.token, r),将ActivityClientRecord放入集合;

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);
        }
       ......
        Activity activity = null;
       ......
        activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
           ......
            if (activity != null) {
                ......
                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);
                ......
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                 ......
                 activity.performStart();
                  ......                                                 
                  mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
                  ...... 
            }
                  ...... 
        } 
          ...... 
        mActivities.put(r.token, r);
        return activity;
    }

至此Activity的onCreate、onStart方法就被调用,也就是启动起来了。

补充看下Activity.attach方法
Activity.attach

主要工作:
(1)attachBaseContext,给Activity mBase变量赋值,我们获取Resource对象其实通过它;
(2)new PhoneWindow(this),这个大家都很熟悉了,就是PhoneWindow;
(3)mWindow.setCallback(this),Activity作为mWindow的监听器,当有事件分发到Window,Activity也就能接受事件;

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);
        .....
        mWindow = new PhoneWindow(this);
        .....
        mWindow.setCallback(this);
        .....
    }
Activity启动流程.png
总结:

(1)启动Activity最终会调用startActivityForResult,接着调到Instrumention,通过ActivityManagerNative获取AMS的客户端代理ActivityManagerProxy,通过代理跨进程通讯到AMS,AMS对LaunchMode 、intent等进行处理后,通过ApplicationThreadProxy跨进程通讯到该Activity所属的ApplicationThread,通过sendMessage转到主线程,调到handleLaunchActivity,内部执行performLaunchActivity创建Activity以及给mBase赋值,最终通过Instrumention调用Activity的声明周期方法;
(2)ActivityManagerServices、ApplicationThread、ActivityThread、Instrumention四者之间的关系,AMS负责管理Activity生命周期,需要对生命周期进行调度时通知到进程的ActivityThread,而真正的调用者是Instrumention,它是进程单例的,ApplicationThread是负责AMS跨进程通讯到ActivityThread的。
(3)Activity的引用链关系,ActivityThead的mActivities属性保存没有被销毁的ActivityClientRecord,ActivityClientRecord持有Activity的引用,ActivityThead-> ActivityClientRecord->Activity;

Tips:ActivityClientRecord与ActivityRecord,都是描述Activity,只不过前者是在app端使用,后者是在AMS端使用。

(4)无论是App跨进程通讯到AMS,还是AMS跨进程通讯到App,都是采用binder通讯,当App跨进程通讯到AMS,App端就是Client端,而AMS就是Server端,两者都对共同的接口IActivityManager,只不过Client端是代理,真正的实现是在Server,所以这里采用了代理模式。
(5)遇到问Activity启动流程的面试题,建议重点讲下fork进程、创建Application以及Activity、调用他们的生命周期。

以上分析有不对的地方,请指出,互相学习,谢谢哦!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354