Android的Activity启动流程

         一个Android系统的手机,面对桌面一大堆的应用图标,我们随便点击一个应用图标,打开该应用,然后就进行了该系统的业务流程,登录注册等等之类。那我们开发者在最初写项目的时候,都知道要有一个入口Activity,并且需要在AndroidManifest.xml配置action和category,这样我们点击应用图标就会首先进入这个Activity里面,这样的Activity被称作主Activity,至于都已经到了主Activity里面去了,那么如果想要跳转到其它的页面,也很简单,使用startActivity方法就可以。

        那我们有没有想过,点击桌面的应用图标,为什么就可以打开这个应用了呢?Android这个系统在后面都有哪些操作呢?

        Android系统是基于Linux系统的,init进程是Linux操作系统里面由内核启动的用户级线程,是系统必不可少的程序之一。Zygote进程是整个系统创建新进程的核心进程,是由init进程fork出来的。那么除了Zygote整个整个系统的根进程,还有个SystemService进程,这个进程主要作用是启动各种系统服务。比如ActivityManagerService、PackageManagerService、WindowManagerService等等。

        那么我们平时Android手机看到的桌面其实也是一个应用程序,将它称作Launcher,Launcher是由系统服务LauncherAppService进行启动的,LauncherAppService则是由SystemService来启动的。


ActivityManagerService里面的systemReady方法

        首先,在ActivityManagerService里面可以找到systemReady方法,这个方法什么时候调用呢?又是由谁调用呢?在SystemService进程启动过程中,在其中通过内部方法分别调用了boot service,core service和other service,在调用startOtherService的时候就会调用ActivityManagerService的systemReady方法。

ActivityManagerService的systemReady方法很长,我们着重看一个


systemReady方法里面的调用startHomeActivityLocked
startHomeActivityLocked的实现

这个顾名思义,就是启动一个home的Activity,那么针对Android操作系统来说,桌面看作一个Activity的话, 那么毋庸置疑这个home的Activity指的就是桌面。

看看getHomeIntent方法


getHomeIntent方法

        有没有发现这段代码我们很熟悉,就是我们经常写的要启动一个Activity,创建出一个intent,并给intent设置Component、flag和Category,注意这里的Category是android.intent.category.HOME

        那么这种启动Activity的方式很明显是属于隐士启动,查看Launcher源码得知,在AndroidManifest里面配置Category为android.intent.category.HOME的是LauncherActivity。

        LauncherActivity是继承ListActivity的,看看它的布局


LauncherActivity的布局文件

       是不是很简单?就是一个ListView再加上个TextView,那么LauncherActivity的onCreate方法是什么样的呢?


LauncherActivity的onCreate方法


        我们可以发现,getPackageManager这个方法一开始就初始化了PackageManager,这个用于查询手机里面所有的应用程序包名、应用名、图标等,将这些作为数据源,放入到Adapter中,这样我们在桌面上所看到的应用程序名字和图标信息皆是来源于此。

ListView的item点击监听


ListView的onListItemClick方法

很简单,就是创建一个intent,然后startActivity方式启动这个Activity。

看看intentForPosition方法


intentForPosition方法

        到现在为止的分析来看,Launcher程序本身就是一个安卓应用程序,只不过是系统默认启动的第一个应用程序。那我们在Launcher程序LauncherActivity提供了一个应用程序视图,可以供用户点击隐士打开一个应用程序。

那么,接下去看看startActivity这个过程


Activity的startActivityForResult

       不管我们是调用startActivity(Intent intent)还是startActivity(Intent intent, Bundle options)最终都会执行到startActivityForResult方法

看看这个方法里面的关键代码


Activity里面的startActivityForResult

发现了一个新的类Instrumentation,是这个Instrumentation的实例调用了execStartActivity方法。Instrumentation类是Android操作系统中程序端操作Activity的具体操作类,当系统需要具体执行Activity的某个操作时,都需要借助于Instrumentation来进行具体实现。


Instrumentation的execStartActivity方法


再来看关键的代码

public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options, UserHandle user) {

...

 int result = ActivityManagerNative.getDefault() .startActivityAsUser(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options, user.getIdentifier()); checkStartActivityResult(result, intent); 

...

}

首先来看看ActivityManagerNative.getDefault是什么


ActivityManagerNative的getDefault方法


ActivityManagerNative的gDefault

        那么看到IBinder对象,看到asInterface方法,对aidl很熟悉的知道这个IActivityManager很像我们创建的aidl文件,然后ServiceManager.getService("activity")方法返回一个IBinder对象则很像我们连接一个服务,连接成功后返回一个操作服务方法的句柄IBinder,使用asInterface方法可以转换成我们定义的接口对象。

        在这里,ActivityManagerNative.getDefault() .startActivityAsUser这个方法实际上就是通过Binder机制进行了跨进程间的通信。为什么在这里需要采用进程间的通信方式呢?因为Android系统里面的应用进程和SystemServer进程不是同一个进程,所以需要采用自身设计的Binder机制。

        我们可以回过头来看看ActivityManagerService,发现它是继承ActivityManagerNative的,而ActivityManagerNative是实现IActivityManager接口的,那么最终ActivityManagerNative.getDefault()执行startActivityAsUser这个方法实际上就是执行ActivityManagerService里面的startActivityAsUser方法。


ActivityManagerService里面的startActivityAsUser方法

再看看ActivityStarter里面的startActivityMayWait方法,方法很长,节选关键部分


ActivityStarter里面的startActivityLocked方法

继续看看startActivityLocked方法,方法同样很长,节选关键部分


ActivityStarter里面的startActivityLocked最终的调用方法

        注意,调用startActivityUnChecked里面的第一个参数是r,r是ActivityRecord实例,在这个方法里面new了一个ActivityRecord对象,并将这个对象作为参数传入startActivityUnchecked方法里面

调用了方法startActivityUnchecked方法,节选部分


ActivityStarter里面的startActivityUnchecked方法

注意,在这里,boolean类型的变量mDoResume为true,这个是之前传入的参数。

继续看ActivityStackSupervisor类里面的resumeFocusedStackTopActivity方法


ActivityStarter里面的resumeFocusedStackTopActivityLocked方法


最终调用了targetStack.resumeTopActivityUncheckedLocked方法,看看这个方法


ActivityStack里面的resumeTopActivityUncheckedLocked方法

注意,这里是到了ActivityStack里面执行resumeTopActivityUncheckedLocked方法,然后紧接着调用同类里面的resumeTopActivityInnerLocked方法,看看这个方法,方法很长,节选关键部分来看


ActivityStack里面的resumeTopActivityInnerLocked方法

        我们都知道,在一个活动的Activity里面打开另外一个Activity,那么这个正在活动的Activity必然先经历onPause的生命周期方法。那么在这个地方,不妨可以将startPausingLocked视作要去pause当前的活动Activity。究竟我们的这个猜想是不是正确的,继续跟踪下去。


ActivityStack里面的startPausingLocked方法

        那么我们在startPausingLocked方法里面找到了一个很重要的调用语句,prev.app.thread.schedulePauseActivity方法,那么这几个prev.app.thread是什么呢?prev是ActivityRecord类型,prev.app是什么呢?从ActivityRecord类结构可以看到,是有个ProcessRecord类,这个类是什么?可以看下它的大致结构


ProcessThread类结构

        那么很显然,prev.app.thread就是IApplicationThread类型的实例。这个情形有点像IActivityManager的情况。Android系统中,ApplicationThread是IApplicationThread.Stub的子类,那么拥有IApplicationThread对象去执行schedulePauseActivity自然就是执行ApplicationThread里面的schedulePauseActivity方法,是典型的binder通信机制。

继续看下ApplicationThread里面的schedulePauseActivity方法


ActivityThread里面的内部类ApplicationThread

那么是调用setMessage方法


ActivityThread里面的sendMessage方法

注意,这里的mH是Handler实例。那么再查看消息是怎么被处理的。


handleMessage方法


继续看里面调用的handlePauseActivity方法


ActivityThread里面的handlePauseActivity方法

继续跟踪下去,performPauseActivity->performPauseActivityIfNeed找到调用的方法


ActivityThread里面的performPauseActivityIfNeed

好吧,看到mInstrumentation.callActivityOnPause方法,明白需要借助Instrumentation来调用Activity的方法


Instrumentation里面的callActivityOnPause方法

最终回到了Activity里面,看看Activity方法里面的performPause方法


Activity里面的performPause方法

其中的onPause就是我们经常写的Activity生命周期方法onPause的调用。

        那么到现在为止,我们将Activity栈顶的Activity置为pause状态,那么接下去一步,应该是新的Activity的创建和显示,那么这一步的步骤在哪呢?我们得回到ActivityThread的handlePauseActivity方法里面再看看


还是ActivityThread里面的handlePauseActivity方法

        上面的红色框是刚才走的流程,将栈顶上面的Activity状态置为pause状态,那么下面的红色框,大家应该很熟悉,binder机制进行进程中的通信,ActivityManager.getService调用activityPaused方法实际上在ActivityManagerService里面具体实现,我们看看这个方法


ActivityManagerService里面实现的activityPaused方法

好,接着调用了ActivityStack里面的activityPausedLocked方法


ActivityStack类里面的activityPausedLocked

调用了completePauseLocked方法


ActivityStack里面的completePauseLocked方法


紧接着,又调用了ActivityStackSupervisor类里面的resumFocusedStackTopActivityLocked方法,看到这个方法名,是不是觉得很熟悉,没错,上面的部分流程和这里是完全一样的。

最终到了ActivityStack里面的resumeTopActivityInnerLocked方法,注意,在此时不会执行startPausingActivityLocked方法,原因是mResumedActivity为null


ActivityStack里面的resumeTopActivityInnerLocked方法

不会执行,接着往下走,最终会调用


ActivityStack里面的resumeTopActivityInnerLocked方法

继续查看startSpecificActivityLocked方法


ActivityStackSupervisor里面的startSpecificActivityLocked方法


注意,这里会有个判断,即判断如果要新建一个进程,则会使用binder方式,调用下面红色框里面的ActivityManagerService里面的startProcessLocked方法;如果不需要新建进程,那么就会执行上面红色框里面的realStartActivityLocked方法。

假设现在的情景是需要新建一个进程,那我们看看ActivityManagerService里面的startProcessLocked方法


ActivityManagerService里面的startProcessLocked方法

那么会调用Process.start方法


Process里面的start方法

调用方法zygoteProcess.start->startViaZygote->zygoteSendArgsAndGetResult


ZygoteProcess的zygoteSendArgsAndGetResult方法

        使用Socket方式与Zygote进程进行通信,申请fork了一个新的进程,并根据我们刚刚传递的字段"android.app.ActivityThread",反射出该对象并执行ActivityThread的main方法。所以这个时候新的进程就已经创建好了。我们经常称之ActivityThread为ui线程或者主线程,是因为进程一创建就会首先执行ActivityThread的main方法。


ActivityThread的main方法

那么,看到很熟悉的两句代码,Looper.prepareMainLooper和Looper.loop,初始化Looper对象,MessageQueue对象等等,所以我们可以随意在主线程里面new Handler不会报错。

这里,关键句代码thread.attach(false)


ActivityThread里面的attach方法

同样,使用binder机制调用了ActivityManagerService的attachApplication方法,attachApplication调用了attachApplicationLocked方法


ActivityManagerService里面的attachApplicationLocked方法

调用了ActivityStackSupervisor里面的attachApplicationLocked方法


ActivityStackSupervisor里面的attachApplicationLocked方法

到了这里,就是执行realStartActivityLocked方法


ActivityStackSupervisor里面的realStartActivityLocked方法

又是通过IApplicationThread的binder机制,调用ActivityThread里面的scheduleLauncherAcitivty方法


ActivityThread里面的scheduleLauncherActivity方法

同ActivityThread里面的sendMessage,交由handle来处理消息,最终调用handleLaunchActivity


ActoivityThread里面的handleLaunchActivity方法

看到了performLauncherActivity方法,看看是什么


ActivityThread里面的performLaunchActivity的上半部分

那么这里的activity是用反射创建出来的,创建好activity之后,看看这个方法的下半部分


ActivityThread里面的performLaunchActivity的下半部分

看到第一个红色框,activity.attach方法,在上一篇分析view加载流程的时候说到Window实例mWindow变量就是在attach方法里面初始化的,那么什么时候会调用activity的attach方法呢?答案就在这。


Activity里面的Attach方法

第二个红色框,是用mInstrumentation调用callActivityOnCreate方法


Instrumentation里面的callActivityOnCreatef方法


Activity里面的performCreate方法


第三个红色框,则是调用了Activity里面的performStart方法


Activity里面的performStart

那么onCreate和onStart方法都执行过了,onResume方法什么时候执行呢?这个得回头看看ActivityThread里面的handleLaunchActivity


ActivityThread里面的handleLaunchActivity方法

执行了handleResmeActivity


ActivityThread里面的handleResumeActivity

        在这个方法上半部分,执行了performResumeActivity继而执行activity的performResume方法,到目前为止,新的activity的onResume方法也执行了。那么还有个疑问,已经暂停的activity怎么继续执行它的onStop方法呢?继续在handleResumeActivity的下班部分寻找,有一句关键的代码,上图红色框里面的。


ActivityThread里面的Idler

好吧,看到这个,依旧是我们很熟悉的binder对象,调用了ActivityManagerService里面的activityIdle方法


ActivityManagerService里面的activityIdle方法

调用了ActivityStackSupervisor里面的activityIdleInternalLocked方法


ActivityStackSupervisor里面的activityIdleInternalLocked方法

调用了ActivityStack里面的stopActivityLocked方法


ActivityStack里面的stopActivityLocked方法

又是通过binder机制调用了scheduleStopActivity方法


ActivityThread里面的scheduleStopActivity方法


最终经过消息的分发,交给handleStopActivity方法处理


ActivityThread里面的handleStopActivity方法

调用了performStopActivityInner方法


ActivityThread里面的performStopActivityInner方法

回到了Activity里面的peformStop方法


Activity里面的performStop方法

借助于mInstrumentation调用callActivityOnStop方法


Instrumentation的callActivityOnStop方法

好了,最后一步,调用activity的onStop方法。

总结:

一个Activity的启动都是从startActivity方法开始的,最终都会执行到Activity里面的startActivityForResult,只不过普通的startActivity方法传递的requestCode为-1。

Activity的启动过程是需要SystemServer进程主要是ActivityManagerService代表类和应用进程主要是ActivityThread代表类的共同协助调用的过程。

ActivityThread与ActivityManagerService的沟通需要ActivityManagerNative这个Binder对象,表现为可以在ActvitityThread中调用ActivityManagerService里面的方法。

反过来,ActivityManagerService和ActivityThread的沟通需要ApplicationThread这个Binder对象,表现为可以在ActivityManagerService中调用ActivityThread方法。当然一般而言,不会在ActivityManagerService里面直接调用ActivityThread方法,更多的会在ActivityStarter、ActivityStackSupervisor里面。

当Activity执行到startActivityForResult方法之后,会执行到Instrumentaion里面的execStartActivity方法,这个时候通过Binder机制,会到ActivityManagerService里面去执行。

ActivityManagerService经过一系列的判断,历经ActivityStarter、ActivityStackSupervisor会执行startPausingLocked方法

经过ApplicationThread这个Binder对象,会到ActivityThread里面去执行startPausingActivity方法。

将栈顶的Activity执行onPause方法之后,ActivityThread里面会通过ActivityManagerNative的Binder机制告诉ActivityManagerService继续后续的操作。

ActivityManagerService经过一系列的流转,最终会在ActivityStackSupervisor里面判断,新建的Activity是否需要一个新进程,如果不需要,则执行启动Activity的操作,如果需要,那么还是通过Binder机制通知ActivityManagerService去新建进程。

ActivityManagerService收到了新建进程的消息,通知Process执行start方法,在Process的流程中,通过Socket方式和跟进程Zygote进程沟通,新建一个进程,并且根据传入的进程名字,一般为“android.app.ActivityThread”反射出该对象执行它的main方法。

ActivityThread的main方法里面进行了一些变量的初始化,其中就包括了Looper对象的初始化,然后同样通过Binder机制告诉ActivityManagerService继续接下去的操作。

ActivityManagerService收到之后经过一系列的流转,也是在ActivityStackSupervisor通过Binder机制告诉ActivityThread可以启动新的Activity了。

ActivityThread通过反射机制创建了一个Activity,并借助于Instrumetation完成对新建的Activity的attach、onCreate、onStart和onResume方法,最终执行第一个Activity的onStop方法。

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

推荐阅读更多精彩内容