一文搞定面试 | Activity启动流程之冷热启动(下)
Activity启动流程由于篇幅较长,将分述两篇文章进行讲解。
上文主要进行概念提要和流程综述,下文主要从源码角度逐步探寻流程经过
一图看懂
在上一篇中,已经大致将流程从概念上进行梳理了一遍,在结尾中给出了这么一张图,那么本文将从源码角度还原这张图的全部流程和细节。本文基于Android 31
源码进行解析
源码深入
startActivity的起点
对于Launcher点击应用图标来说,也是startActivity的调用。最终均通过Instrumentation
这个工具类,向AMS发起startActivity
的Binder通信行为
// Activity.java
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
startActivity
>>>startActivityForResult(这里有很多分支,但最终都会走下一路径)
>>>Instrumentation.execStartActivity
// Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
// ……
IApplicationThread whoThread = (IApplicationThread) contextThread;
// ……
// 注意下面的ActivityTaskManager.getService()
// 这里即相当于调用了AMS的startActivity()
// 同时关注下第一个参数,whoThread,传入的是IApplicationThread对象,而这个来源于Activity对应的ActivityThread里的mAppThread
// 也就是应用进程创建之初创建的主线程,而IApplicationThread是Stub,即Binder的服务端
// 这里留个心眼,后面有呼应
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
// ……
}
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
// 这里从ServiceManager中获取到了ACTIVITY_TASK_SERVICE即AMS的Binder对象,并最终将其包装成Proxy返回供外部调用
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
AMS创建Activity环节
AMS中的startActivity目前均交由ActivityTaskManagerService进行代理,当前已进入System Server进程,在该流程return前,Client即发起startActivity的应用进程均处于挂起状态
// ActivityTaskManagerService.java
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
ActivityTaskManagerService.startActivity() >>> startActivityAsUser()
>>> ActivityStarter.execute() >>> executeRequest() >>> startActivityUnchecked() >>> startActivityInner()
>>> RootWindowContainer.resumeFocusedTasksTopActivities()
>>> Task.resumeTopActivityUncheckedLocked() >>> resumeTopActivityInnerLocked()
>>> ActivityTaskSupervisor.startSpecificActivity()
// ActivityStarter.java
// 这个类的含义很好理解,启动器嘛
private int executeRequest(Request request) {
// ……这个方法内可以看到 确定Intent和flag应如何转换为活动以及相关的任务和堆栈
// r是新build出来的ActivityRecord对象
startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
}
// ActivityTaskSupervisor.java
// 这是之前提到过的大管家
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
// 热启动和暖启动流程,最后会一起提到,先不讲,先继续看冷启动fork进程
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
// 冷启动,创建应用进程
final boolean isTop = andResume && r.isTopRunningActivity();
// 这一块关于socket是如何发送的,待补充
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Zygote孵化应用进程
Zygote的主要职责就是孵化进程,其中包括管理AMS的System Server进程也由它进行孵化。通信采用Soceket Server持续监听。新的子应用进程孵化完成后,将会反射调用ActivityThread.main()
// ZygoteInit.java
// Zygote进程启动类
public static void main(String[] argv) {
caller = zygoteServer.runSelectLoop(abiList);
}
// ZygoteServer.java
// Zygote Socket服务端
Runnable runSelectLoop(String abiList) {
while (true) {
// connect就是AMS Client发起的连接请求
try {
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command =
connection.processCommand(this, multipleForksOK);
} catch (Exception e) {
// 这里贴一段官方注释,注意processCommand将会执行ActivityThread的main方法
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other
// main() method). Log the details of the exception and bring down
// the process.
}
}
}
// ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
// 我们的目的是为了看进程fork,所以找关键词:进程号pid
// 这里Zygote完成了子进程fork创建
// 然后根据该方法内的注释,我们又关注到了handleChildProc()
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
// ……
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
}
private Runnable handleChildProc(ZygoteArguments parsedArgs,
FileDescriptor pipeFd, boolean isZygote) {
// 由于需要fork子进程,所以isZygote为true,走childZygoteInit
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
// 这里的调用链就很简单了,就反射执行main方法,而class对象上面的注释里就提到了,是ActivityThread
// 至于这块逻辑怎么就确认是ActivityThread,我解释不了hh
return ZygoteInit.childZygoteInit(
parsedArgs.mRemainingArgs /* classLoader */);
}
}
应用进程创建后
应用进程创建后,被反射执行了ActivityThread.main(),内容比较少,主体流程就是将自身ActivityThread实例attach给AMS
// ActivityThread.java
public static void main(String[] args) {
// 关于looper的内容就不多阐述了,对handler这块想要了解的就去翻下我前面的文章叭
Looper.prepareMainLooper();
// 这里就要开始绑定了
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system, long startSeq) {
if (!system) {
// 因为传进来的是false,所以走这里
final IActivityManager mgr = ActivityManager.getService();
try {
// 那这个老生常谈了,那就是去AMS看下文喽
// 所以当AMS完成attach后,该线程才会唤醒,去执行之后的loop()
// 前面startActivity中调用AMS时,传入了同样的参数类型:IApplicationThread
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
应用进程向AMS发起请求时,通过ServiceManager得到AMS注册的Binder从而得到Proxy代理类,而AMS需要向应用进程发起调度时,则通过作为服务端时接受的IApplicationThread对象以进行工作
那不如看看IApplicationThread能做些什么吧?在ActivityThread中,mAppThread是ApplicationThread
// ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
// 由于里面的方法大同小异,随意选取一个眼熟的,四大组件之一的Service
// sendMessage通过外部类ActivityThread发送handler消息,最终会回调执行Service.onCreate()
// 那把其他方法大致可以扫一眼,四大组件的一些处理皆需要通过这里发起
// 那发起的客户端应该就是AMS了,所以为什么说AMS是四大组件的集中管理者
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
}
// handleMessage
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
AMS绑定应用进程
AMS完成了Application创建后,通知ActivityThread进行生命周期回调
ActivityManagerService.attachApplication() >>> attachApplicationLocked() // 这里对ProcessRecord进行了一些状态设置……
>>> IApplicationThread.bindApplication() // 这里又回去了,不用解释了吧,在ActivityThread里发送对应的handler消息
>>> ActivityThread.handleBindApplication()
// 这里就接近尾声了,完成了application的创建,onCreate这块是在主线程,所以注意尽可能避免耗时操作
>>> makeApplication() + mInstrumentation.callApplicationOnCreate
是不是觉得哪里不对劲?Activity还没启动呢!想一想一件事,Binder的挂机机制,回到AMS中调用bindApplication
的后面
// ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// ……
thread.bindApplication()
// ……
// 这个时候,Application已经完成了onCreate()
// 一开始我也找了好久,很多文章中也没有提到这一茬,直到我仔细看了官方注释
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
// attachApplication全局搜了下只剩下RootWindowContainer里还有了,去看看吧
// 当然喔,这里只是我的想法,但是他们的方法名、入参、返回值一模一样,我也就不多想了
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
// RootWindowContainer
boolean attachApplication(WindowProcessController app) throws RemoteException {
// 看来看去,startActivityForAttachedApplicationIfNeeded这个最顺眼
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app,
rootTask.topRunningActivity());
rootTask.forAllActivities(c);
c.recycle();
}
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top) {
// realStartActivityLocked这个方法熟不熟悉
if (mTaskSupervisor.realStartActivityLocked(r, app,
top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
mTmpBoolean = true;
}
}
如果你忘了realStartActivityLocked在哪见过的话,我帮你回忆回忆。现在想起来了嘛
// ActivityTaskSupervisor.java
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
// 热启动和暖启动流程
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
// 冷启动,创建应用进程
final boolean isTop = andResume && r.isTopRunningActivity();
// 这一块关于socket是如何发送的,待补充
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Activity最终启动
对于这块的调用链,不同版本源码可能有所不同,但最终都将通过ActivityThread.performLaunchActivity
或类似方法名展开。当然这里举例的是冷启动状态下,Activity处于ON_CREATE
阶段的情况,如果是热启动的话,只需要快速进行状态恢复就好了
ActivityTaskSupervisor.realStartActivityLocked()
>>> ClientLifecycleManager.scheduleTransaction()
>>> ClientTransaction.schedule()
>>> IApplicationThread.scheduleTransaction()
// 这里在ActivityThread里没找到对应的方法,在其父类中找到
>>> ActivityThread:ClientTransactionHandler.scheduleTransaction() // 发送了EXECUTE_TRANSACTION
>>> TransactionExecutor.execute() >>> executeCallbacks() >>> cycleToPath() >>> performLifecycleSequence()
// 这次是父类引用,子类实现了
// 当然这里是根据lifecycle生命周期变化调度对应方法,热启动就不需要launchActivity了
>>> ActivityThread:ClientTransactionHandler.handleLaunchActivity()
>>> ActivityThread.performLaunchActivity()
// 包括其他生命周期分发也都能看到
>>> Instrumentation.callActivityOnCreate()
>>> Activity.performCreate()
现在再来对比一下这张图,有所区别的就是14.1和14.2的方法名,但整体调用链却是一模一样。对于Activity启动的整体流程,无论是冷启动还是热启动,可以不用过于关注细节的方法调用链,应该关心如图几个具有关键职能的类之间的调度流转。
在厘清这个之后,再回头去过一遍源码细节,相信你会有所收获
灵魂发问
暂无,等待大佬们提供面试问题……欢迎评论
拜读
第一篇主攻源码流程,第二篇主攻概念及思路解析,两篇的阅读顺序可以不一定,但结合起来,非常有助于理解
# Android Application 启动流程分析及其源码调用探究
如果觉得本文对你有帮助,不妨
点赞+收藏+关注
支持一波,感谢肯定和青睐当然,更希望
初读点赞
、再读收藏
、三而关注
转载自:https://juejin.cn/post/7239484016948658235