Android Launcher启动Activity的工作过程
温馨提醒,今天晚上零点就是一年一度的双11购物狂欢节了,不知道大家的购物车是不是已经塞满了呢?今年的双11正好还是在周末,真是太适合买买买了。我也没什么别的福利能带给大家的,这两天关注了一下《第一行代码》在各网店的折扣情况,发现双11果然真是很给力。在当当上,《第一行代码》已经是5折了,而在天猫上,有的店铺更是给出了4折的折扣。对于一直有想法购买《第一行代码》却始终还没下手的朋友们,这真是最好的时机。店铺链接地址如下:
天猫:https://detail.tmall.com/item.htm?id=542469538914
当当:http://product.dangdang.com/24144166.html
另外,有不少朋友都跟我说,已经买了纸质书,但是不方便携带,问我这本书有没有电子版。这里特别跟大家提一下,这本书近期已经推出了电子版,但是电子版并不是免费附赠的,还需要单独购买才行。不过,如果你已经买过了纸质书,可以凭书背后的刮刮卡,到图灵官网去注册,享受1折购买本书电子版的优惠。和网上流传的那种模糊的电子扫描盗版不同,这是官方正版的电子书,格式是PDF,不光内容清晰,而且电子书中的代码都是可以直接复制的,绝对甩盗版体验好几条街。有电子书需求的小伙伴可以到下面的链接购买,记住用刮刮卡享1折优惠哦。
电子版:http://www.ituring.com.cn/book/1841
明天又到周末啦,大家狂购之后还可以在家等着收包裹,真是美滋滋呀。提前祝大家周末愉快!
周五的文章来自 凶残的程序员,详细的分析了Launcher是如何启动Activity的,将之前的AIDL,Binder,AMS等知识点串联起来,希望大家喜欢。
凶残的程序员 的博客地址:
http://blog.csdn.net/qian520ao
通过上一篇文章《Android Binder之应用层精彩解析》可以了解到进程间通讯的一个大致情况,像今天要提到的 Activity 启动过程,也是以 Binder 为通讯方式。系统对这个工作过程做了很多封装,使得启动一个 Activity 变得十分简单。这看似简单的背后,实际上是 Activity 与 ActivityManagerService 之间多次通讯的结果。
阅读该篇文章建议配合源码一起食用,味道更佳。
手机桌面也是一个App,每一个应用的 icon 都罗列在 Launcher 上,点击 icon 触发 onItemClick 事件,下面例如我们要启动「淘宝」这个App,首先我们要在清单文件定义默认启动的 Activity 信息。
然后 Launcher 获取到该信息之后,启动淘宝App
启动 Activity 这一工作不管是相同应用的2个不同 Activity 的启动,或者是不同进程不同应用的 Activity 启动,都是由 Activity 大管家 ActivityManagerService(简称AMS)全权管理,而他们之间的通讯就要用到 Binder,通过 Binder 与 AMS 多次通讯,才能启动淘宝App。
通过对 Android 操作系统的学习可以提高我们对操作系统在技术实现上的理解,这对于加强开发人员的内功是很有帮助的。
但是由于 Android 内部实现多数都比较复杂,在研究内部实现上应该更加侧重对整体流程的把握,而不能深入到代码细节不能自拔。
-
Launcher 通知 AMS 启动淘宝APP的 MainActivity,也就是清单文件设置启动的 Activity。
-
AMS 记录要启动的 Activity 信息,并且通知 Launcher 进入 pause 状态。
-
Launcher 进入 pause 状态后,通知 AMS 已经 paused 了,可以启动淘宝了。
-
淘宝app未开启过,所以 AMS 启动新的进程,并且在新进程中创建 ActivityThread 对象,执行其中的 main 函数方法。
-
淘宝app主线程启动完毕后通知 AMS,并传入 applicationThread 以便通讯。
-
AMS 通知淘宝绑定 Application 并启动 MainActivity。
-
淘宝启动 MainActivitiy,并且创建和关联 Context,最后调用 onCreate 方法。
startActivityForResult
我们从 Activity 的 startActivity 方法开始分析。
startActivity 方法有好几种重载方式,但它们最终都会调用 startActivityForResult 方法。
在 startActivityForResult 方法内,会调用 Instrumentation 的 execStartActivity 方法。
Instrumentation
Instrumentation 从字面上来看是仪器盘的意思,具体到程序中是管理 activity 的一个工具类,包括创建和启动 Activity,activity 的生命周期方法都是由 Instrumentation 这个仪器来控制,一个进程中只用一个 Instrumentation 实例。
我们截取了比较关键的代码片段来分析 Instrumentation 的 execStartActivity 方法,方法参数注释中也有对该方法的几个参数进行简单描述。下面我们来分析一下比较重要的2个参数,contextThread 和 token。
IBinder contextThread
在上一个方法中传入为 mMainThread.getApplicationThread(),我们可以看到这是一个 IBinder 对象,说明它的作用就是用于进程间通讯的 Binder 对象。
mMainThread 实际上是 ActivityThread 对象。ActivityThread,就是主线程,也就是UI线程,它是在App启动时创建的,它代表了App应用程序。
啥?ActivityThread 代表了App应用程序,那 Application类 岂不是被架空了?其实,Application 对我们App开发人员来说也许很重要,但是在Android系统中还真的没那么重要,他就是个上下文。Activity 不是有个 Context 上下文吗?Application 就是整个 ActivityThread 的上下文。
我们找到 ActivityThread 文件,其实这个 getApplicationThread 方法获取的是内部类 ApplicationThread 对象,而且 ApplicationThread 继承 ApplicationThreadNative
我们打开 ApplicationThreadNative类 (需要通过sdk的源码找到,具体路径为Sdk\sources\android-25(sdk版本)\android\app\ApplicationThreadNative)
通过构造方法我们就很清晰的可以得知原来这个 ApplicationThreadNative 就是相当于 AIDL 通讯中的 Stub,也就是服务端,ApplicationThreadProxy 即 AIDL 通讯中的 Proxy,也就是客户端。所以 ApplicationThread 是通讯的具体实现类。
上面的介绍中我们也说过,Activity 的启动实际上是多次进程间通讯的成果,看到这里我们就可以得出结论:ActivityThread 通过内部类 ApplicationThread 来进行进程间通讯
IBinder token
追溯到参数起源,这个 token 对象,是在 Activity 的 attach 方法中传入的,也就是 Activity 的创建与关联时候(下面的内容会提到)传入的 Activity 信息。
这也是个 Binder 对象,它代表了 Launcher 这个 Activity,这里也通过 Instrumentation 传给 AMS,AMS 查询后,就知道是谁向 AMS 发起请求了。
contextThread 和 token 这两个参数是伏笔,传递给 AMS,以后 AMS 想反过来通知 Launcher,就能通过这两个参数,找到 Launcher。
startActivity
在 Instrumentation 中,启动 Activity 真正的实现是由 ActivityManagerNative.getDefault() 的 startActivity 方法来完成。
ActivityManagerService(下面简称AMS)继承自 ActivityManagerNative(下面简称AMN),而 AMN 继承自 Binder 并实现了 IActivityManager 这个 Binder 接口,因此 AMS 也是一个 Binder,它是 IActivityManager 的具体实现,由于ActivityManagerNative.getDefault() 其实是一个 IActivityManager 类型的 Binder 对象,因此它的具体实现是 AMS。
我们先看代码,捋一捋上述所说的关系。
首先我们来看这个命名方式,xxxNative,根据我们的 AIDL分析文章,我们知道 Stub 持有 Binder 本地对象,Proxy 持有的是 Binder 的代理对象。所以系统命名也是依据此因素(Native:本地的,土著的)作为命名规范。
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final SingletongDefault = new Singleton() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
}
};
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;//同一进程,返回Stub本地对象。
}
return new ActivityManagerProxy(obj);//跨进程,返回代理对象。 }
可以发现,在 AMN 中,AMS 这个 Binder 对象采用单例模式对外提供,Singleton 是一个单例的封装类,第一次调用它的 get 方法时它会通过 create 方法来初始化 AMS 这个 Binder 对象,在后续的调用中则直接返回之前创建的对象(使用同一个AMS)。
分析 create 方法,根据上篇Binder分析,可以得知在 IActivityManager 内(相当于Client),通过应用程序中的0号引用,可以向 SMgr 获取服务端(Server)的 Binder 引用。
AMN 通过 getDefault 方法,从 ServiceManager 中获取 AMS 中 Binder 的引用对象,然后将它转换成 ActivityManagerProxy 对象(简称AMP),AMP 就是 AMS 的代理对象。
类似 AIDL 中客户端的绑定代码,此时我们就可以通过 ActivityManagerProxy(asInterface返回值为 IActivityManager),与 AMS 进行通讯。
//ActivityManagerProxy
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();//从Parcel池中获取Parcel对象(通讯载体),用来写入数据
Parcel reply = Parcel.obtain();//如果方法有返回值,则写入返回值
data.writeInterfaceToken(IActivityManager.descriptor);//Binder唯一标识
//caller即上面提到的contextThread,AMS就可以通过它与Launcher通讯
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
//resultTo即上面提到的token,包含Launcher的Activity信息
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
......
//发送类型为START_ACTIVITY_TRANSACTION的请求给AMS,data包含Launcher和淘宝App的信息
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
//Instrumentation通过result来检查并抛出异常(Activity未在清单文件注册等)
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
从上面的分析可以知道,Activity 是由 AMN.getDefault() 来启动的,而 AMN.getDefault() 实际上是 AMS,因此 Activity 的启动过程又转移到了 AMS 中,为了继续分析这个过程,只需要查看 AMS 的 startActivity 方法即可。
1. Launcher 通知 AMS 启动淘宝 APP 的 MainActivity,也就是清单文件设置启动的 Activity。
上个图,先通俗易懂的总结一下 Activity 启动的整体流程,对整体框架有一个大概认识。
AMS分析
再回顾一遍,通过对 AMS 类的查看,我们可以知道 AMS 也是一个 Binder,并且它是 IActivityManager 的具体实现。
接着我们继续分析 AMS 的 startActivity 方法,这个阶段比较复杂和繁琐,一不小心就绕晕了,我们了解大致过程,不深入代码细节,对整体流程建立足够认识即可。(毕竟功力有限)
//AMS
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
//7.0Acitivty启动管理类新增ActivityStarter(原本是ActivityStackSupervisor处理该过程)
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);
}
ActivityStarter
//ActivityStarter
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
Bundle bOptions, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
......
//根据intent在系统中找到合适的应用的activity,如果有多个activity可选择,
//则会弹出ResolverActivity让用户选择合适的应用。
ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
profileFile, profileFd, userId);
......
int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor,
resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, outRecord, container,
inTask);
......
return res;
}
//在startActivityLocked方法里,对传过来的参数做一些校验,然后创建ActivityRecord对象,再调用startActivityUnchecked(7.0前是startActivityUncheckedLocked)方法启动Activity。
final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
......
//创建ActivityRecord对象
//ActivityRecord : 在AMS中,将用ActivityRecord来作为Activity的记录者,每次启动一个Actvity会有一个对应的ActivityRecord对象,表示Activity的一个记录
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
options, sourceRecord);
......
err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true, options, inTask);
//此处将通知ActivityStarter, Activity对应的Task被移动到前台
postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
return err;
}
在startActivityLocked 方法里,对传过来的参数做一些校验,然后创建 ActivityRecord 对象,再调用 startActivityUnchecked 方法启动 Activity。
startActivityUnchecked 方法负责调度 ActivityRecord 和 Task,理解该方法是理解 Actvity 启动模式的关键。
startActivityUnchecked 方法调度task的算法非常复杂,和当前回退栈,要启动的 acitivity 的启动模式以及 taskAffinity 属性,启动 activity 时设置的 intent 的 flag 等诸多要素相关, intent 的 flag 就有很多种情况,故此算法非常复杂,需要阅读源码并结合特定启动情况才能理解。
接下来调用 ActivityStack 的 startActivityLocked 将 ActivityRecord 加入到回退栈里
//ActivityStarter
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
...
//ActivityStack的startActivityLocked,不要搞混了。
//同时调用WindowManager准备App切换相关的工作
mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
} else {
//最终调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
}
}
ActivityStackSupervisor
//ActivityStackSupervisor
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
//待启动Activity对应的Task为前台Task时,调用该Task对应ActivityStack的resumeTopActivityUncheckedLocked函数
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
//否则只是调用当前前台栈的resumeTopActivityUncheckedLocked
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
}
return false;
}
ActivityStack
接着跟进 ActivityStack
//ActivityStack
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
result = resumeTopActivityInnerLocked(prev, options);
return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
//mResumedActivity指向上一次启动的Activity(Launcher)
if (mResumedActivity != null) {
...
//通知Launcher进入pause状态
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
if (pausing) {//Launcher已经暂停了
...
if (next.app != null && next.app.thread != null) {
//如果app已经启动过
//调用淘宝(待启动)Activity所在进程的优先级,保证其不被kill
mService.updateLruProcessLocked(next.app, true, null);
}
}
...
if (next.app != null && next.app.thread != null) {
//如果Intent不为空,调用NewIntent方法传入Intent
next.app.thread.scheduleNewIntent(next.newIntents, next.appToken, false);
//假设淘宝App已经启动,点击Home键返回到Launcher,再次从Launcher启动淘宝(或者第三方启动已开启的App)
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
...
} else {
...
//创建进程,冷启动Activity。或者已启动App,重新启动Activity
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
return true;
}
resumeTopActivityInnerLocked 函数非常繁琐,但整体来讲应该只有两个比较关键的地方:
-
判断是否已有 Activity(mResumedActivity) 启动(即 Launcher,通过 Launcher 启动淘宝的),有则暂停该 Activity
-
判断是否需要重新启动目标 Activity,即 Activity 是否已经启动过。(例如保存在后台,应用切换)
2. AMS 记录要启动的 Activity 信息,并且通知 Launcher 进入 pause 状态。
3. Launcher 进入 pause 状态后,通知 AMS已经 paused 了,可以启动淘宝了。
创建进程
接下来的操作就比较重要了,创建进程,启动 Activity。
从上面代码可以了解到 startSpecificActivityLocked 为启动 Activity 的两种不同情况
-
例如从 Launcher 冷启动淘宝,则需要创建新进程,通过 AMS 调用 Zygote(孕育天地)孵化应用进程。
-
如果淘宝App已经启动,例如从 MainActivity 跳转到 LoginActivity,则通过 realStartActivityLocked 启动。
因为我们开头以 Launcher 启动淘宝为例子,所以我们硬着头皮继续分析 AMS 创建进程以及 Activity 的绑定过程。
上面分析到 mService.startProcessLocked,到了这里我们直接看启动线程的方法,中间的过程实在是略复杂。
4. 淘宝App未开启过,所以 AMS 启动新的进程,并且在新进程中创建 ActivityThread 对象,执行其中的 main 函数方法。
//ActivityServiceManager
//Process.java的start函数,将通过socket发送消息给zygote
//zygote将派生出一个子进程,子进程将通过反射调用ActivityThread的main函数
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
Zygote 进程孵化出新的应用进程后,通过反射执行 ActivityThread类 的 main方法。在该方法里会先准备好 Looper 和 消息队列,然后调用 attach 方法将应用进程绑定到 AMS,然后进入 loop 循环,不断地读取消息队列里的消息,并分发消息。
//ActivityThread
public static void main(String[] args) {
...
//准备主线程的Looper,下篇博文分析Handler,Looper
Looper.prepareMainLooper();
//创建当前进程的ActivityThread
ActivityThread thread = new ActivityThread();
//将该进程绑定到AMS
thread.attach(false);
if (sMainThreadHandler == null) {
//保存进程对应的主线程Handler
sMainThreadHandler = thread.getHandler();
}
...
//进入主线程的消息循环
Looper.loop();
...
}
//上面说过,ApplicationThread是ActivityThread用来与AMS通讯的中介
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
if (!system) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
//调用AMS的attachApplication方法,将ApplicationThread对象绑定至ActivityManagerService
//这样AMS就可以通过ApplicationThread代理对象控制应用进程
mgr.attachApplication(mAppThread);
} else {
...
}
}
至此,进程创建完毕,并且也有了主线程,剩下的便是 启动Activity 和 关联context 等初始化操作了。
5. 淘宝app主线程启动完毕后通知 AMS,并传入 applicationThread 以便通讯。
AMS启动Activity小结
至此通过下图总结一下在 AMS 启动 Activity 的大致流程,各个方法函数像一台机器上的不同零件,各尽其责,分工明确。
虽然错综复杂,但是耦合性低,比如说启动模式需要优化,重新完善 startActivityUnchecked 方法函数即可。
关联Activity
在这个时候,虽然有了app进程,和主线程,但是仍是一副空壳。没有 activity 信息,没有关联上下文,这时候就要请出 AMS 来进行指挥。此时的app应用–>
因为主线程 main 入口通过attach方法将 ApplicationThread 发送给 AMS ,所以通过 applicationThread 这个桥梁来通知 ActivityThread 创建/关联和启动 Activity。
通过 Binder 获取 proxy(ApplicationThread )方的进程id,也就是获取目标(淘宝)进程的Pid。
接下来重点分析 attachApplicationLocked 方法
//AMS
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
//因为进程由AMS启动,所以在AMS中一定会有ProcessRecord(进程记录)
//如果没有ProcessRecord,则需要杀死该进程并退出
if (app == null) {
...
return false;
}
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
//如果从ProcessRecord中获取的IApplicationThread不为空,则需要处理该IApplicationThread
//因为有可能此Pid为复用,旧应用进程刚释放,内部IApplicationThread尚未清空,
//同时新进程又刚好使用了此Pid
handleAppDiedLocked(app, true, true);
}
//创建死亡代理(进程kill后通知AMS)
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
//进程注册成功,移除超时通知
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
...
try {
//******绑定Application******
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
} catch (Exception e) {
...
//bindApplication失败后,重启进程
startProcessLocked(app, "bind fail", processName);
return false;
}
try {
//******启动Activity(启动淘宝MainActivity)******
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;//didSomething表示是否有启动四大组件
}
} catch (Exception e) {
badApp = true;
}
...
//绑定service和Broadcast的Application
if (badApp) {
//如果以上组件启动出错,则需要杀死进程并移除记录
app.kill("error during init", true);
handleAppDiedLocked(app, false, true);
return false;
}
//如果以上没有启动任何组件,那么didSomething为false
if (!didSomething) {
//调整进程的oom_adj值, oom_adj相当于一种优先级
//如果应用进程没有运行任何组件,那么当内存出现不足时,该进程是最先被系统“杀死”
updateOomAdjLocked();
}
return true;
}
在 attachApplicationLocked 中有两个比较重要的方法函数,分析到这里我们的文章也要进入尾声了。
-
thread.bindApplication(…) : 绑定 Application 到 ActivityThread
-
mStackSupervisor.attachApplicationLocked(app) : 启动 Activity(7.0前为mMainStack.realStartActivityLocked())
bindApplication
在上面我们说道,ActivityThread 通过 ApplicationThread 与 AMS 进行通讯,所以上面的 thread.bindApplication(...)方法,就应该是通过 ApplicationThread 进行传达。
在 ActivityThread 的内部类 ApplicationThread 中,我们找到 bindApplication 方法
发送消息是通过 H 的 Handler类 完成的,这个命名贼个性,很令人印象深刻。PS : 我怀疑是编写这个类的工程师词穷了…
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
...
public static final int RESUME_ACTIVITY = 107;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
...
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
//绑定application
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
}
可以看出,这个 H类 相当于 ActivityThread 和 ApplicationThread 的中介人,也就是拉皮条的。
ActivityThread 通过 ApplicationThread 与 AMS 通讯。
ApplicationThread 通过 H 与 ActivityThread 通讯,处理 Activity 事务。
那么既然 H、ApplicationThread 都在 ActivityThread类 里,为何 ApplicationThread 还要通过 Handler 来发送消息?
-
便于集中管理,方便打印Log日志等,H 就是这其中的大管家。
-
ActivityThread 通过 ApplicationThread 和 AMS 进行进程间通信,AMS 以进程通讯的方式来完成 ActivityThread 的请求后调用 ApplicationThread 中的 Binder 方法,然后 ApplicationThread 会向 H 发送消息,H 收到消息后会将 ApplicationThread 中的逻辑切换到 ActivityThread 中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
而且有一点要注意的是,这个 ActivityThread 并不是一个线程 Thread,它是 final类 并且无继承或者实现其它类,它的作用就是在 main 方法内消息循环,处理主线程事务。(还需了解 Looper 及消息机制)
言归正传,上面 ApplicationThread 给 H 发送 BIND_APPLICATION 标识,在 H 中,通过 handleBindApplication 处理 application 的绑定事务。
//ActivityThread
private void handleBindApplication(AppBindData data) {
...
//根据传递过来的ApplicationInfo创建一个对应的LoadedApk对象
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//获取LoadedApk
/**
* For apps targetting Honeycomb or later, we don't allow network usage
* on the main event loop / UI thread. This is what ultimately throws
* {@link NetworkOnMainThreadException}.
*/
//禁止在主线程使用网络操作
if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
StrictMode.enableDeathOnNetwork();
}
/**
* For apps targetting N or later, we don't allow file:// Uri exposure.
* This is what ultimately throws {@link FileUriExposedException}.
*/
//7.0引入Fileprovide
if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
StrictMode.enableDeathOnFileUriExposure();
}
...
//创建进程对应的Android运行环境ContextImpl
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
if ((InstrumentationInfo)ii != null) {
...
} else {
//注意Activity的所有生命周期方法都会被Instrumentation对象所监控,
//也就说执行Activity的生命周期方法前后一定会调用Instrumentation对象的相关方法
mInstrumentation = new Instrumentation();
}
try {
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
//加载进程对应Package中携带的ContentProvider
installContentProviders(app, data.providers);
...
mInstrumentation.onCreate(data.instrumentationArgs);
try {
//这里会调用Application的onCreate方法
//故此Applcation对象的onCreate方法会比ActivityThread的main方法后调用
//但是会比这个应用的所有activity先调用
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
如上文所述,handleBindApplication 的目的是让一个Java进程融入到 Android 体系中。因此,该函数中的代码主要进行以下工作:
-
按照 Android 的要求,完成对进程基本参数的设置置,包括设置进程名、时区、资源及兼容性配置;同时也添加了一些限制,例如主线程不能访问网络等。
-
创建进程对应的 ContextImpl、LoadedApk、Application 等对象,同时加载 Application 中的 ContentProvider,并初始化 Application。
-
使用 Instrumentation 监控 Activity 的生命周期。(一个进程对应一个 Instrumentation 实例)
当完成上述工作后,新建的进程终于加入到了 Android 体系。
6. AMS通知淘宝绑定 Application 并启动 MainActivity。
attachApplicationLocked
在上述代码 AMS 的 attachApplicationLocked 方法中,我们说道:
在 attachApplicationLocked 中有两个比较重要的方法函数,分析到这里我们的文章也要进入尾声了。
thread.bindApplication(…) : 绑定 Application 到 ActivityThread
mStackSupervisor.attachApplicationLocked(app) : 启动 Activity
绑定了 Application 之后,我们就可以启动 Activity(淘宝MainActivity)。
//ActivityStackSupervisor
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
//ActivityStackSupervisor维护着终端中所有ActivityStack
//此处通过轮询,找出前台栈顶端的待启动Activity
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayListstacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack)) {
continue;
}
ActivityRecord hr = stack.topRunningActivityLocked();
if (hr != null) {
//前台待启动的Activity与当前新建的进程一致时,启动这个Activity
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
//realStartActivityLocked进行实际的启动工作
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (RemoteException e) {
}
}
}
}
}
return didSomething;
}
大概系统工程师也觉得这个启动过程贼鸡儿绕了,最终启动的方法命名为 realStartActivityLocked,意味着告诉你,大伙儿不要搞晕了,这个就是最后启动 Activity 的方法了。
最后我们直捣黄龙,在 ActivityStackSupervisor 方法中,我们找到如下代码
//ActivityStackSupervisor
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
看到这里想必大伙儿都明白了,AMS 最后通过 ApplicationThread 通知 ActivityThread 启动 Activity,感觉这一切的通讯都像发电报一样,鬼斧神工出神入化,皆出架构师之目营心匠。
那么到这里我们就能推算出接下来的老套路了 ApplicationThread—> H—> ActivityThread—> 最终启动 Activity 的方法。
ActivityThread
//ActivityThread
//内部类ApplicationThread
private class ApplicationThread extends ApplicationThreadNative {
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
ListpendingResults, ListpendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
//设置参数
...
//从LAUNCH_ACTIVITY这个标识我们就可以知道,它就是用来启动Activity
sendMessage(H.LAUNCH_ACTIVITY, r);
}
}
private class H extends Handler {
...
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
//利用ApplicationInfo等信息得到对应的LoadedApk,保存到ActivityClientRecord
//ActivityClientRecord包含Activity相关的信息
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
}
//ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
...
}
...
}
handleLaunchActivity 方法里有有两个重要的函数调用,
-
performLaunchActivity : 会调用 Activity 的 onCreate,onStart,onResotreInstanceState 方法
-
handleResumeActivity : 会调用 Activity 的 onResume 方法.
从上面的源码可以看出,performLaunchActivity 方法最终完成了 Activity 对象的创建和启动过程,并且 ActivityThread 通过 handleResumeActivity 方法来调用被启动 Activity 的 onResume 这一生命周期方法。
performLaunchActivity
【performLaunchActivity】 这个方法主要完成了如下几件事。【摘自Android开发艺术探索】
1、从 ActivityClientRecord 中获取待启动的 Activity 的组件信息。
2、通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象。
3、通过 LoadedApk 的 makeApplication 方法来创建 Application 对象。
//ActivityThread的performLaunchActivity方法
//r.packageInfo为LoadedApk对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
其实在我们上面的 bindApplication 中,我们就有介绍到通过 LoadedApk 创建 Application,并且创建完毕后,通过 Instrumentation 的 callApplicationOnCreate 来调用 Application 的 onCreate 方法
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...
mInstrumentation.callApplicationOnCreate(app);
所以第三步是为了判断 Application 是否为空,而且我们从 makeApplication 方法中也能看出如果 Application 已经被创建过了,那么就不会再重复创建了。
4、创建 ContextImpl 对象,并通过 Activity 的 attach 方法来完成一些重要数据的初始化。
ContextImpl 是一个很重要的数据结构,它是 Context 的具体实现,Context 中的大部分逻辑都是由 ContextImpl 来完成的。ContextImpl 来完成的。ContextImpl 是通过 Activity 的 attach 方法来和 Activity 建立关联的,除此之外,在 attach 方法中 Activity 还会完成 Window 的创建并建立自己和 Window 的关联,这样当 Window 接收到外部输入事件后就可以将事件传递给 Activity。
5、调用 Activity 的 onCreate 方法
mInstrumentation.callActivityOnCreate(activity, r.state);
由于 Activity 的 onCreate 已经被调用,这也意味着 Activity 已经完成了整个启动过程。
6、调用 Activity 的 onStart,onResotreInstanceState 方法
mInstrumentation.callActivityOnCreate(activity, r.state);
...
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
至此从 Launcher 启动 Activity 的工作过程整个流程已经阐述完毕了,通过这次分析,对启动 Activity 的来龙去脉有了大致的掌控,但是也留下了几个知识点尚未探索清晰。(越深入探索,越发现不足)
-
Looper,Handler的工作机制(Android的消息机制)
-
Context 到底是什么
-
Window的内部机制又是怎样的
如果是淘宝 MainActivity 启动 LoginActivity 呢?其实原理和上述过程大体一致,只是在 ActivityStackSupervisor 的 startSpecificActivityLocked 方法中,发现进程已经启动,直接调用 realStartActivityLocked 启动 Activity。
欢迎长按下图 -> 识别图中二维码
或者 扫一扫 关注我的公众号
微信扫一扫
关注该公众号