《转》深入理解Activity启动流程(三)–Activity启动的详细流程1
本文原创作者:Cloud Chou. 出处:本文链接
本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究。
- 深入理解Activity启动流程(一)--Activity启动的概要流程
- 深入理解Activity启动流程(二)--Activity启动相关类的类图
- 深入理解Activity启动流程(三)--Activity启动的详细流程2
- 深入理解Activity启动流程(四)--Activity Task的调度算法
本篇博客将开始介绍Activity启动的详细流程,由于详细启动流程非常复杂,故此分成两篇来介绍。
本篇主要介绍前半部分的启动流程:
- 1. Activity调用ActivityManagerService启动应用
- 2. ActivityManagerService调用Zygote孵化应用进程
- 3. Zygote孵化应用进程
下篇介绍后半部分的启动流程:
- 4. 新进程启动ActivityThread
- 5. 应用进程绑定到ActivityManagerService
- 6. ActivityThread的Handler处理启动Activity的消息
1. Activity调用ActivityManagerService启动应用
点击图片可看大图

在launcher应用程序里启动应用时,点击应用图标后,launcher程序会调用startActivity启动应用,传递的intent参数:
intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(className);
activity最终调用Instrumentation的execStartActivity来启动应用:
//Activity类
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
//...
}else{
//...
}
Instrumentation调用ActivityManagerProxy对象的startActivity方法启动Activity,而ActivityManagerProxy只是ActivityManagerService对象在应用进程的一个代理对象,ActivityManagerProxy最终调用ActivityManagerService的startActvity方法启动Activity。
//Instrumentation类
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//...
try{
//...
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, null, options);
} catch (RemoteException e) {
}
//...
}
2. ActivityManagerService调用Zygote孵化应用进程
点击图片可看大图

ActivityManagerProxy对象调用ActivityManagerService对象(运行在system_server进程)的startActivity方法以启动应用,startActivity方法接下来调用startActivityAsUser方法以启动应用。在startActivityAsUser方法里会调用ActivityStack的startActivityMayWait方法以启动应用,startActivityMayWait方法里启动应用时,需先根据intent在系统中找到合适的应用的activity,如果有多个activity可选择,则会弹出ResolverActivity让用户选择合适的应用。
//ActivityStack类
final int startActivityMayWait(IApplicationThread caller, int callingUid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, String profileFile,
ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
Bundle options, int userId) {
//…
//根据intent在系统中找到合适的应用的activity,如果有多个activity可选择,
//则会弹出ResolverActivity让用户选择合适的应用。
ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
profileFile, profileFd, userId);
//…
int res = startActivityLocked(caller, intent, resolvedType,
aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
startFlags, options, componentSpecified, null);
//…
}
在startActivityLocked方法里,对传过来的参数做一些校验,然后创建ActivityRecord对象,再调用startActivityUncheckedLocked方法启动Activity。
startActivityUncheckedLocked方法负责调度ActivityRecord和Task,理解该方法是理解Actvity启动模式的关键。
startActivityUncheckedLocked方法调度task的算法非常复杂,和当前回退栈,要启动的acitivity的启动模式以及taskAffinity属性,启动activity时设置的intent的flag等诸多要素相关,intent的flag就有很多种情况,故此算法非常复杂,需要阅读源码并结合特定启动情况才能理解。
后续会介绍startActivityUncheckedLocked方法的实现,并结合特定场景分析调度算法。
接下来调用startActivityLocked将ActivityRecord加入到回退栈里:
//ActivityStack类
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
//...
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
//...
}
在startActivityLocked里调用resumeTopActivityLocked显示栈顶Activity:
//ActivityStack类
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
//...
if (doResume) {
resumeTopActivityLocked(null);
}
}
resumeTopActivityLocked(null)会调用另一个resumeTopActivityLocked方法显示栈顶的acitivity:
//ActivityStack类
final boolean resumeTopActivityLocked(ActivityRecord prev) {
return resumeTopActivityLocked(prev, null);
}
因为应用还未启动过,所以调用startSpecificActivityLocked启动应用,执行逻辑如下:
//ActivityStack类
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
//...
if (next.app != null && next.app.thread != null) {
//…
}else{
//…
startSpecificActivityLocked(next, true, true);
}
//...
}
在startSpecificActivityLocked里调用mService.startProcessLocked启动应用:
//ActivityStack类
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
//...
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false);
}
在ActivityManagerService的startProcessLocked方法里:
//ActivityManagerService类
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid);
} else {
//...
}
//...
if (app == null) {
app = newProcessRecordLocked(null, info, processName, isolated);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
mProcessNames.put(processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
} else {
//..
}
//...
startProcessLocked(app, hostingType, hostingNameStr);
//...
}
在startProcessLocked方法里:
//ActivityManagerService类
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
//...
try {
//...
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
//Zygote孵化dalvik应用进程后,会执行android.app.ActivityThread类的main方法
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
//...
} catch (RuntimeException e) {
//...
}
}
在Process类的start方法里:
//Process类
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try{
startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
}catch (ZygoteStartFailedEx ex) {
//...
}
}
在Process类的startViaZygote方法里,会计算启动应用进程用的各个参数,然后再调用zygoteSendArgsAndGetResult方法将这些参数通过socket发送给zygote进程,zygote进程会孵化出新的dalvik应用进程,然后告诉ActivityManagerService新启动的进程的pid。
3. Zygote孵化应用进程
点击图片可看大图

zygote进程将ZygoteInit作为启动类,会执行它的main方法,先注册ZygoteSocket,然后调用runSelectLoop方法,runSelectLoop方法会调用方法在ZygoteSocket上监听请求,如果别的进程通过ZygoteSocket请求孵化进程,则孵化进程。
runSelectLoop方法的主要代码:
//ZygoteInit类
private static void runSelectLoopMode() throws MethodAndArgsCaller {
//...
while (true) {
//...
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//监听客户连接请求
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//若客户发送孵化进程的请求过来,
//此时便需要调用ZygoteConnection的runOnce方法孵化进程
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
在runOnce方法里调用Zygote.forkAndSpecialize方法孵化进程,如果返回值为0表示是在孵化出来的应用进程里,此时会调用handleChildProc进行一些处理,并使用异常机制进行逃逸,会直接逃逸至ZygoteInit的main方法。
//ZygoteConnection类
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
//...
try {
//...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
}
//...
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//handleChildProc是一个很重要的函数,在该函数里使用了异常进行逃逸
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
//...
} else {
//...
}
} finally {
//...
}
}
3.1 Zygote.forkAndSpecialize
Zygote的forkAndSpecialize方法会调用nativeForkAndSpecialize方法孵化进程,nativeForkAndSpecialize是一个本地方法,它的实现在dalvik/vm/native/dalvik_system_Zygote.cpp里,在该cpp文件里与nativeForkAndSpecialize对应的C++方法是Dalvik_dalvik_system_Zygote_forkAndSpecialize,在该方法里会调用forkAndSpecializeCommon孵化进程,在forkAndSpecializeCommon方法里会调用fork系统调用创建进程,因为使用的是fork机制所以创建进程的效率比较高。
3.2 handleChildProc
handleChildProc方法主要代码:
//ZygoteConnection类
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//...
if (parsedArgs.runtimeInit) {
//...
} else {
String className;
try {
//这里得到的classname实际是android.app.ActivityThread
className = parsedArgs.remainingArgs[0];
} catch (ArrayIndexOutOfBoundsException ex) {
logAndPrintError(newStderr,
"Missing required class name argument", null);
return;
}
//...
if (parsedArgs.invokeWith != null) {
//...
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
//调用ZygoteInit.invokeStaticMain执行android.app.ActivityThread的main方法
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}
}
ZygoteInit的invokeStaticMain方法并不会直接执行className的main方法,而是会构造一个 ZygoteInit.MethodAndArgsCaller异常,然后抛出来,通过异常机制会直接跳转到ZygoteInit的main方法, ZygoteInit.MethodAndArgsCaller类实现了Runnable方法,在run方法里会执行要求执行的main方法,故此跳转到ZygoteInit的main方法后,异常会被捕获,然后执行方法caller.run(),这样便会执行android.app.ActivityThread的main方法。
ZygoteInit的invokeStaticMain方法主要代码:
//ZygoteInit类
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
//...
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch(//...){
}
//...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
ZygoteInit.MethodAndArgsCaller主要代码:
public static class MethodAndArgsCaller extends Exception
implements Runnable {
//...
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
}//...
}
}
ZygoteInit的main方法相关代码:
//ZygoteInit类
public static void main(String argv[]) {
try {
//...
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
//...
}
}
下面博客将介绍Activity详细启动流程的后半部分。
《转》深入理解Activity启动流程(三)–Activity启动的详细流程1的更多相关文章
- 《转》深入理解Activity启动流程(三)–Activity启动的详细流程2
本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启 ...
- 深入理解Activity启动流程(三)–Activity启动的详细流程2
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--A ...
- Android之Activity系列总结(三)--Activity的四种启动模式
一.返回栈简介 任务是指在执行特定作业时与用户交互的一系列 Activity. 这些 Activity 按照各自的打开顺序排列在堆栈(即返回栈,也叫任务栈)中. 首先介绍一下任务栈: (1)程序打开时 ...
- 《转》深入理解Activity启动流程(四)–Activity Task的调度算法
本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启 ...
- 《转》深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先为大家介绍Act ...
- 《转》深入理解Activity启动流程(一)–Activity启动的概要流程
本文原创作者:Cloud Chou. 原文地址:http://www.cloudchou.com/android/post-788.html Android中启动某个Activity,将先启动Acti ...
- 深入理解Activity启动流程(四)–Activity Task的调度算法
本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启动的概要流程 深入理解Activity启动流程(二)- ...
- 深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 欢迎转载,请注明出处和本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先 ...
- 深入理解Activity启动流程(一)–Activity启动的概要流程
概述 Android中启动某个Activity,将先启动Activity所在的应用.应用启动时会启动一个以应用包名为进程名的进程,该进程有一个主线程,叫ActivityThread,也叫做UI线程. ...
随机推荐
- 【调研与分析】标杆学习、知识管理和竞争情报的关系——From Team
注: 1)红色实线箭头表示可以直接使用:例如竞争情报业务输出产品之一的标杆文档可以直接作为公司标杆学习中外部标杆的资料: 2)蓝色虚线箭头表示转化后使用或者间接利用的关系:例如专题调研可以帮助建立内部 ...
- Mirror--镜像使用的工作线程数
/*在SQL SERVER 2005 及以后版本中, 使用'MAXworker thread' 来配置可用的线程数,默认设置为0 ,即自动控制线程数 计算最大工作线程数: 对于32 位系统:逻辑CPU ...
- Flask系列(五)Flask实现分页
一.flask分页组件 from urllib.parse import urlencode,quote,unquote class Pagination(object): ""& ...
- Hadoop mapreduce自定义分组RawComparator
本文发表于本人博客. 今天接着上次[Hadoop mapreduce自定义排序WritableComparable]文章写,按照顺序那么这次应该是讲解自定义分组如何实现,关于操作顺序在这里不多说了,需 ...
- Learning to Rank之Ranking SVM 简介
排序一直是信息检索的核心问题之一,Learning to Rank(简称LTR)用机器学习的思想来解决排序问题(关于Learning to Rank的简介请见我的博文Learning to Rank简 ...
- 20145202马超 2016-2017-2 《Java程序设计》第8周学习总结
20145202马超 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 NIO与NIO2 NIO使用频道(channel)来衔接数据节点,对数据区的标 ...
- EF Code First 学习笔记:关系(转)
一对多关系 项目中最常用到的就是一对多关系了.Code First对一对多关系也有着很好的支持.很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性.导航属性等检测到模型之 ...
- python 中使用ConfigParser类修改配置文件
配置文件的格式: [user] user_ip=127.0.0.1 user_name=testuser user_id=13 import ConfigParser conf = ConfigPar ...
- Linux内核分析 03
一,构造一个简单的Linux系统MenuOS 1.Linux内核源代码简介 回顾一下前面的三大法宝和两把宝剑. arch/x86目录下的代码需要重点关注 阅读代码的时候把除了x86以外的都删掉会有利于 ...
- 2017-2018-1 JaWorld 第八周作业
2017-2018-1 JaWorld 第八周作业 团队分工 成员 分工 陈是奇 统计成员工具选择 马平川 类图 王译潇 编码规范 李昱兴 用例图 林臻 状态图 张师瑜 推进工作进展.写博客 UML ...