前文回顾:
Android8 从系统启动到用户见到第一个Activity的流程源码分析(一)-CSDN博客文章浏览阅读250次,点赞2次,收藏3次。本文分析了Android系统启动过程中AMS(ActivityManagerService)的systemReady方法及其关键流程。当SystemService调用AMS的systemReady方法后,AMS会初始化各类服务,清理不允许运行的进程,最终通过startHomeActivityLocked启动主屏幕Activity。该流程涉及多个关键步骤: 创建Home Intent并解析对应Activity信息 通过ActivityStarter启动主屏幕Activity 在startActivityLochttps://blog.csdn.net/g_i_a_o_giao/article/details/150958400?spm=1001.2014.3001.5502在上篇文章中,我们依次分析了从systemReady方法到startHomeActivityLocked方法,再到startHomeActivity方法,接着深入探讨了startActivityLocked方法和startActivity方法,最终对startActivityUnchecked方法进行了详细解析。
那么就来看看ActivityStarter.java中的startActivityUnchecked方法。首先就是初始化内部状态,然后就是获取可重用的Activity,但是在这里获取到的应该为null,然后就是判断包名是否存在,当然这里是存在的。然后就是一堆变量的设置,并且判断是不是新的任务。接下来就是调用方法ActivityStack.java的方法startActivityLocked,在目标任务栈中启动Activity。接下来由于之前调用startActivity方法传递的doResume为true,因此会进入ture分支判断可见性。又因为这是启动第一个Activity,那么这个Activity肯定是不可见的并且不在前台,就会调用ActivityStackSupervisor.java的resumeFocusedStackTopActivityLocked方法来resume一个Activity。
private ActivityStack mTargetStack;
rivate final ActivityStackSupervisor mSupervisor;
/*
之前传递的doResumed为true
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,options, inTask, outActivity);
*/
// 注意:此方法只能从 {@link startActivity} 调用
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
// 1. 初始化内部状态
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// 2. 计算启动任务标志
computeLaunchingTaskFlags();
// 3. 计算源堆栈
computeSourceStack();
// 4. 设置Intent的标志
mIntent.setFlags(mLaunchFlags);
// 5. 查找可重用的Activity
ActivityRecord reusedActivity = getReusableIntentActivity();
// 6. 获取优先启动的堆栈和显示ID
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
final int preferredLaunchDisplayId =
(mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
// 7. 处理可重用Activity的情况
if (reusedActivity != null) {
// 检查是否违反锁定任务模式
if (mSupervisor.isLockTaskModeViolation(reusedActivity.getTask(),
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
mSupervisor.showLockTaskToast();
Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
// 设置启动Activity的任务
if (mStartActivity.getTask() == null) {
mStartActivity.setTask(reusedActivity.getTask());
}
// 设置任务的基础Intent
if (reusedActivity.getTask().intent == null) {
reusedActivity.getTask().setIntent(mStartActivity);
}
// 处理CLEAR_TOP、单实例、单任务等标志
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask) {
final TaskRecord task = reusedActivity.getTask();
// 清除任务中到要启动的Activity之上的所有Activity
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
// 确保reusedActivity仍然有任务引用
if (reusedActivity.getTask() == null) {
reusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) {
// 更新任务的Intent
top.getTask().setIntent(mStartActivity);
}
// 传递新的Intent
deliverNewIntent(top);
}
}
// 发送启动功率提示
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
// 设置目标堆栈并移动到前台
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
// 处理输出Activity
final ActivityRecord outResult =
outActivity != null && outActivity.length > 0 ? outActivity[0] : null;
// 当有可重用Activity且当前结果是蹦床Activity时,设置可重用Activity为结果
if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
outActivity[0] = reusedActivity;
}
// 处理ONLY_IF_NEEDED标志
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// 不需要启动新Activity,只需恢复顶部Activity
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
setTaskFromIntentActivity(reusedActivity);
// 如果没有添加到任务且没有重用任务,只需将任务带到前台
if (!mAddingToTask && mReuseTask == null) {
resumeTargetStackIfNeeded();
if (outActivity != null && outActivity.length > 0) {
outActivity[0] = reusedActivity;
}
return START_TASK_TO_FRONT;
}
}
// 8. 检查包名是否存在
if (mStartActivity.packageName == null) {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
if (sourceStack != null) {
sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
null /* data */);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// 9. 检查是否应该启动(单顶模式等)
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord topFocused = topStack.topActivity();
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
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
// 确保正确恢复顶部Activity
topStack.mLastPausedActivity = null;
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
return START_RETURN_INTENT_TO_CALLER;
}
// 传递新的Intent
deliverNewIntent(top);
// 处理不可调整大小的任务
mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
preferredLaunchDisplayId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
// 10. 确定是否为新任务
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// 判断是否为新任务
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// 这种情况很少见,将其放在顶部任务中或创建新任务
setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
// 11. 授权URI权限和临时访问
mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
// 12. 设置返回任务
if (mSourceRecord != null) {
mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
}
// 13. 记录任务和Activity创建事件
if (newTask) {
EventLog.writeEvent(
EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
mStartActivity.getTask().taskId);
}
ActivityStack.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
// 14. 发送启动功率提示
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
// 15. 在目标堆栈中启动Activity
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
// 16. 处理resume或可见性
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
// 如果Activity不可聚焦(如画中画)或当前有覆盖层,则确保可见但不resume
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} else {
// 如果目标堆栈可聚焦但不在前台,则移动到前台
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
// resume顶部Activity
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
// 添加到最近活动列表
mTargetStack.addRecentActivityLocked(mStartActivity);
}
// 17. 更新用户堆栈
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
// 18. 处理不可调整大小的任务
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
preferredLaunchDisplayId, mTargetStack.mStackId);
return START_SUCCESS;
}
接下来分析frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java中的resumeFocusedStackTopActivityLocked方法。该方法主要是resume焦点栈顶部的Activity。因为这里传递的targetStack不为空,那么就会调用ActvityStack.java中的resumeTopActivityUnchecked
Locked方法
/**
* 尝试恢复焦点栈顶部的Activity。
* 这是一个同步方法,调用者需要持有AMS(ActivityManagerService)的相关锁。
*
* @param targetStack 目标Activity栈,如果非空且是当前焦点栈,则尝试恢复其顶部Activity
* @param target 目标Activity记录,用于指定要恢复的具体Activity
* @param targetOptions 启动选项,包含动画等参数
* @return boolean 表示是否成功执行了恢复操作
*/
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
// 检查系统是否准备就绪可以执行Activity恢复操作
if (!readyToResume()) {
return false; // 系统未就绪,直接返回false
}
// 如果指定了目标栈且该栈正是当前焦点栈,则尝试恢复该栈顶部的Activity(执行这里的代码)
if (targetStack != null && isFocusedStack(targetStack)) {
// 调用目标栈的恢复方法,并返回其结果
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
// 获取当前焦点栈顶部正在运行的Activity记录
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
// 情况1: 没有正在运行的Activity,或者顶部Activity不在RESUMED状态
// 需要恢复焦点栈的顶部Activity
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.state == RESUMED) {
// 情况2: 顶部Activity已处于RESUMED状态
// 执行可能存在的挂起任务到前台的过渡动画
mFocusedStack.executeAppTransition(targetOptions);
}
// 对于非焦点栈或不需要立即恢复的情况,返回false
return false;
}
那么我们继续看一下ActivityStack.java中的resumeTopActivityUncheckedLocked方法。在这个方法中,主要是调用了resumeTopActivityInnerLocked方法来实现具体的逻辑。
/**
* 确保栈顶的Activity被恢复到RESUMED状态。
* 这是恢复Activity的核心入口方法,但通常不应直接调用。
*
* @param prev 先前处于RESUMED状态的Activity(通常正在执行PAUSE过程),可能为null。
* @param options 启动选项,包含动画等参数。
* @return 如果成功开始了某个Activity的恢复流程则返回true,否则返回false。
*
* 注意:直接调用此方法是不安全的,因为它可能导致非焦点栈中的Activity被恢复。
* 正确的做法是使用 {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked}
* 来根据当前系统状态恢复正确的Activity。
*/
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
// 递归调用保护:检查全局标志,防止重入(例如在resume一个Activity时,它又触发了另一个resume)
if (mStackSupervisor.inResumeTopActivity) {
// 如果已经在执行resume操作,则直接返回,避免递归调用。
return false;
}
boolean result = false;
try {
// 设置全局标志,表示开始执行resume操作,防止递归调用。
mStackSupervisor.inResumeTopActivity = true;
// 调用内部方法执行实际的恢复逻辑
result = resumeTopActivityInnerLocked(prev, options);
} finally {
// 无论内部方法执行成功与否,最终都要清除全局标志,确保后续调用能正常进行。
mStackSupervisor.inResumeTopActivity = false;
}
// 在恢复栈顶Activity的过程中,可能需要暂停当前的顶层Activity(例如,用户返回了锁屏界面)。
// 上面的resumeTopActivityInnerLocked方法内部会处理正常的暂停逻辑。但有一种特殊情况:
// 当最终要恢复的Activity就是当前已经Resumed的Activity时,正常的暂停逻辑会被抑制。
// 因此,这里需要再次检查系统是否应该进入睡眠(准备暂停)状态。
// 获取当前栈中真正可获取焦点的顶层Activity
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
// 检查条件:如果下一个Activity为空,或者下一个Activity没有能力(或权限)点亮屏幕
if (next == null || !next.canTurnScreenOn()) {
// 调用检查准备进入睡眠的方法。这个方法会判断是否需要暂停当前Activity(比如设备即将休眠、锁屏等)。
checkReadyForSleep();
}
// 返回内部方法执行的结果
return result;
}
紧接着我们去分析resumeTopActivityInnerLocked方法。这个方法太长了足有500多行,本篇文章只截取其中一个比较关键的代码进行分析。进行一系列判断以后,最终调用到了ActivityStackSupervisor.java中的startSpecificActivityLocked方法。
// Whoops, need to restart this activity!
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);
mStackSupervisor.startSpecificActivityLocked(next, true, true);
那么再来看看这个startSpecificActivityLocked方法。在这个方法中首先判断目标Activity所存在的进程是否存在。如果存在的话直接在该进程中启动Activity,不存在则调用AMS中的startProcessLocked来启动一个新的应用进程。从这里可以看出Android在启动Activity中“进程先于Activity”的核心原则。
final ActivityManagerService mService;
/**
* 启动一个特定的Activity。此方法负责判断是该Activity所属的应用进程是否已经运行,
* 并根据判断结果决定是直接启动Activity还是先启动应用进程。
* 这是一个同步方法,调用者需要持有AMS(ActivityManagerService)的相关锁。
*
* @param r 要启动的Activity的记录(ActivityRecord)
* @param andResume 是否在启动后立即将其置为RESUMED状态(true),还是只走到STARTED状态(false)
* @param checkConfig 是否检查配置变更(例如屏幕旋转)并等待Activity处理
*/
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// 1. 检查目标Activity所需的应用程序进程是否已经存在并运行。
// 通过进程名和UID来查询进程记录(ProcessRecord)
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
// 为此Activity设置启动时间戳,用于后续性能分析和ANR判断
r.getStack().setLaunchTime(r);
// 2. 如果找到了对应的进程记录,并且该进程的ApplicationThread(与应用进程通信的Binder代理)不为空
if (app != null && app.thread != null) {
try {
// 检查Activity的配置标志:FLAG_MULTIPROCESS
// 通常,一个应用的组件默认运行在同一个进程中。此标志允许Activity运行在一个新的专属进程中。
// 但同时需要排除Android系统核心组件("android"包),因为它们是框架的一部分,
// 即使标记为多进程,也不应作为独立的APK在进程统计信息中进行跟踪。
if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// 将此Activity所在的包名和版本码添加到进程的包列表中。
// 这用于进程管理(例如:当该包被更新时,需要重启进程)和统计信息收集。
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
// 3. 核心方法:进程已存在,直接在该进程中启动目标Activity
realStartActivityLocked(r, app, andResume, checkConfig);
// 启动成功,直接返回
return;
} catch (RemoteException e) {
// 捕获远程异常。如果与应用进程的通信失败(例如进程刚刚意外死亡),
// 记录日志并继续执行下面的代码,走启动新进程的流程。
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// 如果上面的try块中抛出了DeadObjectException(是RemoteException的一种),
// 代码会执行到这里。此时app.thread可能已经无效,需要 fall through 到下面的逻辑去重启应用进程。
}
// 4. 如果进程不存在,或者进程存在但通信失败(app == null || app.thread == null || 发生异常)
// 则调用AMS的方法来启动一个新的应用进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", // 启动原因,表示为启动一个Activity而创建进程
r.intent.getComponent(), // 目标组件,用于调试信息
false, // 已知该进程当前不运行
false, // 不设置为持久进程
true); // 允许在启动时使用isolated(隔离)进程(如果该Activity配置了isolatedProcess属性)
}
那我们继续分析startProcessLocked方法。它内部又调用了重载的startProcessLocked方法,继续分析这个重载方法。由于传递的isolated标志位为false,因此app这个变量会置为null。那么接下来就会调用newProcessRecordLocked方法来创建一个新的ProcessRecord。最后会调用另一个重载方法startProcessLocked。
// 这里的isolated为false
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
// 调用自身的重载方法startProcessLocked
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
/**
* 启动或准备一个应用进程。这是一个核心方法,处理进程的创建、复用和清理。
* 这是一个同步方法,调用者需要持有AMS(ActivityManagerService)的相关锁。
*
* @param processName 要启动的进程名
* @param info 要启动的ApplicationInfo
* @param knownToBeDead 调用者是否已知该进程已经死亡。如果为true,即使找到现有进程记录也会认为其无效。
* @param intentFlags 启动这个进程的Intent的Flags,用于判断是否来自后台
* @param hostingType 宿主类型(例如"activity", "service", "receiver"等),描述为何启动此进程
* @param hostingName 宿主组件的ComponentName,用于调试和错误报告
* @param allowWhileBooting 是否允许在系统还未完全启动完成(booting)时启动此进程
* @param isolated 是否启动一个隔离进程(isolated process)
* @param isolatedUid 如果是隔离进程,指定的UID
* @param keepIfLarge 如果进程因为占用内存过大而被杀后,是否保留其进程记录
* @param abiOverride 要覆盖的ABI(应用程序二进制接口),例如强制使用32位模式
* @param entryPoint 入口点,通常为null(使用默认的"android.app.ActivityThread")
* @param entryPointArgs 传递给入口点的参数
* @param crashHandler 进程崩溃时的处理Runnable
* @return ProcessRecord 返回进程记录。如果进程启动失败或因为某些原因被阻止,则返回null。
*/
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.elapsedRealtime(); // 记录开始时间,用于性能分析
ProcessRecord app;
// 1. 处理非隔离进程:尝试获取已存在的进程记录并检查"坏进程"状态
if (!isolated) {
// 查询是否已有该进程名的记录
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
checkTime(startTime, "startProcess: after getProcessRecord"); // 记录耗时点
// 根据启动来源(前台/后台)处理“坏进程”逻辑
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// 后台启动:如果该进程已被标记为“坏进程”(例如连续崩溃),则静默失败,不启动。
if (mAppErrors.isBadProcessLocked(info)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + info.processName);
return null; // 静默返回null
}
} else {
// 前台启动(例如用户点击图标):清除此进程的崩溃计数,给它一个新的机会。
// 如果它之前被标记为“坏进程”,现在将其重置为“好进程”。
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + info.processName);
mAppErrors.resetProcessCrashTimeLocked(info); // 重置最近崩溃时间
if (mAppErrors.isBadProcessLocked(info)) {
// 记录事件日志,标记进程变好
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mAppErrors.clearBadProcessLocked(info); // 从坏进程列表中清除
if (app != null) {
app.bad = false; // 清除进程记录本身的坏标记
}
}
}
} else {
// 2. 对于隔离进程,它不能复用任何现有进程,所以将app设为null,强制走创建新流程。
app = null;
}
// 3. 决策点:检查是否可以直接复用现有的进程记录
// 满足以下所有条件则可以复用:
// a) 找到了现有的进程记录 (app != null)
// b) 该进程有PID(pid > 0),意味着它正在运行或正在启动
// c) 并且满足以下条件之一:
// i) 调用者不认为它已死 (!knownToBeDead) 且它未被杀死 (!app.killed)
// ii) 进程记录还没有绑定ApplicationThread对象 (app.thread == null),
// 这意味着进程正在启动中,我们只需等待它准备好。
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
if (app != null && app.pid > 0) {
if ((!knownToBeDead && !app.killed) || app.thread == null) {
// 可以复用现有进程!
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
// 将新包添加到进程的包列表中(如果尚未添加),用于后续管理
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: done, added package to proc");
return app; // 直接返回现有的进程记录
}
// 4. 如果找到进程记录,但它已经死亡(knownToBeDead为true 或 app.killed为true),
// 并且已经有thread对象(说明之前完全启动过),那么需要先清理这个死亡的进程。
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
checkTime(startTime, "startProcess: bad proc running, killing");
// 杀死进程组(确保所有子进程都被清理)
killProcessGroup(app.uid, app.pid);
// 处理进程死亡的回调,清理内部状态
handleAppDiedLocked(app, true, true);
checkTime(startTime, "startProcess: done killing old proc");
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
// 5. 此时,如果没有可用的进程记录,则需要创建一个新的。
if (app == null) {
checkTime(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
if (app == null) {
// 创建失败记录日志并返回
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
// 设置崩溃处理器
app.crashHandler = crashHandler;
checkTime(startTime, "startProcess: done creating new process record");
} else {
// 6. 如果app不为null(走到这里说明是上面第4步清理了旧进程后,app记录被保留了下来),
// 则将新包信息添加到这个将要被复用的ProcessRecord中。
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: added package to existing proc");
}
// 7. 检查系统状态:如果系统尚未准备就绪,并且此进程不允许在启动时运行,
// 则将其加入等待队列(mProcessesOnHold),延迟启动。
if (!mProcessesReady // 系统未就绪
&& !isAllowedWhileBooting(info) // 该应用本身不允许在启动时运行
&& !allowWhileBooting) { // 调用者没有特别允许此次启动在启动时运行
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app); // 加入等待队列
}
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
"System not ready, putting on hold: " + app);
checkTime(startTime, "startProcess: returning with proc on hold");
return app; // 返回进程记录,但此时进程尚未真正启动
}
// 8. 所有条件都已满足,真正开始启动进程!
checkTime(startTime, "startProcess: stepping in to startProcess");
// 调用另一个重载方法,执行fork进程等实际操作
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
checkTime(startTime, "startProcess: done starting proc!");
// 9. 返回进程记录。如果进程启动成功,app.pid会被设置为非0值。
return (app.pid != 0) ? app : null;
}
那么再来看这个重载的startProcessLocked方法。在这个方法中进行一些列的权限检验,环境配置以及参数准备。然后就是调用最核心的代码Process.java的start方法。
/**
* 真正启动应用进程的核心方法。该方法准备所有参数,并通过Zygote fork出新进程。
* 这是一个同步方法,调用者需要持有AMS(ActivityManagerService)的相关锁。
*
* @param app 要启动的进程记录(ProcessRecord),其pid字段将被更新
* @param hostingType 宿主类型(如"activity", "service"等),用于描述启动原因
* @param hostingNameStr 宿主组件的字符串表示,用于调试和日志
* @param abiOverride 要覆盖的ABI(应用程序二进制接口),例如强制使用32位模式
* @param entryPoint 入口点类名,如果为null则默认为"android.app.ActivityThread"
* @param entryPointArgs 传递给入口点的参数
*/
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime(); // 记录开始时间,用于性能分析和超时判断
// 1. 清理旧的PID映射(如果存在)
// 这种情况发生在进程之前启动过但死亡了,现在重新启动它。需要清理旧的状态。
if (app.pid > 0 && app.pid != MY_PID) { // MY_PID是system_server自己的PID,不能清理自己
checkTime(startTime, "startProcess: removing from pids map");
synchronized (mPidsSelfLocked) {
// 从PID映射表中移除旧的PID项
mPidsSelfLocked.remove(app.pid);
// 移除可能存在的进程启动超时消息
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0); // 将进程记录的PID重置为0,表示尚未分配有效PID
}
// 2. 如果此进程之前被放在保持队列中(因为系统未就绪),现在启动它,所以从队列中移除
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) {
Slog.v(TAG_PROCESSES, "startProcessLocked removing on hold: " + app);
}
mProcessesOnHold.remove(app);
// 3. 更新CPU统计信息,为即将到来的新进程负载做准备
checkTime(startTime, "startProcess: starting to update cpu stats");
updateCpuStats();
checkTime(startTime, "startProcess: done updating cpu stats");
try {
// 4. 安全检查:在启动前,通过PackageManager服务检查该包是否允许被启动
// 例如,如果应用被管理员禁用或用户停用,这里会抛出异常。
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; // 外部存储挂载模式
// 5. 为非隔离进程准备GID(组ID)和外部存储访问权限
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
// 从PackageManager获取此包声明所需的所有权限对应的GID
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
// 查询此外部存储的挂载模式(读、写、无访问权限)
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
// 构建完整的GID数组,包括:
// - 权限GIDs (permGids)
// - 共享应用GID (允许共享资源,如共享库)
// - 缓存应用GID (访问缓存目录)
// - 用户GID (访问用户范围的资源)
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[3];
} else {
gids = new int[permGids.length + 3];
System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
checkTime(startTime, "startProcess: building args");
// 6. 工厂测试模式处理:在特定工厂测试模式下,允许某些进程以root权限运行
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0; // root UID
}
if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags & ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
uid = 0; // root UID
}
}
// 7. 设置调试标志(debugFlags),控制新进程的调试和行为选项
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// 可调试应用:启用JDWP、Java调试、CheckJNI
debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
// 安全模式:如果应用请求或系统处于安全模式,则在安全模式下运行
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
mSafeMode == true) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
// 根据系统属性设置额外的调试选项
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
if ("true".equals(genDebugInfoProperty)) {
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
// 本地调试:如果此进程是待调试的本地进程,则设置相关标志
if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
debugFlags |= Zygote.DEBUG_ALWAYS_JIT; // 禁用解释模式,始终JIT
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // 生成调试信息
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // 禁用优化,便于本地调试
mNativeDebuggingApp = null; // 重置,只调试一次
}
// 8. 包装脚本(invokeWith):对于可调试应用,检查是否存在wrap.sh脚本
// 该脚本可用于在启动应用前设置环境变量等(如LD_PRELOAD)
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (new File(wrapperFileName).exists()) {
// 如果找到wrap.sh,则通过logwrapper执行它
invokeWith = "/system/bin/logwrapper " + wrapperFileName;
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
// 9. 确定目标ABI(应用程序二进制接口)和指令集
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0]; // 默认使用主ABI
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
// 10. 将计算出的值存回ProcessRecord,供后续使用
app.gids = gids;
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
// 11. 准备SELinux安全上下文(seInfo)
// SELinux是Android的重要安全机制,每个进程都必须有正确的上下文
if (TextUtils.isEmpty(app.info.seInfoUser)) {
Slog.wtf(TAG, "SELinux tag not defined",
new IllegalStateException("SELinux tag not defined for "
+ app.info.packageName + " (uid " + app.uid + ")"));
}
// 拼接完整的seInfo字符串,包括用户部分
final String seInfo = app.info.seInfo
+ (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
// 12. 核心调用:通过Zygote fork新进程
boolean isActivityProcess = (entryPoint == null); // 判断是否是启动ActivityThread
if (entryPoint == null) entryPoint = "android.app.ActivityThread"; // 默认入口点
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName); // 开始Trace,用于性能分析
checkTime(startTime, "startProcess: asking zygote to start proc");
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
// WebView有特殊的启动路径
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
// 正常应用启动:调用Process.start,最终通过socket与zygote通信,fork新进程
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
checkTime(startTime, "startProcess: returned from zygote!");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // 结束Trace
// 13. 进程启动成功后的后续处理
mBatteryStatsService.noteProcessStart(app.processName, app.info.uid); // 更新电池统计
checkTime(startTime, "startProcess: done updating battery stats");
EventLog.writeEvent(EventLogTags.AM_PROC_START, // 写事件日志
UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
try {
// 通知PackageManager记录进程启动(用于应用待机分组等)
AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
seInfo, app.info.sourceDir, startResult.pid);
} catch (RemoteException ex) {
// 忽略RemoteException
}
// 14. 如果是持久化进程(persistent),通知Watchdog监控它
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
// 15. 记录信息日志
checkTime(startTime, "startProcess: building log message");
StringBuilder buf = mStringBuilder;
buf.setLength(0);
buf.append("Start proc ");
buf.append(startResult.pid);
buf.append(':');
buf.append(app.processName);
buf.append('/');
UserHandle.formatUid(buf, uid);
if (!isActivityProcess) {
buf.append(" [");
buf.append(entryPoint);
buf.append("]");
}
buf.append(" for ");
buf.append(hostingType);
if (hostingNameStr != null) {
buf.append(" ");
buf.append(hostingNameStr);
}
Slog.i(TAG, buf.toString());
// 16. 更新ProcessRecord状态
app.setPid(startResult.pid); // 设置新分配的PID
app.usingWrapper = startResult.usingWrapper; // 是否使用了包装脚本
app.removed = false; // 重置移除标志
app.killed = false; // 重置被杀标志
app.killedByAm = false; // 重置被AMS杀死标志
// 17. 更新PID映射表并设置启动超时监控
checkTime(startTime, "startProcess: starting to update pids map");
ProcessRecord oldApp;
synchronized (mPidsSelfLocked) {
oldApp = mPidsSelfLocked.get(startResult.pid);
}
// 18. 处理PID冲突:如果新分配的PID已经被另一个进程记录占用(通常是因为进程死亡后Linux内核快速重用了PID),则需要清理旧的进程记录。
if (oldApp != null && !app.isolated) {
Slog.w(TAG, "Reusing pid " + startResult.pid
+ " while app is still mapped to it");
cleanUpApplicationRecordLocked(oldApp, false, false, -1,
true /*replacingPid*/);
}
synchronized (mPidsSelfLocked) {
// 将新的<PID, ProcessRecord>映射添加到全局表中
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
// 设置进程启动超时监控:如果进程在指定时间内没有成功附加到AMS,则视为启动失败
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkTime(startTime, "startProcess: done updating pids map");
} catch (RuntimeException e) {
// 19. 异常处理:如果进程启动过程中发生任何异常(如Zygote通信失败、包被冻结等)
Slog.e(TAG, "Failure starting process " + app.processName, e);
// 强制停止该包,清理任何相关的状态。这通常发生在包被冻结(例如正在升级)时。
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
}
}
关于Progress.java中的start方法,主要就是通过socket和Zygote通信来fork一个子进程,将会在下篇文章中进行详细讲解。
这里进行一个小的总结,可以看出要启动第一个Activity,调用流程还是比较复杂的。不过最核心的还是先fork一个进程供给Activity启动。