根Activity的启动过程简述

参照《Android系统源代码情景分析》中的例子。

有三个Activity:

1. MainActivity 根Activity

2.SubActivityInProcess  与根Activity运行在同一个进程的Activity

3.SubActivityInNewProcess 运行在新进程中的Activity

两个重要的结构体:

1.ActivityRecord 每个启动的Activity在ActivityManagerService中都有唯一一个对应的ActivityRecord对象。该对象是Binder本地对象。同时Activity所在的ActivityThread会持有该ActivityRecord的binder代理对象。在Activity和ActivityManagerService进行远程通信的时候,该binder代理对象会被传输以被ActivityManagerService用来识别当前与自己通信的Activity的具体信息。

2.ApplicationThread 每个app都含有这样一个Binder本地对象。每个运行的app进程在ActivityManagerService中都有一个唯一的ProcessRecord对象。该对象保存了ApplicationThread的Binder代理对象。从而ActivityManagerService可以主动与Activity所在的进程进行通信。

3.ActivityClientRecord 每个启动的Activity在自身进程中都有唯一一个对应的ActivityClientRecord对象。它和Activity进程所持有的ActivityManagerService中的ActivityRecord的代理对象是一一对应的。

重要变量:

ActivityStack类有三个成员变量mResumedActivity, mLastPausedActivity和mPausingActivity,它们的类型均为ActivityRecord,分别用来描述系统当前激活的Activity组件、上一次被中止的Activity组件,以及正在被中止的Activity组件。

从Launcher启动MainActivity

1.Launcher-->startActivitySafely

2.Activity-->startActivity

3.Activity-->startActivityForResult

Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(

    this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode

);

mMainThread.getApplicationThread()就是Launcher Activity所属进程的ApplicationThread本地对象。

mToken是Launcher Activity在ActivityManagerService中的ActivityRecord对应的代理对象。

4.Instrumentation-->execStartActivity

5.ActivityManagerProxy-->startActivity

将需要启动的intent信息以及自身的一些信息写入Parcel中进行远程通信

...

//caller是IApplicationThread

data.writeStrongBinder(caller != null ? caller.asBinder() : null);

//intent是需要启动的MainActivity的相关信息

intent.writeToParcel(data, 0);

//resultTo是Launcher Activity对应的ActivityRecord代理对象

data.writeStrongBinder(resultTo);

mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

...

接下来在ActivityManagerService进程中执行

6.ActivityManagerService-->startActivity

7.ActivityStack-->startActivityMayWait

通过PackageManager解析需要启动的intent信息,获取对应的ActivityInfo

ActivityInfo aInfo;

ResolveInfo rInfo = AppGlobals.getPackageManager().resolveIntent(intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS);

aInfo = rInfo != null ? rInfo.activityInfo : null;

8.ActivityStack-->startActivityLocked

通过Launcher传过来的ActivityRecord代理对象获取其在ActivityManagerService中对应的ActivityRecord  sourceRecord

通过Launcher传过来的IApplicationThread对象获取Launcher进程在ActivityManagerService中对应的ProcessRecord对象 callerApp,以及进程id callingPid和用户id  callingUid。

用callerApp callingUid以及第7步得到的aInfo构造需要启动的MainActivity对应的ActivityRecord r。

9. ActivityStack-->startActivityUncheckedLocked

检测到MainActivity所在的Task不存在,新建一个TaskRecord。将该TaskRecord赋给MainActivity对应的ActivityRecord的task变量中。并将该TaskRecord加入到ActivityManagerService的recentTask中。

   ActivityStack-->startActivityLocked

将MainActivity对应的ActivityRecord加入到ActivityStack的mHistory中。

10.ActivityStack.resumeTopActivityLocked

获取当前运行的top Activity的ActivityRecord(就是MainActivity)。和mResumedActivity(即Launcher Activity)相比较。发现不一致。于是需要告诉mResumedActivity需要执行pause操作。

11.ActivityStack-->startPausingLocked

通过Launcher Activity对应的ActivityRecord所保存的ProcessRecord的thread对象获取Launcher Activity所在进程的IApplicationThread代理对象。从而进行远程通信。

//prev是Launcher Activity对应的ActivityRecord。 app是ProcessRecord类型。thread是IApplicationThread类型。

prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, prev.configChangFlags);

同时发送一个PAUSE_TIMEOUT_MSG延迟消息。如果PAUSE_TIMEOUT时间之后这个消息没有被取消掉,说明Launcher Activity的pause操作无响应了。

12.ApplicationThreadProxy.schedultePauseActivity

...

//token是Launcher Activity对应的ActivityRecord

data.writeStrongBinder(token)

mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);

...

接下来在Launcher Activity的进程中执行

13.ApplicationThread-->schedulePauseActivity

14.ActivityThread-->queueOrSendMessage

15.H-->handleMessage

16.ActivityThread-->handlePauseActivity

//token是Launcher Activity的ActivityRecord代理对象。

Bundle state = performPauseActivity(token, finished, true);

17. ActivityManagerProxy-->activityPaused

...

//token是Launcher Activity的ActivityRecord代理对象

data.writeStrongBinder(token);

data.writeBundle(state);

mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);

...

接下来在ActivityManagerService进程中执行

18.ActivityManagerService-->activityPaused

19.ActivityStack-->activityPaused

移除之前发送的PAUSE_TIMEOUT_MSG延时信息

修改Launcher Activity的ActivityRecord的状态。

int index = indexOfTokenLocked(token);

ActivityRecord r = mHistory.get(index);

20. ActivityStack-->completePauseLocked

将mPausingActivity置为null

21.ActivityStack-->resumeTopActivityLocked

上一次进入这个函数的时候由于resumedActivity不等于top running Activity.所以进入了pause流程。

这次由于已经pause过了。所以直接进入start流程。

22.ActivityStack-->startSpecificActivityLocked

检测到MainActivity对应的进程并没有起来。也即MainActivity对应的ActivityRecord的app (ProcessRecord类型)以及app.thread(IApplicationThread类型)为null。启动进程。

23.ActivityManagerService.startProcessLocked

为MainActivity所在进程创建ProcessRecordLocked对象。启动进程

int[] gids = mContext.getPackageManager().getPackageGids(app.info.packageName);

int pid = Process.start("android.app.ActivityThread", mSimpleProcessManageMent ? app.processName : null, uid, uid, gids, debugFlags, null);

发送一个延时消息PROC_START_TIMEOUT_MSG,如果PROC_START_TIMEOUT之后,该消息没有被取消。则判断为启动进程无响应。

接下来在MainActivity的进程中运行

24.ActivityThread-->main

创建ActivityThread。创建ApplicationThread。

25.ActivityManagerProxy-->attachApplication

//app是IApplicationThread类型

data.writeStrongBinder(app.asBinder());

mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);

接下来在ActivityManagerService的进程中运行

26.ActivityManagerService.attachApplication

27.ActivityManagerService.attachApplicationLocked

通过Binder驱动告知的pid获取当前attach的进程在ActivityManagerService中对应的ProcessRecord。第23步创建的。

将ApplicationThread代理对象保存在ProcessRecord中。供之后ActivityManagerService与Activity进程通信用。

移除之前发送的延迟消息PROC_START_TIMEOUT_MSG

检测到top running Activity需要运行,且其ActivityRecord的app为null,且进程名等于当前attach的进程名。于是启动MainActivity.

28.ActivityStack.realStartActivityLocked

ProcessRecord有activities变量保存有所有在该进程中运行的Activity

29.ApplicationThreadProxy-->scheduleLaunchActivity

...

//intent是MainActivity的intent

intent.writeToParcel(data, 0);

//token是MainActivity对应的ActivityRecord本地对象

data.writeStrongBinder(token);

//info是MainActivity对应的ActivityInfo

info.writeToParcel(data, 0);

mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);

...

接下来是在MainActivity的进程中运行的

30.ApplicationThread-->scheduleLaunchActivity

为MainActivity创建ActivityClientRecord。将其和ActivityRecord关联起来。

31.ActivityThread-->queueOrSendMessage

32.H-->handleMessage

调用ActivityThread类的getPackageInfoNoCheck获取LoadedApk对象。赋给ActivityClientRecord的packageInfo成员变量中。

33.ActivityThread-->handleLaunchActivity

34.ActivityThread.performLaunchActivity

调用Instrumentation.newActivity创建MainActivity的实例。

创建MainActivity的Application。

为MainActivity的实例赋予需要用到的变量。

35.MainActivity.onCreate

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

推荐阅读更多精彩内容