作为一名合格的Android开发工程师,我们不仅要会使用四大组件,并且要知晓其背后运作的原理!当我们学会了其背后的运作原理,才能更好的帮助我们进行开发工作,知晓每个组件是如何与系统进行交互、数据传递以及调用逻辑,当遇bug难题,才能更好的对症下药及时解决。
本博文是由android8.1.0源码分析后的结果
四大组件如Activity的打开、关闭等操作都是由App进程通过Binder跨进程调用到AMS(ActivityManagerService)进行处理完成的,AMS作为系统提供的模块,用于组织管理四大组件的业务逻辑调用,可以说它是四大组件的日常操作的中心枢纽,几乎所有的操作都会经过AMS,在分发到各个子模块进行判断处理;所以,学会AMS将十分重要,为了更快理解AMS,我们先了解AMS的一些重点类,在以startActivity方法为样例,将重点类连接起来,融会贯通
窗口活动,四大组件之一,可以与用户进行交互的页面,运行在App客户端进程;Activity有自己的窗口大小,全屏或者部分窗口,可以配置启动模式LaunchMode以及启动时配置的Flag等,还可以配置栈taskAffinity属性等
运行在AMS服务端进程,记录一个Activity的相关信息,包括但不仅限于其包名、Activity名字、进程信息、启动Intent、运行状态等信息,还有它属于哪个栈TaskRecord、以及它的线程信息ProcessRecord;
它里面有一个重要的appToken成员,是一个唯一标识量,客户端和服务端都根据这个标识来确定对应的ActivityRecord或ActivityClientRecord,所以涉及到Activity信息相关的东西,在AMS和App进程之间不传用Activity来传递,一般都是由appToken来传递确定
记录一个进程信息,包含进程名、IApplicationThread客户端线程、uid、线程状态等相关信息,通常保存在AMS服务端,客户端访问服务端时,通过客户端的pid可以获取对应的ProcessRecord,进而可以知道向哪个客户端发起调用
运行在AMS服务端进程,组织管理许多ActivityRecord,它就是我们俗称的Activity栈,它由自己的id、名字(affinity)以及它属于哪个ActivityStack管理等等信息
运行在AMS服务端进程,它是一个更大的Activity栈,它管理了许多TaskRecord,在8.1.0源码中,一个系统只有固定大约7个ActivityStack栈,如HomeStack也就是Luncher的管理栈、全屏栈、窗口可调整大小的栈、占用屏幕专用区域栈(DOCKED_STACK)、始终存在顶部的栈等,这些栈的分类可以在ActivityManager的内部类StackId中查询到;
9.0系统发现这个ActivityStack可以超过7个,adb dumpsys可以查看到stackid会大于7,不知道是不是9.0代码修改了,知道的评论区留言下
ArrayList mTaskHistor 存储了许多TaskRecord,管理了Activity栈
ActivityRecord mPausingActivity 当前栈中暂停的Activity
ActivityRecord mLastPausedActivity
ActivityRecord mResumedActivity 正在运行的Activity
int mDisplayId 唯一标识,与本ActivityStack匹配
ActivityStack的管理者,管理了系统中所有的ActivityStack;
SparseArray
ActivityStack mHomeStack; Launcher的栈
ActivityStack mFocusedStack; 当前获取焦点的栈
ActivityStack mLastFocusedStack; 上一个获取焦点的栈
除此之外,还有很多ActivityRecord的集合,如mStoppingActivities、mFinishingActivities和mGoingToSleepActivities等等
Binder跨进程的服务端,面向外部提供一系列的接口,主要是负责接收外部调用,预处理部分数据,真正的执行逻辑是交给ActivityStarter去处理
真正的业务处理类,它会组织以上所有的类进行业务调用、处理等
客户端进程的入口类,入口方法为main方法;startActivity时,AMS判断启动目标Activity还没有进程,会以LocalSocket方法向zygote孵化器发起创建进程请求,zygote根据自身创建好进程后,会议ActivityThread的main作为入口开始执行,这样一个App进程就开始执行了
在ActivityThread内部有一个内部类ApplicationThread,它是一个IApplicationThread.Stub类型,也就是一个Binder类,在上诉main方法中,会调用AMS的attachApplication将这个ActivityThread绑定到ProcessRecord上去,这样客户端和服务端App都对应匹配上了
Activity生命周期类负责的类,四大组件的生命周期几乎都是由它来控制的
我们的类class从哪里来,肯定是由classLoader来加载,那classLoader又从系统中哪个位置去加载出来呢?这一些列的操作都是由它来控制
如上如所示,列举了部分包含依赖关系组织架构,其中ActivityRecord与Activity对应,主要是根据appToken对应的,appToken是一个IApplicationToken.Stub类型;一般来说,客户端通过Intent意图启动Activity,AMS拿到Intent意图后会创建ActivityRecord记录此次Activity,其构造方法自动实例化成员变量appToken,服务端完成相应逻辑后会将ActivityInfo(记录Activity的载体类)和appToken传递给客户端,客户端获取到ActivityInfo会将其重要信息提取到ActivityClientRecord中去,同时classLoader加载到class类并保存到其中,最后将appToken和ActivityClientRecord保存到ActivityThread的成员ArrayMap
ProcessRecord是保存一个进程状态的类,这个进程一般来说是App客户端进程,他们之间是如何建立起对应关系的?大概是这样一个流程:
startActivity时,AMS发现这个Activity还没有自己的App进程,会通知zygote孵化器孵化一个App进程,并创建一个ProcessRecord,其保存了zygote返回给AMS的pid,这个pid就是客户端App的pid,App客户端进程启动后,会以ActivityThread的main作为入口点执行,执行过程中,会跨进程Binder调用AMS的attachApplication(IApplicationThread.Stub)方法,AMS此时就会从自己保存的ProcessRecord列表中找到pid与App进程的pid相同的,找到后并设置App进程的回调接口到ProcessRecord中,也就是attachApplication传递过来的参数IApplicationThread.Stub,这样就建立好对应回调关系了
以上只是列举了AMS各个模块之间的包含关系,还需要一个完整的业务线将他们组织起来,这里就以在桌面Launcher上点击图标启动app为例开始阐述业务逻辑,先来一个流程图:
startActivity执行逻辑大体如上图,标红的方法是逻辑当中比较关键性的地方,执行逻辑有分叉,走向不同的逻辑,整个业务逻辑可以大致分为几个业务线:
假设我们在桌面Launcher上点击一个App图标,并且这个app从未运行过,它会按照上图Launcher执行,需要注意的是Launcher不在是调用自己Instrumentation来startActivity,而是会调用一个系统服务LauncherAppsService来发起启动,再由他与AMS发起调用,这样就走到AMS的业务逻辑
ActivityStarter相当于startActivity前期预处理逻辑,因为传递过来的Activity实质是一个Intent意图,所以其主要的工作内容:
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
launcher启动 inTask-null sourceRecord-null voiceSession-null mStartActivity - r
以下函数主要是设置本类ActivityStarter的成员变量为参数值
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
检查lunchMode启动模式以及配置到mLaunchFlags
computeLaunchingTaskFlags();
计算源的ActivityStack
computeSourceStack();
将配置的flag配置到Intent上去
mIntent.setFlags(mLaunchFlags);
找到现存的任务TaskRecord,把当前Activity添加进去,返回null则表示没有找到可以添加的任务
ActivityRecord reusedActivity = getReusableIntentActivity();
....省略后面逻辑....
}
为mStartActivity查找一个现存任务站TaskRecord,然后将mStartActivity插入进栈
private ActivityRecord getReusableIntentActivity() {
当Lunchmode为singTask和singInstance或者flags为New_TASK标志时,才可以去根据Activity去查找Stack,进行复用stack
就是对集中标志的理解
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {
if (mLaunchSingleInstance) {
info就是ActivityInfo
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
!mLaunchSingleTask);
} else {
根据intent去每个TaskRecord的启动意图Intent比较,否则就根据taskAffinity相比较,先比较前者,前者说明Activity已存在,后者说明在同一个任务栈里面
intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
}
}
intentActivity有可能为null,那就需要创建一个新的任务栈TaskRecord
return intentActivity;
}
getReusableIntentActivity方法和我们配置taskAffinity相关,就是任务栈的亲和属性,我们都知道,不配置这个属性,Activity会默认加入到包名相同的任务栈TaskRecord中去,当我们配置taskAffinity=“xxx”时,会将Activity加入到名字为xxx的栈里面去,但是记住,从源码中可以看到,必须该Activity的为mLaunchSingleInstance || mLaunchSingleTask才会进入else if条件,mSupervisor.findTaskLocked和findActivityLocked才会去查找相应的栈,最后这个函数返回是null,说明没有为这个Activity找到合适任务栈,就需要重新创建TaskRecord;
接上面startActivityUnchecked剩余的函数部分:
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
....
找到现存的任务TaskRecord,把当前Activity添加进去,返回null则表示没有找到可以添加的任务
ActivityRecord reusedActivity = getReusableIntentActivity();
if (reusedActivity != null) {
如果找到的reusedActivity不为空,说明为此次启动的mStartActivity找到了合适的任务栈
if (mStartActivity.getTask() == null) {
mStartActivity.setTask(reusedActivity.getTask());
}
if (reusedActivity.getTask().intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
reusedActivity.getTask().setIntent(mStartActivity);
}
如果启动flag是FLAG_ACTIVITY_CLEAR_TOP,那就要注意了
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask) {
final TaskRecord task = reusedActivity.getTask();
移除mStartActivity之上的Activity,根据mLaunchFlags确定是否要移除mStartActivity,具体细节
可自行跟入performClearTaskForReuseLocked进去看
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
....
}
}
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
创建一个新的Task来启动我们的目标ActivityStack和TaskRecord,并且将创建的Stack赋值给成员mTargetStack
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
启动Activity 协调组织windowmanager布置转场布局动画等
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
mDoResume传进来的参数赋值的,为true
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
在上面创建Stack的时候,会将mTargetStart设置为获取焦点Focus
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
进入else
} else {
isFocusable是否可获取焦点 当然可以返回true mTargetStack是否已经是FocusedStack获取焦点状态的栈,显然还不是 才刚刚创建
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
将mTargetStack设置为获取焦点状态
mTargetStack.moveToFront("startActivityUnchecked");
}
执行到这里,为此次启动的Activity检查好了权限、Activity启动配置信息、ActivityStack以及TaskRecord任务栈等信息,需要为我们真正启动Activity做准备了
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
preferredLaunchDisplayId, mTargetStack.mStackId);
return START_SUCCESS;
}
部分细节可查看上面的代码注释,这里在重点分析setTaskFromReuseOrCreateNewTask创建任务栈逻辑,如下:
private int setTaskFromReuseOrCreateNewTask(
TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
创建一个新的ActivityStack
mTargetStack = computeStackFocus(
mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
if (mReuseTask == null) {
创建新的TaskRecord栈
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
将mStartActivity添加到task中去
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
if (mLaunchBounds != null) {
final int stackId = mTargetStack.mStackId;
if (StackId.resizeStackWithLaunchBounds(stackId)) {
mService.resizeStack(
stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
} else {
mStartActivity.getTask().updateOverrideConfiguration(mLaunchBounds);
}
}
.........
if (!mMovedOtherTask) {
updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags,
preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
}
mDoResume为true,进入if
if (mDoResume) {
此步骤会让mTargetStack成为获取焦点状态
mTargetStack.moveToFront("reuseOrNewTask");
}
return START_SUCCESS;
}
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
int launchFlags, ActivityOptions aOptions) {
........
if (stack == null) {
首先会尝试获取一个DynamicStack,动态Stack,是根据ID来确定的,ID>=0即可
final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
if (isDynamicStack(stack.mStackId)) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Setting focused stack=" + stack);
return stack;
}
}
找不到合适的,就需要创建一个新的了,重点关注这里的StackId只有以下几种确定的可能
final int stackId = task != null ? task.getLaunchStackId() :
bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
FULLSCREEN_WORKSPACE_STACK_ID;
这里就去根据stackId去创建,由于stackId上局代码确定了几种可能,那说明这个创建后的stack的数量
就是固定的,也就是整个Android系统的ActivityStack数量是固定的
stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ r + " stackId=" + stack.mStackId);
return stack;
}
由于本源码是Android 8.1.0上查看的,说明在系统上ActivityStack是固定的,可以使用
adb shell dumpsys activity activities
来查看栈信息,确实是固定的,但是Android9.0就不同了,整个系统对于ActivityStack数量没有限制,可以有很多,不知为何要做这种修改,是为了分屏同时进行吗?知道的可在评论区留言
继续startActivityUnchecked,后面会依次走到ActivityStack的resumeTopActivityInnerLocked方法
在resumeTopActivityInnerLocked中,业务可能会发生变化,走向两条不同的逻辑,但是最终又会走回到此方法;
逻辑1:其他Activity还在pause中,没有pause完成,就需要先去暂停其他Activity,当其他Activity都pause完成,最后又经过一些列逻辑走回到resumeTopActivityInnerLocked
逻辑2:当所有Activity都pause完成了,就可以继续往下执行,启动我们的目标Activity了
所以,这里经常有面试官会问你,A启动B,A的onPause和B的onCreate谁先执行啊?
看代码把!
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
AMS还没启动完成
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
return false;
}
获取下一个正在执行的Activity,因为在创建TaskRecord将即将要启动的ActivityRecord已经添加进去了
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
因为马上要启动Activity了,暂停所有的Activity初始化工作
mStackSupervisor.cancelInitializingActivities();
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
if (!hasRunningActivity) {
// There are no activities left in the stack, let's look somewhere else.
return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
}
如果当前Stack的ResumeActivity就是next就啥也不做了,传递参数即可;
意思就是启动的Activity已经在栈顶且运行中
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Top activity resumed " + next);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
必须要等待ActivityStack的mPausingActivity处于Pause状态才能继续执行
如果没有pause成功就返回,不在继续往下执行,不用担心,当其他暂停成功后会有另外一条业务逻辑发起此函数的调用,进而执行我们的Activity
if (!mStackSupervisor.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
暂停其他堆栈的Activity
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
暂停上一个resume状态的Activity
pausing |= startPausingLocked(userLeaving, false, next, false);
}
暂停中情况说明还没暂停完成,不在往下执行,pausing上个函数返回为true
if (pausing && !resumeWhilePausing) {
......
return true;
} else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
....
return true;
}
.......
在以上代码中,逻辑1会从pauseBackStacks这里出发,会暂停其他ActivityStack中的mResumedActivity,这个mResumedActivity就是当前正在运行的Activity,如下:
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
每个ActivityStack都是以DisplayId匹配,并存储在mActivityDisplays成员
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
遍历所有的ActivityStack列表
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
如果此Stack没有获取焦点,并且有正在运行Activity -- mResumedActivity
if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
那就去暂停他把!dontWait是否立即返回还是等待
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
}
return someActivityPaused;
}
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
ActivityRecord prev = mResumedActivity;
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
.......
跨进程调用使上一个Activity暂停Pause,pause完成后会调用回到AMS,逻辑流程查看上面的流程图
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, pauseImmediately);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
if (mPausingActivity != null) {
.......
pauseImmediately传递进来为false
if (pauseImmediately) {
completePauseLocked(false, resuming);
return false;
走此逻辑,并返回为true,会回到resumeTopActivityInnerLocked中去,而
resumeTopActivityInnerLocked的if条件发现是true又会走上面流程图1的逻辑
} else {
发送pause time out消息,防止pause客户端Activity时间过程,当客户端pause完成后,会
跨进程返回到AMS,取消掉这个timeout消息
schedulePauseTimeout(prev);
return true;
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (resuming == null) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
}
至此,Activity正常启动流程将中止了,暂停逻辑也会走到App客户端进程去,当App客户端pause完成后,会调用跨进程调用AMS的activityPaused方法,进而在此走回到resumeTopActivityInnerLocked方法;流程查看上面图片,就不在继续阐述
我们继续沿着resumeTopActivityInnerLocked的后续启动流程查看:
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
........
业务逻辑走到这里,必须所有其他Activity都pause完成
如果即将启动的App进程存在,就直接执行
if (next.app != null && next.app.thread != null) {
next.sleeping = false;
mService.showUnsupportedZoomDialogIfNeededLocked(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
真正resumeActivity的步骤,记住这里只是resume,并没有oncreate onstart
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
}else {
真正执行启动Activity会走此逻辑,新App进程不存在
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null /* prev */, false /* newTask */,
false /* taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
以下函数会是真正执行Activity启动
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
}
next为即将启动的ActivityRecord,由于此时next的进程还没有,所以会走到else执行startSpecificActivityLocked方法!
在startSpecificActivityLocked方法中,会判断是否存在App客户端进程,如果有就直接启动,没有我们就去创建:
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
根据进程名去AMS和uid里面查找进程记录
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
App进程存在直接执行
if (app != null && app.thread != null) {
try {
.....
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
开始启动进程信息,这个函数里面会创建进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
startProcessLocked是一个重载函数,会进行多次调用,大致会先创建ProcessRecord类,然后创建App进程,创建进程成功后会返回新进程的pid,将其保存到ProcessRecord,并且AMS将这个pid和ProcessRecord匹配保存到map数据模型中去;看看关键核心代码把:
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
......
如果入口点为null,则就默认启动类为ActivityThread
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
ProcessStartResult startResult;
启动类型为web_service
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
启动类型为Activity,Process内部会以localsocket方式连接上zygote,并返回启动结果
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
......
synchronized (mPidsSelfLocked) {
pid是通过zygote进程孵化出来的客户端进程pid,pid和客户端的App保存在SparessArray中
this.mPidsSelfLocked.put(startResult.pid, app);
这里是为true,实质是要求新创建的进程及时attach到AMS上,再删除这个消息;防止启动的进程异常
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
........
}
到这里,App客户端进程创建好了,startActivity也算是执行完了!但是我们的Activity都还没启动,咋回事?
这是因为App进程启动完后,App进程跨进程调用AMS的attachApplication方法,在启动我们的Activity,因为Activity已经配置到ActivityStack和TaskRecord即将启动项,处于Focus获取焦点状态,其他的Activity也都暂停完成了;这里,可以说是万事俱备,只欠东风了!
需要注意的是,其一Process与孵化进程zygote是以LocalSocket方式交互的,其二App进程入口类ActivityThread
由于此时主动权已经在App进程的ActivityThread这边了,所以我们看看它的启动main方法,main方法中主要工作就是:
最后,还有一个关键的地方,就是attach:
public static void main(String[] args) {
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"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
}
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
........
RuntimeInit.setApplicationObject(mAppThread.asBinder());
ActivityManagerService的客户端
final IActivityManager mgr = ActivityManager.getService();
try {
把mAppThread设置到ActivityManagerService端去了
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
.....
}
上面代码很清楚了,mgr.attachApplication(mAppThread)就将回调设置到AMS,走到AMS的逻辑了,后续流程看看上面流程图就知道了,我们重点关注一下attachApplicationLocked方法
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
mPidSelfLocked保存了客户端进程号对应的ProcessRecord进程记录信息
在上面创建进程的时候保存过,这里取出来
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
makeActive实质就是将app.thread = thread
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
app.killed = false;
这里取消我们之前在创建App进程的超时消息,这种发送handler消息就是Android内部防止超时机制
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
发起App客户端进程的Application onCreate事件调用,因为这个App进程才启动,要先启动Application
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
if (normalMode) {
try {
又会走到ActivityStackSupervisor中,启动我们即将启动Activity
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
这里,我们直接去看realStartActivityLocked方法逻辑把!
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
......
app.hasShownUi = true;
app.pendingUiClean = true;
app.forceProcessStateUpTo(mService.mTopProcessState);
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
启动APP进程的Launch事件,就是onCreate,Activity还没执行onStart/onResume,为什么???
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
.......
}
因为只执行onCreate事件,还没有执行onStart和onResume事件,搞不明白?我们去app进程看看:
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,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
new一个ActivityClientRecord
ActivityClientRecord r = new ActivityClientRecord();
.....
赋值
r.token = token;
r.startsNotResumed = notResumed;
.....
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity执行时,还不是App的主线程,通过发送Handler消息会回到主线程中去,最终会走到handleLaunchActivity进行启动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();
}
handleConfigurationChanged(null, null);
WindowManagerGlobal.initialize();
执行classLoader加载类并且执行onCreate,这里就不继续跟进去了
执行完成后,会将ActivityClientRecord保存到mActivities成员map中去
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
这里执行onStart/onResume事件
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}else{
.....
}
到这里就算真正启动完成了
AMS模块是四大组件的核心模块,要了解模块由哪些组成,并了解其贯通运行逻辑!这里重点掌握启动模式以及FLAG,任务栈和Activity栈这些属性,启动时,Activity依据什么样的条件去归属到对应的栈中!
还有多参考这种耦合式设计,将重要的参数检查、权限等核心工作放在一个进程,启动目标放到另一个进程,这样即使目标进程奔溃,也不影响核心工作进程!
相关注释源码下载地址不去CSDN了,本来设置免费的,它自己修改了分数,在百度网盘下载:
链接:https://pan.baidu.com/s/1A2GubiC1jM-V5d-slfyDnA 密码:pigx