Android 应用启动源码分析 9.0

前言

本文主要分析当用户点击 Launcher 上的应用图标,到启动应用程序首个页面的流程。本文基于 Android 9.0 ,结论由调试编译后模拟器得出,aosp 分支 android-9.0.0_r1。

分析源码前,先提出几个问题,带着疑问去看代码

  1. 应用启动时显示的白屏究竟是什么,如何禁止显示?
  2. 应用程序进程是如何创建的,创建完做了什么?
  3. 系统管理 Activity 栈涉及的数据结构有哪些?
  4. 应用崩溃后,为什么会打印导致崩溃的错误日志?
  5. 调试应用时,为什么会出现等待提示框,这个框是如何弹出的?
  6. 在系统设置中设置代理,为什么应用就会走这个代理?
  7. 免初始化的 SDK 究竟是如何做到的?
  8. 为什么应用不会退出,不应该方法执行完就退出?
  9. 应用在后台时点击应用图标,为什么不会再次启动首页?
  10. 为什么 onCreate、onStart、onResume 都获取不到 View 的宽高?

整体分为以下两个流程

  1. 用户点击 Launcher 图标到应用程序进行创建前
  2. 应用程序进程创建后到首个 Activity 展示出来

源码分析

应用程序进程创建前

LauncherAMS

桌面对应 Launcher3 这个应用程序,其源码位于 /packages/apps/Launcher3。当点击桌面上的图标时会触发ItemClickHandler#onClick。

// ItemClickHandler.java
private static void onClick(View v) {
// Launcher为桌面主Activity
Launcher launcher = Launcher.getLauncher(v.getContext());
Object tag = v.getTag();
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
}
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
Intent intent = item.getIntent();
launcher.startActivitySafely(v, intent, item);
}
// Launcher.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
// Launcher 的基类是 BaseDraggingActivity
boolean success = super.startActivitySafely(v, intent, item);
if (success && v instanceof BubbleTextView) {
// 图标显示点击后的样式,再次回到桌面后恢复
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
setOnResumeCallback(btv);
}
return success;
}
// BaseDraggingActivity.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation
? getActivityLaunchOptionsAsBundle(v)
: null;
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent, optsBundle);
return true;
}

接下来就是标准的启动 Activity 流程,不过上述代码的 Intent 的是在哪创建的呢?还得回到 AppInfo 的构造方法。

// AppInfo.java
public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
this.componentName = info.getComponentName();
this.user = user;
intent = makeLaunchIntent(info);
}
public static Intent makeLaunchIntent(ComponentName cn) {
return new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setComponent(cn)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}

这里设置了 action 为 android.intent.action.MAIN、category 为 android.intent.category.LAUNCHER,同时指定了要启动的 component(首个 Activity 的包名其全类名),*这也就解释了为什么应用程序的首个 Activity 必须要设置这个 action 以及 category。***

同时添加了 Intent.FLAG_ACTIVITY_NEW_TASK 这个 Flag,表示开启的 Activity 在一个新的任务栈中运行,不要和 Launcher 运行在同一个任务栈中,接下来分析 startActivity 的具体流程。

// Activity.java
public void startActivity(Intent intent, @Nullable Bundle options) {
startActivityForResult(intent, -1, options);
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
}

通过 Instrumentation 去启动 Activity,这个类主要用于监控应用程序和系统的交互,Application、Activity 实例创建以及 Activity 生命周期调用都是通过该类完成的,VirtualApk 也是通过 Hook 该类实现插件化的。

// Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
try {
int result = ActivityManager.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;
}
// ActivityManager.java
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};

IApplicationThread 是一个 aidl 文件,ActivityThread.ApplicationThread 继承了 IApplication.Stub,客户端将该对象传递给系统服务进程,系统服务进程就可以通过该 BinderProxy 对象跨进程调用应用程序对应方法。

IActivityManager 也是一个 aidl 文件,AMS 继承了 IActivityManager.Stub ,在系统服务进程启动的时候会向 ServiceManager 注册服务,包括 AMS,客户端通过 ActivityManager.gerService 获取到一个 AMS 的 BinderProxy 对象,从而跨进程调用 AMS 对应方法。

注:这里已经说明了应用程序进程与系统服务进程(AMS)的通信方式,IApplicationThread 用于系统服务进程与应用程序进程通信(注意 AIDL 中标明了 oneway 表明为非阻塞式调用,这也合理,不然应用程序就能把服务进程卡死),IActivityManager 用于应用程序进程与系统服务进程通信(非 oneway 调用表明为阻塞式调用)。

源码目录:

framework/base/core/java/android/app/IApplicationThread.aidl

framework/base/core/java/android/app/IActivityManager.aidl

AMS.startActivity

接下来执行的 ActivityManagerService#startActivity。注: AMS 运行在 SystemServer 进程。

// ActivityManagerService.java
public final int startActivity(...) {
return startActivityAsUser(...);
}
public final int startActivityAsUser(...) {
return mActivityStartController.obtainStarter(intent, "startActivityAsUser").execute();
}
// ActivityStarterController.java
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
// ActivityStarter.java
public ActivityStarter obtain() {
ActivityStarter starter = mStarterPool.acquire();
if (starter == null) {
starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
}
return starter;
}

AST.execute

接下来就运行到了 ActivityStarter#execute。

// ActivityStarter.java
int execute() {
return startActivityMayWait(...);
}
private int startActivityMayWait(...) {
// 调用 PMS 查询 Intent 所指定的 ResolveInfo
ResolveInfo rInfo = mSupervisor.resolveIntent(...);
// 从 ResolveInfo 中取出 ActivityInfo,并且给 Intent 明确指定 Component
ActivityInfo aInfo = mSupervisor.resolveActivity(...);
synchronized (mService) {
final ActivityStack stack = mSupervisor.mFocusedStack;
final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivity(...);
return res;
}
}
ASS.resolveIntent

该方法主要调用 PMS 查询 Intent 所指定的 Activity 信息。

// ActivityStackSupervisor.java
ResolveInfo resolveIntent(...) {
// 这里由于是同进程所以不需要再通过Binder调用
return mService.getPackageManagerInternalLocked().resolveIntent(...);
}
// PackageManagerInternalImpl.java
public ResolveInfo resolveIntent(...) {
return resolveIntentInternal(...);
}
// PackageManagerService.java
private ResolveInfo resolveIntentInternal(...) {
List<ResolveInfo> query = queryIntentActivitiesInternal(...);
// 选择最佳的,根据优先级判断,如果优先级相同并且没有设置偏爱,那么会返回一个特殊的 ResolveInfo,让用户选择,不过对于 Launcher 启动一定只有一个选择
ResolveInfo bestChoice = chooseBestActivity(...);
return bestChoice;
}
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(...) {
if (comp != null) {
List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
// 查询到目标 Activity 信息,Launcher 启动的必然能找到返回
ActivityInfo ai = getActivityInfo(comp, flags, userId);
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
return list;
}
// 隐式启动部分
...
}

方法内部逻辑如下:

  1. 首先从 PMS ( PMS 在应用启动时就会去解析所有系统 App 以及所有三方 App的清单文件,将所有 Activity 信息保持到其成员变量 mActivity 中),查询满足所有满足条件的 Activity 。
  2. 接着选择一个最佳的,如果有多个那么会返回一个特殊的 ResolveInfo 让用户选择打开哪个,不过对于 Launcher 启动而言一般也就一个。
ASS.resolveActivity

该方法根据 ResolveInfo 来获取启动 Activity 信息。

ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
ProfilerInfo profilerInfo) {
final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
}
return aInfo;
}

这里也就是明确指定了将要启动的组件信息。

AST.startActivity

继续看启动流程。

// ActivityStarter.java
private int startActivity(...) {
mLastStartActivityResult = startActivity(...);
return getExternalResult(mLastStartActivityResult);
}
private int startActivity(...) {
int err = ActivityManager.START_SUCCESS;
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// PMS 查询不到能处理该隐式启动的 Activity 返回错误
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// PMS 查询不到能处理该显示启动的 Activity 返回错误,一般是没注册
err = ActivityManager.START_CLASS_NOT_FOUND;
}
if (err != START_SUCCESS) {
// 告知应用程序启动失败
return err;
}
// 进行权限校验,有些 Activity 明确指定了权限
boolean abort = !mSupervisor.checkStartAnyActivityPermission(...);
// 检查 Intent 传递的数据是否与 IntentFilter 指定的 MIME type 和 URI 一致
abort |= !mService.mIntentFirewall.checkStartActivity(...);
// 如果目标 Activity 处于未响应状态或者是有害的 App 或者处于安静模式就会被拦截掉
if (mInterceptor.intercept(...)) {
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
callingUid = mInterceptor.mCallingUid;
checkedOptions = mInterceptor.mActivityOptions;
}
if (abort) {
return START_ABORTED;
}
ActivityRecord r = new ActivityRecord(...);
return startActivity(...);
}

上述一段代码主要进行了显示、隐式启动校验,权限校验,判断是否拦截,接着往下看。

// ActivityStarter.java
private int startActivity(...) {
result = startActivityUnchecked(...);
postStartActivityProcessing(r, result, mTargetStack);
return result;
}
private int startActivityUnchecked(...) {
// 重置并且设置 ActivityRecord、Intent、TaskRecord 和 LaunchFlags
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// 计算出 LaunchFlag ,如果是 SingleTask 或者 SingleInstance 都会添加 Intent.FLAG_NEW_TASK
computeLaunchingTaskFlags();
mIntent.setFlags(mLaunchFlags);
// 判断是否需要将新启动的 Activity 应该放到已经存在的 Task 中去
ActivityRecord reusedActivity = getReusableIntentActivity();
if (reusedActivity != null) {
// 放到已存在 Task 中的情况,Launcher 启动的 Activity 不会进入,先忽略
}
// 获取当前位于前台栈顶的 Activity,判断待启动 Activity 是否与之相同,如相同并且 LaunchMode 是 singleTop
// 或者目标 Activity 清单文件中注册为 singleTop 或 singleTask 都不新启动 Activity
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord topFocused = topStack.getTopActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
if (dontStart) {
// 不启动 Activity,Launcher 启动的 Activity 不会进入,先忽略
}
boolean newTask = false;
int result = START_SUCCESS;
// 创建新的 TaskRecord (Activity 栈)
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
}
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
...
return START_SUCCESS;
}

方法内部逻辑如下:

  1. 首先为 SingleTask 以及 SingleInstance 两种启动模式添加了 Intent.FLAG_NEW_TASK 标记。
  2. 接着判断当前将要启动的 Activity 是否放到已经存在的 Task 中去,Launcher 冷启动应用不会进入,先忽略。
  3. 接着处理 SingleTop 以及 SingleTask,由于这两种启动当栈顶已经是该 Activity 实例时不会重新启动。
  4. 接着创建新的 ActivityStack 以及 TaskRecord 用于存放当前新启动的 Activity。
  5. 接着调用 ActivityStack. startActivityLocked 启动 Activity,对于新启动的栈,只有可能会启动 StartingWindow。
  6. 最后调用 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked 真正启动当前 Activity。

注:AMS 管理 Activity 主要通过以下四个数据结构,我们经常说的 Activity,其实是 TaskRecord,而不是 ActivityStack,ActivityStack 存在的目的应该是为了方便栈前后台切换。

  1. ActivityDisplay 表示的是显示设备,一般也就一个实例。
  2. ActivityStack 用于管理多个 TaskRecord,主要作用是方便任务栈前后台切换。
  3. TaskRecord 表示一个 Activity 栈,管理当前栈中所有的 Activity。
  4. ActivityRecord 表示一个 Activity 记录。

一个 ActivityDisplay 包含多个 ActivityStack

一个 ActivityStack 包含多个 TaskRecord

一个 TaskRecord 包含多个 ActivityRecord

一个 ActivityRecord 唯一标识一个 Activity

AS.startActivityLocked

调用 ActivityStack 启动 Activity。

void startActivityLocked(...) {
TaskRecord rTask = r.getTask();
final int taskId = rTask.taskId;
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
insertTaskAtTop(rTask, r); // 将 TaskRecord 放到 ActivityStack 栈顶
}
if (!newTask) {
// 非新创建 TaskRecord 的情况,忽略
}
// 设置当前 TaskRecord 为前台栈
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
if (r.mLaunchTaskBehind) {
// 后台运行的情况(什么情况会出现?ActivityOptions.getLaunchTaskBehind)
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) { // 应用冷启动 doShow 一定是 true
// 展示 StartingWindow 也就是预览窗口,也就是所谓的白屏
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
}
}

方法内部逻辑如下:

  1. 将待启动的 Activity 对应的 TaskRecord 放到 ActivityStack 栈顶,并设置其为前台栈。
  2. 展示 StartingWindow 也就是预览窗口,也就是所谓的白屏。
AR.showStartingWindow

看看预览窗口显示逻辑,以及如何禁止它。

// ActivityRecord.java
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean fromRecents) {
final boolean shown = mWindowContainerController.addStartingWindow(...);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
public boolean addStartingWindow(...) {
synchronized(mWindowMap) { // mWindowMap 里面包含了状态栏等这些由系统控制的窗口
if (theme != 0) {
AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, com.android.internal.R.styleable.Window, mService.mCurrentUserId);
final boolean windowIsTranslucent = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsTranslucent, false);
final boolean windowIsFloating = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false);
final boolean windowDisableStarting = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowDisablePreview, false);
if (windowIsTranslucent) {
return false;
}
if (windowIsFloating || windowDisableStarting) {
return false;
}
}
mContainer.startingData = new SplashScreenStartingData(...);
scheduleAddStartingWindow();
return true;
}
private final Runnable mAddStartingWindow = new Runnable() {
public void run() {
StartingSurface surface = startingData.createStartingSurface(container);;
}
};
void scheduleAddStartingWindow() {
mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}

可以看到预览窗口添加的操作是通过 postAtFrontOfQueue 添加到消息队列中的,因此要到本条消息执行完后才会执行,接着看看 mAddStartingWindow 到底做了些什么。

StartingSurface createStartingSurface(AppWindowToken atoken) {
return mService.mPolicy.addSplashScreen(....);
}
public StartingSurface addSplashScreen(...) {
WindowManager wm = null;
View view = null;
try {
final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
win.setTitle(label, true);
win.setType(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
win.setFlags(...); // 设置一堆 flag
win.setDefaultIcon(icon);
win.setDefaultLogo(logo);
win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
final WindowManager.LayoutParams params = win.getAttributes();
params.token = appToken;
params.packageName = packageName;
params.windowAnimations = win.getWindowStyle().getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
addSplashscreenContent(win, context);
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
wm.addView(view, params);
return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
} finally {
...
}
return null;
}
private void addSplashscreenContent(PhoneWindow win, Context ctx) {
final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
final int resId = a.getResourceId(R.styleable.Window_windowSplashscreenContent, 0);
a.recycle();
if (resId == 0) {
return;
}
final Drawable drawable = ctx.getDrawable(resId);
if (drawable == null) {
return;
}
final View v = new View(ctx);
v.setBackground(drawable);
win.setContentView(v);
}

添加预览窗口的逻辑已经看完了,本质上就是往 WMS 上添加了一个 View,默认该 View 为空白的, 不过可以通过设置 windowSplashscreenContent 来改变其背景颜色,注意 windowBackground 也可以但是会对 Activity 也有影响,如果需要禁止显示,那么可以通过以下设置

android:windowIsTranslucent // 设置为 true
android:windowDisablePreview // 设置为 true
android:windowIsFloating // 设置为 true 也可以,但是会对 Activity 有影响

ASS.resumeFocusedStackTopActivityLocked

调用 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked 来真正的启动 Activity。

// ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(...) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
}
// ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
return resumeTopActivityInnerLocked(prev, options);;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false); // 将还处在 resume 状态的 Activity 全部 pause
if (pausing && !resumeWhilePausing) {
return true;
}
}
ASS.pauseBackStacks

调用 ActivityStackSupervisor.pauseBackStacks 来调用启动当前 Activity 的 Activity 的 onPause 方法。

boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
boolean someActivityPaused = false;
// 遍历所有 ActivityStack,寻找到还处于 Resume 状态的 ActivityStack,这里 Launcher 所在的 ActivityStack 就还存在 onResume 状态的 Activity。
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
if (!isFocusedStack(stack) && stack.getResumedActivity() != null) {
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
}
return someActivityPaused;
}
// ActvityStack.java
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
ActivityRecord prev = mResumedActivity; // 取到正处于 onResume 状态的 Activity
prev.setState(PAUSING, "startPausingLocked"); // 将正处于 onResume 状态的 Activity 状态修改为 PAUSING 表示正在暂停,等应用程序处理完毕后就变成了 PAUSED
mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(...));
if (mPausingActivity != null) {
if (pauseImmediately) { // 调用者不想等待 onPause 完成的情况
completePauseLocked(false, resuming);
return false;
} else {
// Launcher 启动走这条分支,这里会 post 一个 msg,500 毫秒后执行,一旦执行表示上个 Activity 的 onPause 超时
prev.schedulePauseTimeout();
return true;
}
}
}
// ActivityRecord
void schedulePauseTimeout() {
mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT); // 延时 500 毫秒操作
}

方法内部逻辑如下:

  1. 调用了 Launcher 应用程序的 ApplicationThread.scheduleTransaction 方法,这个方法只是发了个信息等待 系统服务进程处理完毕后执行。
  2. 发送一个延时 500 毫秒执行的消息,这个延时是给上个 Activity 调用 onPause 的实际,等到 500 毫秒到了,如果还没完成,那么就不再进行等待。如果启动 Activity 与待启动 Activity 位于同一个进程,那么启动 Activity 的 onPause 会阻塞待启动的 Activity 启动(由于当前进程的主线程被阻塞了),如果两者位于不同进程那么启动 Activity 的 onPause 最多阻塞 500 毫秒待启动的 Activity 。

注:以下代码是 Android 9.0 服务进程与应用程序进程通信的新方式(在这以前都是明确调用 IApplicationThread 的指定方),最终会按序执行 PauseActivityItem 的 preExecute、execute、postExecute 方法。

mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(...));

稍后系统的 startActivity 流程结束后,Launcher 应用程序就可以脱离阻塞来执行 PauseActivityItem 的 preExecute、execute、postExecute 方法

// PauseActivityItem.java
default void preExecute(ClientTransactionHandler client, IBinder token) {}
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
client.handlePauseActivity(...); // mClient 对应 ActivityThread
}
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
ActivityManager.getService().activityPaused(token); // 告知 AMS onPause 已经完成
}
// ActivityThread.java
public void handlePauseActivity(...) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
performPauseActivity(r, finished, reason, pendingActions);
}
}
private Bundle performPauseActivity(...) {
performPauseActivityIfNeeded(r, reason);
}
private void performPauseActivityIfNeeded(...) {
mInstrumentation.callActivityOnPause(r.activity);
}
// Instrumentation.java
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
// Activity.java
final void performPause() {
onPause();
}

onPause 调用流程已经理清楚了,现在还存在两条分支,一条是 Launcher 在 500 毫秒内完成了 onPause 操作,并通知了 AMS,另一条是 Launcher 没有在 500 毫秒内通知 AMS 完成。

// 第一种情况,未超时
// ActivityManagerService
public final void activityPaused(IBinder token) {
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
}
// 第二种情况,超时
// ActivityStack
public void handleMessage(Message msg) {
switch (msg.what) {
case PAUSE_TIMEOUT_MSG: {
ActivityRecord r = (ActivityRecord)msg.obj;
synchronized (mService) {
activityPausedLocked(r.appToken, true);
}
} break;
}
}

可以看到超不超时,都会调用 ActivityStack.activityPausedLocked 区别在于第二个参数,不超时为 false,超时为 true(其实这个参数之和日志打印有关,可以忽略),因此只要看这个方法就行。

// ActivityStack.java
final void activityPausedLocked(IBinder token, boolean timeout) {
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); // 移除超时消息
if (mPausingActivity == r) {
completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
}
}
}
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
prev.setState(PAUSED, "completePausedLocked"); // 设置刚刚完成 onPause 的 Activity 状态为 PAUSED
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
}
// ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(...) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
}
// ActivityStack.java
boolean resumeTopActivityUncheckedLocked(...) {
return resumeTopActivityInnerLocked(prev, options);
}
private boolean resumeTopActivityInnerLocked(...) {
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false); // 这次由于没有 Activity 还处于 Resume 状态,因此 pausing 为 false,也就不会返回了
if (pausing && !resumeWhilePausing) {
return true;
}
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}

可以绕了一大圈最终其实又回到了 ActivityStack.resumeTopActivityInnerLocked 方法,不过这次由于不存在 Resume 状态的 Activity 因此逻辑改变了,最终调用 ActivityStackSupervisor.startSpecificActivityLocked 方法。

ASS.startSpecificActivityLocked

startSpecificActivityLocked 应该要启动进程了。

// ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// 获取不到该进程信息
ProcessRecord app = mService.getProcessRecordLocked(...);
if (app != null && app.thread != null) { // 进程已经存在的情况
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}
// 让 AMS 开启进程
mService.startProcessLocked(...);
}
// ActivityManagerService.java
final ProcessRecord startProcessLocked(...) {
ProcessRecord app = getProcessRecordLocked(...); // 还是拿不到
if (app == null) {
app = newProcessRecordLocked(...); // 创建 ProcessRecord 实例
final boolean success = startProcessLocked(...); // 启动新进程
return success ? app : null;
}
}
private boolean startProcessLocked(...) {
mProcStartHandler.post(() -> {
final ProcessStartResult startResult = startProcess(...);
}
}
private ProcessStartResult startProcess(...) {
return Process.start(...)
}

最终 AMS 通过 Process 类去开启进程,继续跟进看看究竟如何创建的。

// Process.java
public static final ProcessStartResult start(...) {
return zygoteProcess.start(...);
}
// ZygoteProcess.java
public final Process.ProcessStartResult start(...) {
return startViaZygote(...)
}
private Process.ProcessStartResult startViaZygote(...) {
// 拼接了一大堆启动进程的参数
...
// 如果还没有与 Zygote 进程连接的 Socket,那么首先建立连接具体建立 Socket 连接的代码在 ZygoteState.connect 方法中
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(...) {
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
}

通过上述代码可以看出,最终会将启动参数通过 Socket 传递给 Zygote 进程,传递的启动参数如下。Screen Shot 2021-06-01 at 3.56.01 PM

跳转到 Zygote 进程,查看其是如何处理这个消息的。

// ZygoteServer.java
Runnable runSelectLoop(String abiList) {
while(true) {
...
connection.processOneCommand(this);
}
}
// ZygoteConnection.java
Runnable processOneCommand(...) {
String[] args = Zygote.readArgumentList(mSocketReader); // 读取到参数
ZygoteArguments parsedArgs = new ZygoteArguments(args);
int pid = Zygote.forkAndSpecialize(...)
}
// Zygote.java
static int forkAndSpecialize(...) {
// 最终调用了 Native 方法,通过 fork Zygote 进程创建了应用程序进程。
pid = nativeForkAndSpecialize(...)
}

到此为止 AMS 启动 Activity (新启进程)的流程就已经走完了,下面来看 APP 启动流程。

应用程序进程创建后

AppProcess

当应用程序进程 fork 完毕后,会继续执行 ZygoteConnection.processOneCommand 方法。

// ZygoteConnection.java
Runnable processOneCommand(ZygoteServer zygoteServer) {
...
pid = Zygote.forkAndSpecialize(...);
try {
if (pid == 0) {
// 子进程,关闭 ServerSocket 关闭节省资源,因此子进程不需要等待连接
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
return handleChildProc(...);
} else {
// 父进程或者 fork 失败
}
} finally {}
}
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
// 关闭本次连接 Socket
closeSocket();
return ZygoteInit.zygoteInit(...);
}
// ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
RuntimeInit.redirectLogStreams(); // 重定向日志输出,将 System.out、System.err 变成了 Log.println 日志输出。
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit(); // Native先忽略。
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
protected static final void commonInit() {
LoggingHandler loggingHandler = new LoggingHandler();
Thread.setUncaughtExceptionPreHandler(loggingHandler); // 当未捕获异常出现时,打印日志
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler)); // 当未捕获异常出现时,告知 AMS 应用崩溃了,同时杀死当前进程
String userAgent = getDefaultUserAgent(); // 生成默认使用的 UserAgent 值,并设置给系统属性
System.setProperty("http.agent", userAgent);
NetworkManagementSocketTagger.install(); // 为 socket 设置 tag,用于网络流量统计
initialized = true;
}
protected static Runnable applicationInit(...) {
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
return findStaticMain(args.startClass, args.startArgs, classLoader); // 反射调用 ActivityThread.main
}

根据上文可以看到当应用程序启动完成后,还做了一些初始化动作,包括:

  1. 重定向日志输出,System.out、System.err 打印的日志统一通过 Log.println 进行输出。

  2. 为所有的线程设置预未捕获异常处理器,当未捕获异常出现时会打印错误日志,比如以下日志,就是 LoggingHandler 打印的。

    2021-05-19 15:36:35.344 25610-25610/com.hefuwei.demo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.hefuwei.demo, PID: 25610
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hefuwei.demo/com.hefuwei.demo.MainActivity}: java.lang.NullPointerException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3324)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3473)
    ...
  3. 为所有的线程设置未捕获异常处理器,当未捕获异常出现时会告知 AMS 当前应用已经崩溃,然后杀死当前应用进程。

    public void uncaughtException(Thread t, Throwable e) {
    try {
    // 通知 AMS 当前应用程序崩溃了
    ActivityManager.getService().handleApplicationCrash(
    mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
    } finally {
    // 杀死当前进程
    Process.killProcess(Process.myPid());
    System.exit(10);
    }
    }
  4. 生成供 HttpUrlConnection 使用的 UserAgent 值,并设置给系统属性。

  5. 为 Socket 设置 Tag,用于网络流量统计。(native 实现暂不清楚原理)。

当这些初始化工作都完成后,会通过反射调用 ActivityThread 的 main 方法。

// ActivityThread.java
public static void main(String[] args) {
// 暂时忽略这个
CloseGuard.setEnabled(false);
// 初始化环境,该类提供环境变量的访问
Environment.initForCurrentUser();
// 设置当前进程名为 <pre-initialized>
Process.setArgV0("<pre-initialized>");
// 创建主线程的 Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 主线程死循环从消息队列中取出消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}

main 方法主要工作就是以下三点

  1. 调用 Looper#prepareMainLooper 创建了主线程的 Looper
  2. 调用了 ActivityThread#attach 准备和 AMS 进行通信
  3. 调用 Looper#loop 死循环从消息队列取出消息并处理

Handler 相关部分就不展开了,主要说说 ActivityThread#attach 方法的作用,注意第一个参数传入的是 false,只有系统服务进程传入的是 true。

private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// 设置 GC 监听,当空闲内存低于 1 / 4 通过 AMS 杀死当前部分当前应用的 Activity
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// 系统服务进程逻辑,忽略
}
// 这里有个 ResourceManager 相关逻辑,暂时忽略
ViewRootImpl.addConfigCallback(configChangedCallback);
}

attach 方法主要工作就是以下两点

  1. 调用 AMS 的 attachApplication 方法用于告知当前应用程序进程已经启动。

  2. 设置 GC 监听, 当空闲内存低于 1 / 4 通过 AMS 杀死当前部分当前应用 Activity。

    内部原理也很简单,也就是新建一个类,重写该类 的 finalize 方法,然后创建一个该类的弱引用实例即可,当 GC 触发时就会调用该类的 finalize 方法,一个简单的 demo。

    class GCWatcher {
    protected fun finalize() {
    gcCallbacks.forEach {
    it.run()
    }
    gcWatcher = WeakReference(GCWatcher())
    }
    companion object {
    private var gcWatcher = WeakReference<GCWatcher>(GCWatcher())
    private val gcCallbacks = arrayListOf<Runnable>()
    fun addCallback(runnable: Runnable) {
    gcCallbacks.add(runnable)
    }
    }
    }

转到 AMS 看看 attachApplication 具体执行了什么操作。

public final void attachApplication(IApplicationThread thread, long startSeq) {
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
thread.bindApplication(...);
mStackSupervisor.attachApplicationLocked(app); // 检查有无待启动的 Activity
return true;
}

attachApplication 方法主要工作为以下四点

  1. 调用 IApplicationThread#bindApplication 通知应用程序进程创建 Application 实例,并进行相应初始化。
  2. 调用 ActivityStackSupervisor#attachApplicationLocked 检查是否有需要启动的 Activity。

这里主要关注前面两点,首先看看第一点,回到应用程序进程。

// ApplicationThread.java
public final void bindApplication(Map services, ...) {
...
if (services != null) {
ServiceManager.initServiceCache(services);
}
AppBindData data = new AppBindData();
data.processName = processName;
... // 将 AMS 下发的信息保存
sendMessage(H.BIND_APPLICATION, data);
}

这个方法主要也就是两件事

  1. 首先将 AMS 下发的服务进程对应的 BinderProxy 对象进行缓存,后续用到直接取就行,免的后续又要跨进程去获取,下图为所有下发的服务名。

    Screen Shot 2021-06-02 at 10.20.15 AM
  2. 将 AMS 下发的其它信息封装成 AppBindData 对象,并发送一个消息到主线程的消息队列中。但是由于此时主线程还没调用 Looper#loop 因此该消息还得不到执行,接着再转回系统服务进程看第二点。

// ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
if (!isFocusedStack(stack)) { // 忽略非前台栈
continue;
}
stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
final ActivityRecord top = stack.topRunningActivityLocked(); // 获取该栈中栈顶 Activity
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
if (activity.app == null && app.uid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
realStartActivityLocked(...) // 找到了待启动的 Activity,那么启动
} catch (RemoteException e) {
throw e;
}
}
}
}
}
return didSomething;
}

遍历当前前台 Activity 栈,判断栈顶 Activity 是否需要启动,如果栈顶 ActivityRecord 中的 app 不存在(不存在表示当前 ActivityRecord 还没依附进程)并且其 processName 与当前进程名一样,那么表示该 Activity 现在需要进行启动。

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, ...)  {
final TaskRecord task = r.getTask();
final ActivityStack stack = task.getStack();
r.setProcess(app); // 使当前 ActivityRecord 依附于当前进程
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent)));
final ActivityLifecycleItem lifecycleItem;
if (andResume) { // 走这个分支
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
return true;
}

这个流程其实上面 AMS 调用 Launcher 的 onPause 方法已经说过,最终调用到 ApplicationThread 的 scheduleTransaction,其也只是发送了一个消息返回。

现在应用程序主线程应该会存在两个消息(实际不止,这里只关注主要的),等到 AMS 执行完毕主线程调用 Looper.loop 后会执行,下面一一进行分析。

H.BIND_APPLICATION

首先执行 H.BIND_APPLICATION 跟进代码。

public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
handleBindApplication(data);
break;
...
}
}
private void handleBindApplication(AppBindData data) {
Process.setArgV0(data.processName); // 设置进程名称,前面设置为 <pre-initialized> 现在改为真正的进程名
final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24);
Boolean is24Hr = null;
if (use24HourSetting != null) {
is24Hr = "24".equals(use24HourSetting) ? Boolean.TRUE : Boolean.FALSE;
}
DateFormat.set24HourTimePref(is24Hr); // 设置时间采用 12 小时制还是 24 小时制
// 反射设置 serial 为 unknown 因此 8.0 后就拿不到了,如果要拿需要调用 Build.getSerial() 不过该方法 AMS 会校验权限
Field field = Build.class.getDeclaredField("SERIAL");
field.setAccessible(true);
field.set(Build.class, data.buildSerial);
if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) { // 如果开始了调试
Debug.changeDebugPort(8100); // 调试器 Socket 端口设置为 8100
IActivityManager mgr = ActivityManager.getService();
try {
// 通知 AMS 显示弹窗提醒用户等在等待 Debugger attach
mgr.showWaitingForDebugger(mAppThread, true);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
Debug.waitForDebugger(); // 等待 Debugger attach
try {
mgr.showWaitingForDebugger(mAppThread, false); // 通知 AMS 关闭弹窗
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); // 获取 CTS BinderProxy
try {
final ProxyInfo proxyInfo = service.getProxyForNetwork(null); // 获取系统网络代理设置
Proxy.setHttpProxySystemProperty(proxyInfo); // 设置代理环境变量
} catch (RemoteException e) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw e.rethrowFromSystemServer();
}
}
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); // 创建 LoadedApk 实例,该类封装了 apk 中的相关信息
mInstrumentation = new Instrumentation(); // 创建 Instrumentation 实例管理系统与应用的交互
mInstrumentation.basicInit(this);
app = data.info.makeApplication(data.restrictedBackupMode, null); // 创建 Application 实例
installContentProviders(app, data.providers); // 创建所有的 ContentProvider 实例,并调用其 onCreate 方法
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app); // 调用 Application.onCreate 方法
}

方法内部逻辑为

  1. 如果当前应用需要调试,那么等待调试器连接后继续执行,也就是说在这之前执行的代码是没有办法进行调试的。
  2. 获取系统网络代理信息,然后设置给当前虚拟机的环境变量,OkHttp 会使用这些环境变量,从而使得代理生效。
  3. 反射创建 Application 实例,调用其 attach 方法,内部调用 attachBaseContext 方法。
  4. 创建所有注册的 ContentProvider 实例,并调用其 onCreate 方法。
  5. 调用创建的 Application 的 onCreate 方法。
LoadedApk.makeApplication

makeApplication 用于创建 Application 实例。

// LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application"; // 如果不使用自定义的 Application 那么使用默认的
}
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext); // 使用 Instrumentation 创建 Application 实例
appContext.setOuterContext(app);
...
}
// Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context) {
Application app = getFactory(context.getPackageName()) // 反射创建 Application 实例
.instantiateApplication(cl, className);
app.attach(context); // attach 内部会调用 attachBaseContext 方法
return app;
}
// AppComponentFactory.java
public Application instantiateApplication(ClassLoader cl, String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Application) cl.loadClass(className).newInstance();
}

可以看到内部通过反射创建的 Application 对象,并调用 attach 依附上一个 ContextImpl 实例,attach 内部又会调用 attachBaseContext。同时由于创建 Application 时方法内部判断了 mApplication 成员是否存在,如果存在就不再创建。如果应用程序有多个进程,也就是说有多个虚拟机实例,就会创建多个 Application 实例,并执行多次 onCreate 方法

ActivityThread.installContentProviders

installContentProviders 用于创建应用的所有 ContentProvider 实例,并通知 AMS 以及创建成功。

// ActivityThread.java
private void installContentProviders(Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
ContentProviderHolder cph = installProvider(context, null, cpi, false, true, true);
if (cph != null) {
results.add(cph);
}
}
try {
// AMS 会将这些 ContentProvider 对应的 ContentProviderHolder 缓存起来,便于后续查询到调用
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
private ContentProviderHolder installProvider(...) {
try {
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
...
}
return retHolder;
}
// AppCompoenentFactory.java
public ContentProvider instantiateProvider(ClassLoader cl, String className) {
return (ContentProvider) cl.loadClass(className).newInstance();
}
// ContentProvider.java
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
...
ContentProvider.this.onCreate();
}

可以看到内部通过反射创建了 ContentProvider 实例,然后调用其 onCreate 方法,最终告知 AMS。至于其工作原理暂时先不研究。

综上,可以知道 Application#attachBaseContext、Application#onCreate、ContentProvider#onCreate 的执行顺序,从前到后分别为

  1. Application#attachBaseContext
  2. ContentProvider#onCreate
  3. Application#onCreate

H.EXECUTE_TRANSACTION

接着执行第二个消息 H.EXECUTE_TRANSACTION 跟进代码。

public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
...
}
}
// TransactionExecutor.java
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
executeCallbacks(transaction); // transaction.mActivityCallbacks 只有一个那就是 LaunchActivityItem,可以根据上面 AMS 创建 transaction 的代码得出
executeLifecycleState(transaction); // transaction.mLifecycleStateRequest 就是 ResumeActivityItem,可以根据上面 AMS 创建 transaction 的代码得出
}
public void executeCallbacks(ClientTransaction transaction) {
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
// item 指的是 LaunchActivityItem
final ClientTransactionItem item = callbacks.get(i);
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
}
}
private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
cycleToPath(r, lifecycleItem.getTargetState(), true);
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
// LaunchActivityItem.java
public void execute(...) {
ActivityClientRecord r = new ActivityClientRecord(...);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
// TransactionExecutor.java
private void cycleToPath(...) {
performLifecycleSequence(r, path); // 间接调用到 ActivityThread.handleStartActivity 方法
}
// ResumeActivityItem.java
public void execute(...) {
client.handleResumeActivity(token, true, mIsForward, "RESUME_ACTIVITY");
}
public void postExecute(...) {
ActivityManager.getService().activityResumed(token);
}

实际上就是按序进行以下三个操作:

  1. ActivityThread.handleLaunchActivity
  2. ActivityThread.handleStartActivity
  3. ActivityThread.handleResumeActivity
  4. AMS.activityResumed
AT.handleLaunchActivity

首先看看 ActivityThread.handleLaunchActivity 方法。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
performLaunchActivity(r, customIntent);
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
java.lang.ClassLoader cl = appContext.getClassLoader();
// 反射创建 Activity 实例
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation); // 确保 Application 存在
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
appContext.setOuterContext(activity);
activity.attach(..); // 调用 Activity.attach
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme); // 设置 Activity 主题
}
mInstrumentation.callActivityOnCreate(activity, r.state); // 调用Activity.onCreate
}
} catch (SuperNotCalledException e) {
throw e;
}
return activity;
}
AT.handleStartActivity

接着看看 ActivityThread.handleStartActivity 方法。

public void handleStartActivity(...) {
activity.performStart("handleStartActivity");
if (r.state != null) {
// 如果有状态保留,那么调用 Activity.onRestoreInstanceState
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
// 调用 Activity.onPostCreate
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
// Activity.java
final void performStart(String reason) {
// 调用 Activity.onStart
mInstrumentation.callActivityOnStart(this);
}
AT.handleResumeActivity

最后看看 ActivityThread.handleResumeActivity 方法。

final void handleResumeActivity(...) {
r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l); // 将当前 Activity 的 DecorView 添加到 WindowManager 中进行 View 的三大流程
}
}
}
}
public ActivityClientRecord performResumeActivity(...) {
ActivityClientRecord r = mActivities.get(token);
r.activity.performResume(r.startsNotResumed, reason);
}
// Activity.java
final void performResume(boolean followedByPause, String reason) {
// 判断是否需要调用 Activity.onRestart,如果当前状态是 Stop 那么需要调用
performRestart(true /* start */, reason);
// 调用 Activity.onResume
mInstrumentation.callActivityOnResume(this);
// 调用 Activity.onPostResume
onPostResume();
}

综上 Activity 启动时回调的生命周期包括 onCreate、onStart、onPostCreate、onResume、onPostResume。不过 handleResumeActivity 后面的代码将 DecorView 添加到 WindowManger 中才是 Activity 能够展示的关键,这一块下一篇文章分析。

总结与展望

本文大体上分析了从用户点击 Launcher 界面点击图标到应用首个 Activity 的 onResume 执行完毕的整个调用流程,不过有些过于粗略,比如 AMS 的 Activity 栈管理等等,后续还可分析的内容有:

  1. Activity 界面展示流程(包括 View 的三大流程)。
  2. Android 屏幕刷新机制(结合异步消息同步屏障)。
  3. ContentProvider、Service、Broadcast、Fragment 实现逻辑。
  4. Zygote 进程启动流程(这一块暂时不知道怎么调试)。

问题回答

经过源码调试与分支,现在可以解答上述的问题了。

  1. 应用启动时显示的白屏究竟是什么,如何禁止显示?

    答:应用启动时显示的白屏其实是 StartingWindow 也就是预览窗口,其会在进程启动前就显示,如果需要禁用可以经过以下设置

    android:windowIsTranslucent // 设置为 true 或
    android:windowDisablePreview // 设置为 true

    如果需要设置背景颜色,那么需要经过以下设置

    android:windowSplashscreenContent // 设置为 color 或者 drawable
  2. 应用程序进程是如何创建的,创建完做了什么?

    答:应用程序进程由 AMS 通过 Socket 通知 Zygote 进程,后者通过 fork 自身创建的,创建完毕后做了一系列初始化操作,比如设置默认异常处理器等,接着通过反射调用 ActivityThread.main 方法。

  3. 系统管理 Activity 栈涉及的数据结构有哪些?

    答:

    ​ ActivityDisplay 表示的是显示设备,一般也就一个实例。

    ​ ActivityStack 用于管理多个 TaskRecord,主要作用是方便任务栈前后台切换。

    ​ TaskRecord 表示一个 Activity 栈,管理当前栈中所有的 Activity。

    ​ ActivityRecord 表示一个 Activity 在系统服务进程的记录。

  4. 应用崩溃后,为什么会打印导致崩溃的错误日志?

    答:应用程序进程刚一创建时,就会设置两个默认异常处理器,第一个负责打印最终错误日志,第二个负责将应用 Crash 上报给 AMS 并杀死当前应用。

  5. 调试应用时,为什么会出现等待提示框,这个框是如何弹出的?

    答:在 ActivityThread 的 handleBindApplication 方法中如果应用需要进行调试,则会跨进程调用 AMS 的 showWaitingForDebugger 方法,第二个参数决定是显示还是隐藏。显示逻辑如下:

    // ActivityManagerService.java
    public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
    synchronized (this) {
    ProcessRecord app = getRecordForAppLocked(who);
    Message msg = Message.obtain();
    msg.what = WAIT_FOR_DEBUGGER_UI_MSG;
    msg.obj = app;
    msg.arg1 = waiting ? 1 : 0;
    mUiHandler.sendMessage(msg);
    }
    }
    public void handleMessage(Message msg) {
    case WAIT_FOR_DEBUGGER_UI_MSG: {
    ProcessRecord app = (ProcessRecord)msg.obj;
    if (msg.arg1 != 0) {
    if (!app.waitedForDebugger) {
    Dialog d = new AppWaitingForDebuggerDialog(
    ActivityManagerService.this,
    mUiContext, app);
    app.waitDialog = d;
    app.waitedForDebugger = true;
    d.show();
    }
    } else {
    if (app.waitDialog != null) {
    app.waitDialog.dismiss();
    app.waitDialog = null;
    }
    }
    }
    }

    其实也就是个 Dialog 不过是系统服务进程弹出的,我们也可以使用反射调用让其显示,不过没什么意义。

  6. 在系统设置中设置代理,为什么应用就会走这个代理?

    答:由于应用程序进程在启动后会请求 ConnectivityService 获取代理信息,然后将其设置当前虚拟机的环境变量,而 OkHttp 底层会去读取环境变量,因此就会生效。

  7. 免初始化的 SDK (比如 LeakCanary)究竟是如何做到的?

    答:通过注册 ContentProvider,其 onCreate 方法会自动在 Application.onCreate 之前执行。

  8. 为什么应用不会退出,不应该方法执行完就退出?

    答:由于主线程调用了 Looper.loop 使得主线程处理死循环中(不断从消息队列中取消息),因此主线程不会执行完毕,应用也不会退出。

  9. 应用在后台时点击应用图标,为什么不会再次启动首页?

    答:根据源码发现如果待启动的 Activity 将要存放的 TaskRecord 后台已经存在,并且本次启动的 Intent 与原先启动该 TaskRecord 的 Intent 一致,那么就只会将该 TaskRecord 带到前台,而不进行任何操作(如果设置了 SingleTop 还是会调用 onNewIntent 的)。

    // ActivityStarter.java
    private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
    // 将要启动的组件名,是否与启动该栈启动时的组件名一致,Launcher 启动的栈,再次启动这里当然相同
    if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
    if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
    || LAUNCH_SINGLE_TOP == mLaunchMode)
    && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
    // 要启动的组件名与启动该栈时的组件名一致,并且设置了 SingleTop,那么不新建 Activity,只是调用 onNewIntent
    // In this case the top activity on the task is the same as the one
    // being launched, so we take that as a request to bring the task to
    // the foreground. If the top activity in the task is the root activity,
    // deliver this new intent to it if it desires.
    deliverNewIntent(intentActivity);
    } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
    // 这种情况我们要再次启动一个 Activity 加入栈,因为不同的 Intent。
    // In this case we are launching the root activity of the task, but with a
    // different intent. We should start a new instance on top.
    mAddingToTask = true;
    mSourceRecord = intentActivity;
    }
    }
    }
  10. 为什么 onCreate、onStart、onResume 都获取不到 View 的宽高?

    答:因为 View 的三大流程要在 onResume 回调完毕,并且当前 DecorView 添加到 WindowManager 中才会开始,因此这些生命周期都是拿不到结果的。

0%