Activity 的冷热启动
Activity的启动分为冷和热启动两种,所谓的冷启动指的是当前进程不在的时候,启动一个activity。就相当于我们在launcher 桌面上点击某一个app的图标启动一个应用,并且跳转到对应的activity(通常是MainActivity或者SplashActivity)的流程,launcher其实也是一个应用进程。所谓的热启动指的就是在应用内一个ActivityA跳转到ActivityB的流程。这个流程比冷启动简单的多,这个过程我们更关注当前两个Activity的生命周期的调用,这个流程不是本文的分析重点
时序图分析
在分析之前,先奉献上我自己画的一张activity启动流程的时序图在这张时序图里面我们可以看到,完成启动一个activity可能需要用到的类有
1 ActivityThread
2 ActivityManagerService
3 Zygote
4 Activity
如果当前应用处于热启动状态,那么Android系统就不需要Zygote的介入,但是当我们应用处于冷启动流程,也即是从桌面上点击了应用的icon图标进入的流程,就需要Zygote了来帮我们把目标进程fork出来了。具体的话我们看下面的源码分析。
Activity 启动流程分析
startActivity开始
Intent intent=new Intent();
startActivity(intent);
我们一步一步往里面跟,其实startActivity方法最后调用的是startActivityForResult()的方法。我们来看一下startActivityForResult的源码
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
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());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
这里我们可以看到两个重要的分支,如果当前的mParent不存在的时候,那么就调用
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
这里的instrumentation的execstartActivity就是调用到了ActivityManagerService 的startActivity方法。经过一系列转换后,会调用startProcessLocked方法,这里就开始会和zygote交互了
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
我们这里进入到process.start()方法
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 abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
在这里startViaZygote会通过socket的方法,把Zygote唤醒(我们在这里需要关注的socket-connect 关键字往前追踪)
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
最终的调用方法就是我们的时序图中看到的invokeStaticMain方法,它会根据我们在之前掺入的entrypoint,把ActivityThread的main方法调用起来。这里我们就进入到第三个关键的类ActivityThread
ActivityThread做了什么
我们首先进入ActivityThread的main方法
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
里面最重要的方法已经展现出来了,就是attach方法。我们继续进入attach方法
里面最重要的调用就是
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
这个时候又回到ActivityManagerService里面了。
ActivityManagerService经过一系列的调用后,就继续调用到ActivityThread里面的bindApplication中了。
ActivityThread的bindApplication主要就是把当前的上下文和application绑定起来。
app 的如何被创建
ActivityThread 里面的handleBindApplication方法就是目标应用启动的入口。这个方法是在前面的bindApplication通过handler通讯的方法触发调用的,我们主要关注handleBindApplication里面的这一句:
mInstrumentation.callApplicationOnCreate(app);
这一个方法就把application onCreate() 给创建起来了。
Activity 如何被启动
Activity真正启动的入口在ActivityThread 里面的scheduleLaunchActivity方法中。这个方法同样也是有ActivityManagerService触发。我们进入ScheduleLaunchActivity中可以看到核心的方法调用的是
sendMessage(H.LAUNCH_ACTIVITY, r);
同样是通过handler,把当前launcher_activity的指令发送出去。最后会走到
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out paused, because it
// needs to be visible but isn't in the foreground. We accomplish this by going
// through the normal startup (because activities expect to go through onResume()
// the first time they run, before their window is displayed), and then pausing it.
// However, in this case we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just retain the current
// state it has.
performPauseActivityIfNeeded(r, reason);
// We need to keep around the original state, in case we need to be created again.
// But we only do this for pre-Honeycomb apps, which always save their state when
// pausing, so we can not have them save their state when restarting from a paused
// state. For HC and later, we want to (and can) let the state be saved as the
// normal part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
这里面就是两个重要的流程了:
Activity a = performLaunchActivity(r, customIntent);
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
对应的就是我们activity的生命周期了
总结
由于activity启动流程里面,比较复杂的就是应用的冷启动的流程,一套代码流程下来就是非常的繁琐。特别是在最新的Android9以上,出现了很多的handler和socket通讯的方法调用,如果代码不是很熟悉的话,查找整个调用栈会非常的有挑战性。这里还是希望大家可以仔细的查看代码,follow一下流程,相信大家都会有不错的收获和体验