前言
Activtiy 启动是Android App 开发技术中,重要的技术讨论点,本文会尝试先从整体角度,介绍Android 系统整体的启动流程,先建立全局概念并知晓外部表现,再逐步深入细节来分析Activity 启动的具体源码。
先来张Android 系统整体启动流程图
该过程相对比较复杂,也不是本文讨论的重点,但了解全局的启动。简要来说,经过了以后步骤:
BootLoader: 又称为引导程序,主要用来初始化硬件设备,加载内核文件等,通俗讲就是先完成手机操作系统初始化并启动(不同的设备制造商,引导程序是不同的)。
Linux kernal:负责初始化各种软硬件环境,加载驱动程序,挂载根文件系统(/)等,内核启动完成后,它会在根文件系统中寻找 ”init.rc” 文件,然后启动 init 进程。
init 进程:是 Linux 系统中用户空间的第一个进程,进程号为1,Linux中所有的进程都是由init进程直接或间接fork出来的,我们可以说它是 root 进程或者所有进程的父进程。源码路径为: Android/system/core/init/。
init 进程作用:
挂载虚拟文件系统:如 /sys、/dev、/proc等
启动 property 服务、SELinux服务
解析执行 init.rc 文件: 在 init.rc 中启动的系统服务有 servicemanager, adbd, mediaserver, zygote, bootanimation 等。
zygote :原意为“受精卵“。我们知道在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,Android 又是基于Linux的,所以当系统里面的第一个zygote进程运行之后,在这之后再开启App,Android系统通过fork第一个zygote进程来实现。这样做的好处是实现资源共用和更快的启动速度。
每个APP 启动时,都会分配一个独立的Dalvik/ART虚拟机中,运行在独立进程中。
SystemServer :这个Android开发同学,相对来说熟悉一些,主要的作用是启动各种系统服务,如 ActivityManagerService,PackageManagerService,WindowManagerService 以及硬件相关的 Service 等服务,各种系统服务也是在 SystemServer 进程中启动。服务启动完成后,会调用各服务的 service.systemReady()函数 来通知服务已就绪。
Launcher 的启动:
Launcher 的启动比较复杂,而且不同版本的 Android 系统启动逻辑可能也不太一样,所以这里就不具体讨论,大概说明一下启动的策略:SystemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService,ActivityManagerService等基础服务,Launcher 的启动逻辑就在 ActivityManagerService.systemReady() 中。
补一张 国外同行画的 launch启动流程图
1. Activity 启动检查及启动方法
1.1 进程检查
在APP 开发中,Activity必须在AndroidManifest.xml中声明,启动的前提是先检查所属的进程,有无启动,没有启动的话,会先启动所属进程,之后才会启动Activity。Activity默认运行于主进程,但可以指定运行在独立的进程中。
1.2 启动类型
Activity启动有两种类型,即显示启动与隐式启动
- 显示启动:即指定启动的Activity 对象。
A :当前Activity B :要启动的Activity
A:最常见的
startActivity(new Intent(A.this,B.class));
B: Intent ComponentName
ComponentName cn = new ComponentName("A的全限定类名","B的全限定类名") ;
Intent intent = new Intent() ;
intent.setComponent(cn) ;
startActivity(intent) ;
C: Intent packageName
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("A的全限定类名","B的全限定类名");
startActivity(intent);
- 隐式启动:
通过Intent Filter过滤器筛选,适合跨进程拉起。
Intent it = new Intent("com.custom.skip.action");//参数要跳转的activity中定义的action名,这个action是在androidManifest.sml中定义
//it.putExtra("key","value"); //跳转时传的参数
startActivity(it);
2. 主要API 介绍
Activity 源码中,涉及到以下几个重要的类,他们在不同阶段扮演了重要的角色。先来简要认识下他们。
Instrumentation
可通过AndroidManifest.xml 的<Instrumentation>描述该类的实现。
负责创建Activity的具体生命周期。ActivityManager
该类提供与Activity、Service、Process交互的方法。可看作是ActivityManagerService的代理类ActivityManagerService
Android中核心类之一,负责四大组件的启动,切换,调度及应用程序的管理及调度等。ActivityThread
管理主线程,根据Activity管理者的请求调度和执行activities、Provider,Service,Process,broadcasts及其相关的操作。
其中H (Handler)变量,定义了大量的与Service,Provider等相关的消息类型。ActivityStack
负责单个Activity栈的状态和管理。ActivityStackSupervisor
负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈。
3. 详细启动流程
为简单起见,从 常见的Activity 的startActivity() 方法开始分析
android/app/Activity.java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
最终回调用至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);
}
}
}
注意这里有个
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;
}
再看看方法注释
* @param requestCode If >= 0, this code will be returned in
* onActivityResult() when the activity exits.
说明如果requestCode 设置的是 < 0 的值,是不会有onActivityResult返回的。
轮到Instrument 上场了,android/app/Instrumentation.java。
这个类是Activity 应用进程端的核心控制类。
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
看下这个函数的入参
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity is being started.
* @param token Internal token identifying to the system who is starting
* the activity; may be null.
* @param target Which activity is performing the start (and thus receiving
* any result); may be null if this call is not being made
* from an activity.
* @param intent The actual Intent to start.
* @param requestCode Identifier for this request's result; less than zero
* if the caller is not expecting a result.
* @param options Addition options.
contextThread Binder对象,是主进程的context对象;
token Binder对象,指向了服务端;
注意: 这里的ActivityTaskManager.getService(),10.0 开始变成ActivityTaskManagerService,调用startActivity方法,辗转跳转至startActivityAsUser。
这里与Android 9.0 是不同的,9.0 是通过
ActivityManagerNative.getDefault().startActivity() 方式,Binder形式进行应用进程端与系统服务进程之间的交互。
@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) {
return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
bOptions, userId);
}
ActivityTaskManagerService,会调用startActivityAsUser方法
int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
继续往下调用至,ActivityStarter.execute()方法
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
} else {
return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
mRequest.outActivity, mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
}
} finally {
onExecutionComplete();
}
}
ActivityStarter.startActivityMayWait方法中调用多个startActivity方法后会调用到一个比较重要的方法startActivityUnchecked。会根据启动标志位和Activity启动模式来决定如何启动一个Activity以及是否要调用deliverNewIntent方法通知Activity有一个Intent试图重新启动它。
/**
* Decide whether the new activity should be inserted into an existing task. Returns null
* if not or an ActivityRecord with the task into which the new activity should be added.
*/
private ActivityRecord getReusableIntentActivity() {
Decide whether the new activity should be inserted into an existing task
根据启动模式,确定是否将Activity 加入一个已存在的task中。
最终调用方法
mRootActivityContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
注意: 这里与9.0 也是不同的。9.0 是直接通过ActivityStackSupervisor,10.0 是先通过RootActivityContainer。resumeFocusedStacksTopActivities 最终会调用ActivityStack的resumeTopActivityUncheckedLocked方法。
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mInResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mInResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
// end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
// to ensure any necessary pause logic occurs. In the case where the Activity will be
// shown regardless of the lock screen, the call to
// {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mInResumeTopActivity = false;
}
return result;
}
注意看这里面的注释。
在ActivityStack.resumeTopActivityInnerLocked方法中会去判断是否有Activity处于Resume状态,如果有的话会先让这个Activity执行Pausing过程,然后再执行startSpecificActivityLocked方法启动要启动Activity。
后续 先执行onpause方法退出。层层转发,实际调用的是PauseActivityItem.execute方法。
在PauseActivityItem.execute方法中调用ActivityThread.handlePauseActivity方法,经过一步步调用来到performPauseActivity方法,在这个方法中会先去判断是否需要调用callActivityOnSaveInstanceState方法来保存临时数据,然后执行Instrumentation.callActivityOnPause方法继续执行pasue流程。
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
"PAUSE_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Instrumentation.callActivityOnPause方法中直接调用Activity.performPause,至此栈顶Activity的Pausing流程全部完毕。
frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
frameworks/base/core/java/android/app/Activity.java
final void performPause() {
...
onPause();
...
}
至此,基本的链路已经建立。 真正调起Activity oncreate() 的流程类似
完全冷启动流程较为繁琐,将会新增专题记录。
4. 汇总Activity启动流程
1、应用通过startActivity或是startActivityForResult方法向ActivityTaskManager( 9.0以下 ActivityManagerService)发出启动请求。
2、ActivityTaskManager( 9.0以下 ActivityManagerService)接收到启动请求后会进行必要的初始化以及状态的刷新,然后解析Activity的启动模式,为启动Activity做一系列的准备工作。
ActivityStarter 等所在包,com.android.server. *,为服务端进程,ActivityThread等所在包为android.app包下,为客户端进程。
3、做完上述准备工作后,会去判断栈顶是否为空,如果不为空即当前有Activity显示在前台,则会先进行栈顶Activity的onPause流程退出。
4、栈顶Activity执行完onPause流程退出后开始启动Activity。如果Activity被启动过则直接执行onRestart->onStart->onResume过程直接启动Activity(热启动过程)。否则执行Activity所在应用的冷启动过程。
5、冷启动过程首先会通过Zygote进程fork出一个新的进程,然后根据传递的”android.app.ActivityThread”字符串,反射出该对象并执行ActivityThread的main方法进行主线程的初始化。
6、Activity所在应用的进程和主线程完成初始化之后开始启动Activity,首先对Activity的ComponentName、ContextImpl、Activity以及Application对象进行了初始化并相互关联,然后设置Activity主题,最后执行onCreate->onStart->onResume方法完成Activity的启动。
7、上述流程都执行完毕后,会去执行栈顶Activity的onStop过程。
至此,完整的Activity启动流程全部执行完毕。