Activity启动流程源码分析

申明:源码基于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的启动流程就分析完毕了。

参考:
包建强的无线技术空间
刘望舒的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值