Activity启动流程分析

代码:Android4.4

Activity启动类型与方式
Activitiy启动类型:
  • 根Activity:点击Launcher图标启动
  • 子Activity: 根Activity启动后,内部调用startActivity启动子Activity。
启动方式:
  • 显示启动 通过类名启动
  • 隐式启动 通过组件名启动
点击Launcher图标触发的应用冷启动流程。

总流程图:

一、startActivity

1.1类介绍:

  • Instrumentaion:Activity类的成员变量,用来监控应用程序和系统之间的交互操作。
  • ActivityManagerProxy:与AMS进行binder call的client端。
  • ActivityManagerService:由SystemServer启动的,管理四大组件和进程的系统服务。

1.2流程介绍:
应用程序安装过程中,主要做了两件事:复制apk到指定目录 和 AndroidManifest.xml解析。
Launcher会向PMS查询:<action android:name="android.intent.action.MAIN" />和
<category android:name="android.intent.category.LAUNCHER" />的Activity,并绑定一个应用图标,点击Launcher对应的应用图标,实际上就是做了一次Activity的隐式启动。而启动信息是保存在Intent中的。

1)点击应用图标onClick触发startActivitySafely

4)Activity的启动任务交由Instrumentaion通过exeStartActivity来代为执行,以便监控交互的整个过程。

5)应用层执行ActivityManagerNative.getDefault ,通过ServiceManager.getService("activity”) 向kernel binder驱动查询到AMS的binder引用,同时通过asInterface创建ActivityManagerProxy即binder call的client端,proxy通过AMS binder引用与AMS通信。

6)binder call到AMS。

@Override
public final int startActivity(
     IApplicationThread caller, //发起端的ApplicationThread , AMS通过IApplicationThread与ActivityThread进行binder call
     String callingPackage,//发起端包名
     Intent intent, //传入的intent信息
     String resolvedType, 
     IBinder resultTo, //token 保证Activity与Window一致性。token与ActivityRecord一一对应,Activity attach时传入,setWindowManager传入,最终由Window的AppToken接收。
     String resultWho, //target 目标activity
     int requestCode,  //startActivityForResult(Intent intent, int requestCode, Bundle options) ,requestCode If >= 0, 会被onActivityResult接收,这里是-1
     int startFlags,  //0
     String profileFile, 
     ParcelFileDescriptor profileFd, 
     Bundle options //startActivityForResult(Intent intent, int requestCode, Bundle options) 
) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
           resultWho, requestCode,
           startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
}
二、Activity信息封装以及堆栈任务调整

2.1类介绍:

  • ActivityStackSupervisor:ActivityStack的管理类,同时与AMS、WMS等相关系统服务及时同步信息。
  • ActivityStack:TaskRecord管理类,不是真正的Activity栈。
  • TaskRecord:Activity任务栈,四种启动模式。
  • ActivityRecord:Activity对应的实体对象。

启动模式:

  • standard(默认):启动一个新Activity就加入栈顶,不考虑重复。
  • singleTop :栈顶复用。
  • singleTask :栈内复用,且之上的所有Activity统统出栈。
  • singleInstance :独享栈,没有当前activity就创建一个新task来让该activity独享,否则复用。

与Task相关属性:

  • Intent.FLAG_ACTIVITY_NEW_TASK 创建新的task
  • android:taskAffinity = “ packageName “ 亲和性(物以类聚),同一程序Activity亲和性相同。
  • android:allowTaskReparenting=“true” Activity 可以移动到与其具有关联的Task中。
  • android:process = “packageName”设置是否运行在同一程序中。

taskAffinity约束力比较弱,需要Intent.FLAG_ACTIVITY_NEW_TASK 和 android:allowTaskReparenting=“true”作为前置条件。

比如:

  • 同一程序的不同activity放入不同的栈中:taskAffinity 不同 + Intent.FLAG_ACTIVITY_NEW_TASK
  • 不同程序的activity放入同一栈中:taskAffinity相同 + android:allowTaskReparenting=“true”

2.2流程介绍:

2)AMS.startActivityAsUser 加入UserId信息

3)ActivityStackSupervisor.startActivityMayWait 选择一个匹配Intent的最合适的目标Activity,并获取对应ActivityInfo。

  • PMS.resolveIntent: 通过PMS得到被启动Activity的ResolveInfo, queryIntentActivities 通过Component去匹配要被启动的Activity,chooseBestActivity 对多个activity,android:priority(默认是0 , 范围是[-1000, 1000])不同,选优先级高的,android:priority相同弹窗让用户选择。

  • resolveActivity 由ResolveInfo获取被启动Activity的ActivityInfo。

4)ActivityStackSupervisor.startActivityLocked 将收集到的关于目标启动Activity的信息初始化为ActivityRecord对象

ActivityRecord r = new ActivityRecord(
        mService, // AMS
        callerApp, //发起端对应的ProcessRecord
        callingUid, //发起端的Uid
        callingPackage, //发起端的包名
        intent,
        resolvedType,
        aInfo, //ActivityInfo 当前activity信息
        mService.mConfiguration,
        resultRecord, 
        resultWho,
        requestCode, componentSpecified, this);

5)ActivityStackSupervisor.startActivityUnCheckedLocked

startActivityUncheckedLocked(
r, //目标Activity
sourceRecord, //源Activity
startFlags,
true,  //doResume = true
options
);

由launchMode和 intent.getFlags 和 taskAffinity 等共同决定目标Activity应该在那个task,以什么形式存在。

6)ActivityStack.resumeTopActivityLocked

判断:

  • 当前有存在的resumed activity,且就是要启动的目标activity,那什么都不用做。
  • 当前没有存在的resumed activity, 直接启动目标activity。
  • 当前有存在的resumed activity,不是要启动的目标activity,那么先让之前的activity走pause流程。

7)ActivityStack.startPausingLocked
这里如果mPausingActivity != null,会有一个500ms的超时消息。

8)ApplicationThreadProxy.schedulePauseActivity
system_server进程通过IApplicationThread与Launcher进程进行binder call通信,执行对当前非目标的其他resumeActivity 执行pause操作。

三、pauseActivity

流程介绍:

2 - 3)ActivityThread 是一个消息驱动的大looper,

4)handlePauseActivity做两件事:一是通过Instrumentation让目前resume的activity走onPause,二是向AMS 发送binder call通知activityPaused。

四、重回目标Activity resume流程

流程介绍:

2)ActivityStack.activityPaused : remove PAUSE_TIMEOUT_MSG

3 - 5)继续之前resumeTopActivity工作

6)如果启动的Activity对应的进程为空,则走创建进程流程,否则直接走Activity启动流程。

五、进程创建流程

5.1类介绍:

  • Process: Framework Java层进程相关操作类,比如杀进程、创建进程、设置进程优先级、设置进程组等。

5.2流程介绍:

1)AMS通过 Process.start来创建目标Activity对应的进程

2 - 5)Process.start过程主要是收集创建进程所需参数,包括进程名、pid、uid等信息,打包好通过socket发送给Zygote。

Zygote启动流程:

Zygote通过init进程启动,启动过程主要干了这么几件事:

3)创建虚拟机。

4)注册JNI。

5)registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求。

6)preload()预加载系统通用类、资源、openGL以及共享库以及WebView,用于提高app启动效率。

8)fork SystemServer 上层framework系统服务的运行载体。

10)调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

这里process.start最终通过socket向zygote发起创建进进程的请求,同时把相关参数传递过来。

再简单描述下Zygote fork进程的过程:
1)copy-on-write fork
zygote 采用copy-on-write的方式fork进程,从父进程fork一个子进程,刚fork之后,这两个虚拟地址实际上指向的是相同的物理地址(内存页),且把父子共享的页面标记为“只读”,但如果其中任何一个进程要对共享的页面“写操作”,这时内核会复制一个物理页面给这个进程使用,同时修改页表,把原来的只读页面标记为“可写”,留给另外一个进程使用。此时两个虚拟地址指向不同的物理地址(新的物理地址的内容从原物理地址中复制得到)。

2)zygote 复制自己的一份内存拷贝给对应进程,内部包括系统预加载的资源和类也包括虚拟机环境。同时为创建的新进程设置pid,启动进程对应的Binder线程池(16个线程),最后通过反射执行ActivityThread的main方法。

六、ActivityThread初始化以及attach Application

6.1类介绍:

  • LoadedApk: APK文件信息封装对象。
  • PathClassLoader: 加载已被安装的应用路径中.dex 文件。另外要提的是DexClassLoader :加载指定路径中的.dex 文件。他俩的父类都是BaseDexClassLoader。

6.2 流程介绍:

1 -7)反射执行ActivityThread的main方法, looper消息池转起来,同时binder call到AMS 执行attachApplication,然后AMS binder call回ApplicationThread执行bindApplication。

10 - 18)handleBindApplication : 通过getPackageInfo初始化LoadApk,初始化Instrumentation,通过makeApplication加载主apk, 同时初始化Application类,最后通过Instrumentation执行Application的onCreate回调。

注:时序图默认生成的数字有问题,图中顺序调整下,以上面描述的顺序为准。

七、realStartActivityLocked

AMS执行attachApplicationLocked方法时,其实干了两件事情,一件是binder call回ApplicationThread执行bindApplication。
另一件是走ActivityStackSupervisor.attachApplicationLocked最终执行realStartActivityLocked走Activity在App层的启动流程。

realStartActivityLocked过程非常简单,在ActivityThread中通过消息通信最终执行handleLaunchActivity,通过Instrumentation初始化Activity并走对应的生命周期。

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

推荐阅读更多精彩内容