Android Activity启动过程-从桌面点击图标到调用Activity的OnCreate

1、概述

当用户从桌面点击一个应用图标时,该应用就会启动并显示主Activity,即在AndroidManifest中标注如下过滤器的Activity:

主Activity过滤器

里面的category中涉及到LAUNCHER。这个其实和Laucher进程有关,这是一个桌面进程。所以从桌面点击图标到应用启动显示的页面的过程,其实就是从一个应用启动到另一个应用的过程。

总体流程大致如下图所示:

启动流程

① 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求。

② system_server进程接收到请求后,向zygote进程发送创建进程的请求。

③ Zygote进程fork出新的子进程,即App进程。

④ App进程,通过Binder IPC向sytem_server进程发起attachApplication请求。

⑤ system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求。

⑥ App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息。

⑦ 主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。

⑧ 到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。

2、概念介绍

2.1 Launcher

如开头所说Launcher本质上也是一个应用程序,和我们的App一样,同时桌面显示的页面也是一个Activity:


//packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

public final class Launcher extends Activity

        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,

                  View.OnTouchListener {

                  }

Launcher这个Activity实现了点击、长按等回调接口,来接收用户的输入。既然是Activity,那么从Launcher的Activity跳转到我们应用的主Activity,和我们平时从一个Activity跳转到另一个Activity的其实从代码角度一样。即捕捉图标点击事件,然后startActivity()发送对应的Intent请求。

2.2 system_server

startActivity()发送过来的请求其实是发送给system_server。而SystemServer也是一个进程。所以这一过程其实涉及到了进程间的通信,这边的这一过程是采用Binder的方式来进行的。system_server这个进程是Android Framework层里面非常重要的一个进程。系统里面重要的服务都是在这个进程里面开启的,比如 ActivityManagerService、PackageManagerService、WindowManagerService等等。

而今天重点要涉及到ActivityManagerService这个服务,其简称AMS。ActivityManagerService进行初始化的时机很明确,就是在SystemServer进程开启的时候,就会初始化ActivityManagerService。

我们的App通过调用startActivity()并不能直接打开另外一个App,这个方法会通过一系列的调用,最后告诉AMS说:“我要打开这个App,我知道他的住址和名字,你帮我打开吧!”所以是AMS来通知zygote进程来fork一个新进程,来开启我们的目标App。

除此之外,其实所有的Activity的开启、暂停、关闭都需要AMS来控制,所以我们说,AMS负责系统中所有Activity的生命周期。

在Android系统中,任何一个Activity的启动都是由AMS和应用程序进程相互配合来完成的。AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属的进程具体来完成。

2.3 zygote

如上所说,ActivityManagerService收到一个打开一个应用程序的通知后会发送创建进程的请求给到zygote来创建一个app进程。

在Android系统里面,zygote是一个进程的名字。Android是基于Linux System的,当你的手机开机的时候,Linux的内核加载完成之后就会启动一个叫“init“的进程。在Linux System里面,所有的进程都是由init进程fork出来的,我们的zygote进程也不例外。

我们都知道,每一个App其实都是一个单独的dalvik虚拟机并对应一个单独的进程。所以当系统里面的第一个zygote进程运行之后,在这之后再开启App,就相当于开启一个新的进程。而为了实现资源共用和更快的启动速度,Android系统开启新进程的方式,是通过fork第一个zygote进程实现的。所以说,除了第一个zygote进程,其他应用所在的进程都是zygote的子进程。而zygote的直白翻译为“受精卵”,也是很形象生动了。

而创建的新进程的入口就是ActivityThread.main()方法,之后的部分将着重介绍。

3、应用创建到显示

3.1 启动应用程序

Android中,一个应用程序的开始可以说就是从ActivityThread.java中的main()方法开始的。下面是main()比较关键的代码:


public static void main(String[] args){

    ...

    Looper.prepareMainLooper();

    //初始化Looper

    ...

    ActivityThread thread = new ActivityThread();

    //实例化一个ActivityThread

    thread.attach(false);

    //这个方法最后就是为了发送出创建Application的消息

    ...

    Looper.loop();

    //主线程进入无限循环状态,等待接收消息

}

从源码中可以看到,main()方法中主要做的事情是,初始化主线程的Looper、主Handler。并使主线程进入等待接收Message消息的无限循环状态。并在进入等待接收消息前实例化一个实例化一个ActivityThread,并调用其attach()方法。从这也可以想象到为什么说Android的设计是一个事件驱动的模型了。

3.2 应用程序和AMS关联

我们在看一下thread.attach(false)中的关键代码:


public void attach(boolean system){

    ...

    final IActivityManager mgr = ActivityManagerNative.getDefault(); 

    //获得IActivityManager实例

    try {

        mgr.attachApplication(mAppThread);

    } catch (RemoteException ex) {

        throw ex.rethrowFromSystemServer();

    }

    ...

}

里面的IActivityManager 是一个接口,当我们调用ActivityManagerNative.getDefault()获得的实际是一个代理类的实例——ActivityManagerProxy,这个东西实现了IActivityManager接口。打开源码你会发现,ActivityManagerProxy是ActivityManagerNative的一个内部类。既然是一个代理类它必定有代理的对象。查看一下ActivityManagerProxy的构造函数:


public ActivityManagerProxy(IBinder remote) {

        mRemote = remote;

}

这个构造函数非常的简单。首先它需要一个IBinder参数,然后赋值给mRemote变量。这个mRemote显然是ActivityManagerNative的成员变量。但对它的操作是由ActivityManagerProxy来代理间接进行的。这样设计的好处是保护了mRemote,并且能够在操作mRemote前执行一些别的事务,并且我们是以IActivityManager的身份来进行这些操作。

该构造函数的调用地点:


static public IActivityManager asInterface(IBinder obj) {

    if (obj == null) {

        return null;

    }

    IActivityManager in =

        (IActivityManager)obj.queryLocalInterface(descriptor);

    //先检查一下有没有

    if (in != null) {

        return in;

    }

    ...

    return new ActivityManagerProxy(obj);

    //这个地方调用了构造函数

}

上面这个方法是ActivityManagerNative中的一个静态方法,它会调用到ActivityManagerProxy的构造方法。这个静态方法也需要一个IBinder作为参数。

查找这个函数的调用地点以及传入的参数到底是什么:


private static final SingletongDefault = new Singleton() {

    protected IActivityManager create() {

      IBinder b = ServiceManager.getService("activity");

      //重点啊!IBinder实例就是在这里获得的。

        ...

        IActivityManager am = asInterface(b);

        //调用了上面的方法。

        ...

        return am;

    }

};

这是ActivityManagerNative的静态常量,它是一个单例。在其中终于获得了前面一直在用的IBinder实例。


IBinder b = ServiceManager.getService("activity");

到这里应该已经非常清晰了,IActivityManager 获取到的就是一个ActivityManagerService的代理。有了这个代理之后就可以作为客户端通过Binder机制将app作为客户端,ActivityManagerService作为服务端来进行通信了。具体Binder进程间通信机制请看我之前一篇文章:Binder进程间通信机制

我们回到前面的thread.attach(false)方法中,接着往下看在获得IActivityManager实例之后,将会执行它的attachApplication(mAppThread)方法。该方法会传入一个mAppThread参数。在ActivityThread这个类的成员变量中,有这么一行代码:


final ApplicationThread mAppThread = new ApplicationThread();

ApplicationThread是作为ActivityThread中的一个常量出现的。这表明系统不希望这个变量中途被修改,也说明其的重要性。ApplicationThread类继承自ApplicationThreadNative。并且ApplicationThread是ActivityThread的一个内部类。从设计角度可以看出,该类是专门让ActivityThread来使用的一个类。

看一下ApplicationThread的父类ApplicationThreadNative:


public abstract class ApplicationThreadNative extends Binder

    implements IApplicationThread{

...

}

我们从ApplicationThreadNative看到它也是一个Binder,同时实现了IApplicationThread接口。这个Binder并不是Binder代理,这个Binder说明了应用程序在作为客户端的同时,也作为了服务端。而作为服务端的Binder就是ApplicationThread。而 mgr.attachApplication(mAppThread) 这行代码就是通过mgr将ApplicationThread的信息作为数据发送给AMS,方便日后AMS通过ApplicationThread的代理发送数据给ApplicationThread来达到控制app的Activity生命周期等一系列操作。

几经辗转,ApplicationThread的信息终于传递到了AMS中,我们可以从AMS的源码中找到这个函数:


private final boolean attachApplicationLocked(IApplicationThread thread

, int pid) {

    ...

    thread.bindApplication();

    ...

}

3.3 创建Application

ApplicationThread以IApplicationThread的身份到了ActivityManagerService中(其实在ActivityManagerService中的是ApplicationThread的代理),经过一系列的操作,最终被调用了自己的bindApplication()方法,发出初始化Applicationd的消息:


public final void bindApplication(String processName, ApplicationInfo appInfo, Listproviders, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services,

    Bundle coreSettings){

    ...

    sendMessage(H.BIND_APPLICATION, data);

}

bindApplication()函数就是AMS的ApplicationThread的代理,通过Binder进程间通信调用app进程的ApplicationThread的bindApplication()方法。该方法里面有一句关键代码


sendMessage(H.BIND_APPLICATION, data);

还记不记得最开始main函数创建的Looper。而ActivityThread中还存在一个该Looper的处理对象Hander H。从传送的参数H.BIND_APPLICATION可以看到,这个消息就是发送给这个H来处理的。

一旦H接收到这个消息就开始创建Application了。这个过程是在handleBindApplication()中完成的:


private void handleBindApplication(AppBindData data) {

    ...

    mInstrumentation = (Instrumentation)

        cl.loadClass(data.instrumentationName.getClassName())

        .newInstance();

    //通过反射初始化一个Instrumentation仪表。后面会介绍。

    ...

    Application app = data.info.makeApplication(data.restrictedBackupMode, null);

    //通过LoadedApp命令创建Application实例

    mInitialApplication = app;

    ...

    mInstrumentation.callApplicationOnCreate(app);

    //让仪器调用Application的onCreate()方法

    ...

}

handleBindApplication()中比较关键的是上面几句代码。其中有个类Instrumentation,它在创建Application类之前进行实例化。它能够允许你监视应用程序和系统的所有交互。打开这个类你可以发现,最终Apllication的创建,Activity的创建,以及生命周期都会经过这个对象去执行。简单点说,就是把这些操作包装了一层。通过操作Instrumentation进而实现上述的功能。这里实例化Instrumentation的方法是反射!而反射的ClassName是来自于从ActivityManagerService中通过ApplicationThread的代理传过来的。

接我们着看mInstrumentation调用的方法callApplicationOnCreate(app):


public void callApplicationOnCreate(Application app) {

    app.onCreate();

}

该方法只是回调了一下Application 的onCreate()。这就是为什么它能够起到监控的作用。我们最熟悉的Activity的一些声明周期的方法onCreate(),onStart()等等也是通过这样来进行回调的。

再回到


Application app = data.info.makeApplication(data.restrictedBackupMode, null);

看下调用的方法makeApplication(data.restrictedBackupMode, null):


public Application makeApplication(boolean forceDefaultAppClass,

    Instrumentation instrumentation) {

    ...

    String appClass = mApplicationInfo.className;

    //Application的类名。明显是要用反射了。

    ...

    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread

        , this);

    //留意下Context

    app = mActivityThread.mInstrumentation

        .newApplication( cl, appClass, appContext);

    //通过仪表创建Application

    ...

}

这里首先通过反射找到了Application的类名。其次创建了Application的ContextImpl ,ContextImpl 其实Application的Context具体执行的类,我们平时调用的Context有关的方法最后其实都是调用了ContextImpl 的对应方法,这里不展开讲了。之后就是通过刚才说的mInstrumentation来调用newApplication( cl, appClass, appContext)创建Application。具体该方法如下:


static public Application newApplication(Class clazz

    , Context context) throws InstantiationException

    , IllegalAccessException

    , ClassNotFoundException {

        Application app = (Application)clazz.newInstance();

        //反射创建,简单粗暴

        app.attach(context);

        //关注下这里,Application被创建后第一个调用的方法。

        //目的是为了绑定ContextImpl 。

        return app;

    }

至此终于将Application创建出来了。

3.4 创建及启动Activity

还记得之前的Application启动信号其实是AMS通过ApplicationThread的代理调用bindApplication()发送过来的吗?了解Binder通信机制可以知道,一旦客户端调用远程服务(此时AMS是客户端,app是服务端),调用服务的线程调用服务后是会挂起直到服务调用完毕返回结果的。这边创建完Application相当于服务调用完毕了。此时AMS的对应线程会接着往下执行代码以同样的方法通过ApplicationThread的代理向ApplicationThread发起启动主Activity的请求,并且在ApplicationThread中向H发送一条LAUNCH_ACTIVITY的消息。然后H就开始了初始化Activity。

收到LAUNCH_ACTIVITY后H会调用handleLaunchActivity():


private void handleLaunchActivity(ActivityClientRecord r

    , Intent customIntent

    , String reason) {

    ...

    Activity a = performLaunchActivity(r, customIntent);

    //妈蛋!又封装到另一个方法中创建了。

    ...

    if (a != null) {

        ...

        handleResumeActivity(r.token

        , false

        , r.isForward

        ,!r.activity.mFinished && !r.startsNotResumed

        , r.lastProcessedSeq, reason);

        //Activity创建成功就往onResume()走了!

        ...

    }

}

继续往下看performLaunchActivity(r, customIntent):


private Activity performLaunchActivity(ActivityClientRecord r

    , Intent customIntent) {

    ...

    activity = mInstrumentation.newActivity(

        cl, component.getClassName(), r.intent);

    //通过mInstrumentation来创建Activity

    ...

    Application app = r.packageInfo.makeApplication(false

    , mInstrumentation);

    //获取Application

    ...

    activity.attach(appContext

        , this

        , getInstrumentation()

        , r.token

        ,.ident

        , app

        , r.intent

        , r.activityInfo

        , title

        , r.parent

        , r.embeddedID

        , r.lastNonConfigurationInstances

        , config

        ,r.referrer

        , r.voiceInteractor

        , window);

    ...

    if (r.isPersistable()) {

        mInstrumentation.callActivityOnCreate(

          activity, r.state, r.persistentState);

    } else {

        mInstrumentation.callActivityOnCreate(activity, r.state);

    }

    //根据是否可持久化选择onCreate()方法。

    ...

}

注意这句代码:


activity = mInstrumentation.newActivity(

        cl, component.getClassName(), r.intent);

正如前面所说,Activity、Application的创建及生命周期都被承包给Instrumentation。所以由它来负责。看看newActivity():


public Activity newActivity(ClassLoader cl, String className,

            Intent intent)

            throws InstantiationException

            , IllegalAccessException,

            ClassNotFoundException {

        return (Activity)cl.loadClass(className).newInstance();

        //反射实例化Activity而已

    }

其实就是通过反射实例化了Activity。

回到performLaunchActivity() 创建了Activity后 将之前创建出来的Application和Activity关联。

接着我们看performLaunchActivity() 中的这段代码:


if (r.isPersistable()) {

        mInstrumentation.callActivityOnCreate(

          activity, r.state, r.persistentState);

    } else {

        mInstrumentation.callActivityOnCreate(activity, r.state);

    }

根据是否可持久化选择Activity的onCreate()方法。同样是通过Instrumentation仪表来执行onCreate()的。它两分别对应的onCreate()方法为:


onCreate(icicle, persistentState);

//可获得持久化数据

onCreate(icicle);

//平时重写的最多的。

至此,成功调用了Activity的onCreate()方法。其实之后的onStart(),onResume()等生命周期的方法也时类似这样调用的。

4、总结

从桌面点击图标到创建应用进程,再到创建Application,在到创建主Activity到最后调用onCreate()的流程大致如上文所述。

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

推荐阅读更多精彩内容