news 2026/11/5 7:56:08

安卓应用启动流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
安卓应用启动流程

继续 Android14 应用冷启动源码:从 ActivityThread.attach 到 AttachApplicationHelper-CSDN博客

以及 Android14应用冷启动源码2,从 Zygote fork 到 onCreate:Activity 启动流程六阶段拆解-CSDN博客 之前追踪了ActivityThread的main方法一直到调用了Activity的onCreate方法。前面的流程没看呢。现在从点击Launcher图标这个起点追踪下应用启动流程。

Launcher 本身是一个普通 App。点击图标后,入口在 Launcher 的 onClick,最终走到 startActivitySafely。这里会先设置一个关键 Flag:Intent.FLAG_ACTIVITY_NEW_TASK。

因为 Launcher 本身没有“可用的任务栈上下文”来承载目标 Activity,目标 Activity 必须在新任务栈中启动。

之后进入标准 Activity 启动 API:

Launcher.startActivitySafely()
→ Activity.startActivity(intent)
→ Activity.startActivityForResult(intent, -1) // -1:Launcher 不关心结果
→ Instrumentation.execStartActivity(...)

即

Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);

第二个参数就是ActivityThread里面的ApplicationThread对象,跨进程通信用的。

第三个mToken,是启动当前activity(这里是Launcher)attach方法传过来的。只用于表明调用方的来源 Activity,不是目标 Activity 的 token。

进入到execStartActivity方法内部:

中间这一段是 Instrumentation 的 ActivityMonitor 调试/测试机制,它允许在 Activity 启动请求真正发出之前进行匹配、拦截,甚至直接返回一个伪造的 ActivityResult。

然后是最后一段:

重点看:
int result = ActivityTaskManager.getService().startActivity(whoThread, who.getOpPackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);

这里是跨进程通信了,看下ActivityTaskManagerService的startActivity方法:

追踪到了这里:

追踪到ActivityStarter的execute方法:

int execute() { try { onExecutionStarted(); // Refuse possible leaked file descriptors if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } final LaunchingState launchingState; synchronized (mService.mGlobalLock) { final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo); final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID ? Binder.getCallingUid() : mRequest.realCallingUid; launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching( mRequest.intent, caller, callingUid); } if (mRequest.intent != null) { mRequest.componentSpecified |= mRequest.intent.getComponent() != null; } // If the caller hasn't already resolved the activity, we're willing // to do so here. If the caller is already holding the WM lock here, // and we need to check dynamic Uri permissions, then we're forced // to assume those permissions are denied to avoid deadlocking. if (mRequest.activityInfo == null) { mRequest.resolveActivity(mSupervisor); } // Add checkpoint for this shutdown or reboot attempt, so we can record the original // intent action and package name. if (mRequest.intent != null) { String intentAction = mRequest.intent.getAction(); String callingPackage = mRequest.callingPackage; if (intentAction != null && callingPackage != null && (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction) || Intent.ACTION_SHUTDOWN.equals(intentAction) || Intent.ACTION_REBOOT.equals(intentAction))) { ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null); } } int res = START_CANCELED; synchronized (mService.mGlobalLock) { final boolean globalConfigWillChange = mRequest.globalConfig != null && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0; final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (rootTask != null) { rootTask.mConfigWillChange = globalConfigWillChange; } ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config " + "will change = %b", globalConfigWillChange); final long origId = Binder.clearCallingIdentity(); try { res = resolveToHeavyWeightSwitcherIfNeeded(); if (res != START_SUCCESS) { return res; } res = executeRequest(mRequest); } finally { Binder.restoreCallingIdentity(origId); mRequest.logMessage.append(" result code=").append(res); Slog.i(TAG, mRequest.logMessage.toString()); mRequest.logMessage.setLength(0); } if (globalConfigWillChange) { // If the caller also wants to switch to a new configuration, do so now. // This allows a clean switch, as we are waiting for the current activity // to pause (so we will not destroy it), and have not yet started the // next activity. mService.mAmInternal.enforceCallingPermission( android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); if (rootTask != null) { rootTask.mConfigWillChange = false; } ProtoLog.v(WM_DEBUG_CONFIGURATION, "Updating to new configuration after starting activity."); mService.updateConfigurationLocked(mRequest.globalConfig, null, false); } // The original options may have additional info about metrics. The mOptions is not // used here because it may be cleared in setTargetRootTaskIfNeeded. final ActivityOptions originalOptions = mRequest.activityOptions != null ? mRequest.activityOptions.getOriginalOptions() : null; // Only track the launch time of activity that will be resumed. final ActivityRecord launchingRecord = mDoResume ? mLastStartActivityRecord : null; // If the new record is the one that started, a new activity has created. final boolean newActivityCreated = mStartActivity == launchingRecord; // Notify ActivityMetricsLogger that the activity has launched. // ActivityMetricsLogger will then wait for the windows to be drawn and populate // WaitResult. mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res, newActivityCreated, launchingRecord, originalOptions); if (mRequest.waitResult != null) { mRequest.waitResult.result = res; res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord, launchingState); } return getExternalResult(res); } } finally { onExecutionComplete(); } }

重点看这一行:

继续追踪下executeRequest方法。executeRequest方法太长。看几段重点。

caller 就是之前看到的 whoThread(IApplicationThread)。getProcessController(caller) 通过这个 Binder 句柄反查 Launcher 进程的 WindowProcessController。冷启动时 Launcher 进程一定存在,所以这里能拿到 callerApp,callingPid / callingUid 也会被纠正为真实值。

继续往下:

resultTo 就是 Launcher 传过来的 token。isInAnyTask 通过这个 token 反查到 Launcher 的 ActivityRecord。冷启动时目标进程不存在,但 Launcher 自己的 ActivityRecord 是存在的,所以 sourceRecord 非空。

再看ActivityRecord构造:

final ActivityRecord r = new ActivityRecord.Builder(mService) .setCaller(callerApp) .setLaunchedFromPid(callingPid) .setLaunchedFromUid(callingUid) .setLaunchedFromPackage(callingPackage) .setIntent(intent) .setResolvedType(resolvedType) .setActivityInfo(aInfo) .setResultTo(resultRecord) .setResultWho(resultWho) .setRequestCode(requestCode) .setComponentSpecified(request.componentSpecified) .setActivityOptions(checkedOptions) .setSourceRecord(sourceRecord) .build();

这是整个 executeRequest 里最重要的锚点:到这一步,启动请求从 Request 里的零散参数,变成了 system_server 内部可操作的 ActivityRecord 对象 r。后续所有 Task 决策、进程调度、生命周期调度,都围绕这个 r 展开。

再然后是:

mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, checkedOptions, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid);

r:刚构造的目标 ActivityRecord;

sourceRecord:调用方 ActivityRecord;

startFlags:启动标志;

checkedOptions:合并后的 ActivityOptions;

balVerdict:后台启动检查结果;

intentGrants:Intent 携带的 URI 权限授予;

realCallingUid:真实调用者 UID。

startActivityUnchecked方法代码详细如下:

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, ActivityOptions options, Task inTask, TaskFragment inTaskFragment, BalVerdict balVerdict, NeededUriGrants intentGrants, int realCallingUid) { int result = START_CANCELED; final Task startedActivityRootTask; // Create a transition now to record the original intent of actions taken within // startActivityInner. Otherwise, logic in startActivityInner could start a different // transition based on a sub-action. // Only do the create here (and defer requestStart) since startActivityInner might abort. final TransitionController transitionController = r.mTransitionController; Transition newTransition = transitionController.isShellTransitionsEnabled() ? transitionController.createAndStartCollecting(TRANSIT_OPEN) : null; RemoteTransition remoteTransition = r.takeRemoteTransition(); try { mService.deferWindowLayout(); transitionController.collect(r); try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, options, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityRootTask = handleStartResult(r, options, result, newTransition, remoteTransition); } } finally { mService.continueWindowLayout(); } postStartActivityProcessing(r, result, startedActivityRootTask); return result; }

重点看startActivityInner,这个方法很长。重点:

getReusableTask():找可复用的现有 Task(热启动/复用场景)。

computeTargetTask():如果没有可复用 Task,计算目标 Task。

newTask = targetTask == null:冷启动 Launcher 场景下,目标应用通常没有现成 Task,targetTask 为 null,newTask = true。

这里只需要确认:冷启动走的是 newTask = true 分支,后续会创建新 Task。

再下面:

这是Task 创建与 Activity 挂载。冷启动时:

getOrCreateRootTask(...):为启动创建/获取 RootTask。

setNewTask(taskToAffiliate):新建 Task 并把目标 Activity 放进去。taskToAffiliate 在 mLaunchTaskBehind 场景下才非空,Launcher 正常冷启动通常为 null。

这一步完成后,mStartActivity 已经挂到了目标 Task 上,mStartActivity.getTask() 不再为 null。

再然后:

这是 ActivityRecord 真正被放入 Task 的调度入口。它内部会处理 Activity 在 Task 中的位置、Task 的可见性等。

再下面:

mDoResume 为 true 时(Launcher 冷启动通常为 true),会调用 RootWindowContainer.resumeFocusedTasksTopActivities(...)。

这个调用是触发 resume 的入口。然后继续追踪看下resumeFocusedTasksTopActivities里面的代码。代码在RootWindowContainer中:

重点是这句代码:

if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
|| getTopDisplayFocusedRootTask() == targetRootTask)) {
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
}

上一站 startActivityInner 把刚挂好 mStartActivity 的 mTargetRootTask 传进来,且它就是当前 Display 的顶部聚焦 RootTask,所以这个 if 条件成立,直接进入 resumeTopActivityUncheckedLocked。

这里需要记住的是:target 参数就是 startActivityInner 里传入的 mStartActivity。下游的 resumeTopActivityInnerLocked 会用它做“要 resume 哪个 Activity”的判断,并最终走到 startSpecificActivity 的进程存在性判断。

Task即传统说任务栈,对应Recents 一个卡片。Task的resumeTopActivityUncheckedLocked方法如下:

重点是这一段:

if (isLeafTask()) {
if (isFocusableAndVisible()) {
someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
}
} else {
// 遍历子 Task 递归 ...
}

isLeafTask():判断当前 Task 是否是没有子 Task 的叶子 Task。冷启动时 startActivityInner 通过 setNewTask 新建的 Task 是叶子 Task,所以会进入这个分支。

isFocusableAndVisible():叶子 Task 还必须可聚焦且可见才继续。新建的冷启动 Task 正常情况下满足。

resumeTopActivityInnerLocked(...):真正的 resume 决策(包括 startSpecificActivity 的进程存在性判断)在它里面。

后面的 else 分支是非叶子 Task 的递归遍历,用于分屏、多窗口、TaskFragment 嵌套等场景。冷启动的单层新 Task 不会走到。

下面追踪resumeTopActivityInnerLocked的调用。代码如下:

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options, boolean deferPause) { if (!mAtmService.isBooting() && !mAtmService.isBooted()) { // Not ready yet! return false; } final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */); if (topActivity == null) { // There are no activities left in this task, let's look somewhere else. return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options); } final boolean[] resumed = new boolean[1]; final TaskFragment topFragment = topActivity.getTaskFragment(); resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause); forAllLeafTaskFragments(f -> { if (topFragment == f) { return; } if (!f.canBeResumed(null /* starting */)) { return; } resumed[0] |= f.resumeTopActivity(prev, options, deferPause); }, true); return resumed[0]; }

重点看:

final TaskFragment topFragment = topActivity.getTaskFragment();
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);

TaskFragment 是 Task 内部的一个“片段/容器”,用来承载一组 ActivityRecord。可以把它理解为 Task 和 ActivityRecord 之间新增的一层中间结构。

然后看下TaskFragment.resumeTopActivity的实现,TaskFragment的resumeTopActivity方法如下:

下面还有大量代码,太长了。只看重点。

这个第一段代码,next 就是要 resume 的目标 Activity(即 mStartActivity)。冷启动时它刚挂进 Task,topRunningActivity 能取到;canResumeByCompat() 正常返回 true。

然后这个pausing分支中,startProcessAsync这里是冷启动的一个触发点。这个pause可能是和activity切换有关系吧。其中next.attachedToProcess()为true是热启动,else分支是冷启动。

这里也是一个冷启动分支。重点是 mTaskSupervisor.startSpecificActivity(next, true, true);

我重点看startSpecificActivity分支,前面那个冷启动分支等以后有时间再看下。下面追踪到ActivityTaskSupervisor的startSpecificActivity方法。代码如下:

先看这段代码:

final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
if (wpc != null && wpc.hasThread()) {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
}

wpc != null:系统中存在目标 Activity 对应进程的 WindowProcessController。wpc 是 system_server 侧对“目标进程”的管理对象,通过 processName + uid 查找。

wpc.hasThread():这个进程已经和系统建立了 Binder 连接(IApplicationThread 非空),也就是进程不仅存在,而且已经跑到 ActivityThread.attach() 之后、可以向它调度生命周期了。

冷启动时:目标进程尚未创建,wpc 为 null(或虽存在但 hasThread() 为 false),不会进入这个 if,直接落到方法末尾的 startProcessAsync。

热启动时:进程已存在且 hasThread() 为 true,进入 realStartActivityLocked,直接通过 ClientTransaction 调度 LaunchActivityItem / ResumeActivityItem,不创建新进程。

最后一句代码是冷启动:

mService.startProcessAsync(r, knownToBeDead, isTop,
isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_ACTIVITY);

这里是mService类型是ActivityTaskManagerService。接下来调用的是:

startProcessAsync 非常短,它的全部作用可以概括为一句话:不在 ATMS 的锁内直接调用 AMS,而是把“启动进程”这个动作打包成一条消息,异步投递到 system_server 的主线程去执行。

PooledLambda.obtainMessage 是 Android 用来复用 Message 对象的工具:它把“方法引用 + 参数”绑到一个 Message 的 callback 上,避免每次启动进程都新建 lambda/Message 对象。

这条消息的“执行体”是 ActivityManagerInternal::startProcess,目标对象是 mAmInternal,参数就是启动进程所需的全部信息。

mAmInternal:类型是 ActivityManagerInternal,实际是 AMS 的 LocalService,不是 Binder Proxy。所以后续调用是 system_server 进程内的本地调用,不跨进程。

activity.processName / applicationInfo:告诉 AMS 要启动哪个进程、属于哪个应用。

knownToBeDead:正常冷启动为 false;只有 startSpecificActivity 里 RemoteException 兜底才为 true。

isTop / hostingType:决定进程的初始优先级和 HostingRecord 类型,影响 OOM adj。

intent.getComponent():记录是哪个组件触发了进程启动。

另外,这里的mH 是 ActivityTaskManagerService 内部的 Handler,运行在 system_server 的主线程 Looper 上。

追踪startProcess方法:

HostingRecord hostingRecord =
new HostingRecord(hostingType, hostingName, isTop);

---- 把上一站传下来的 hostingType(HOSTING_TYPE_TOP_ACTIVITY 或 HOSTING_TYPE_ACTIVITY)、hostingName(触发组件)、isTop 打包成 HostingRecord。它记录“这个进程是被谁、以什么身份拉起来的”,后续用于 OOM adj 和进程优先级计算。

ProcessRecord rec = getProcessRecordLocked(processName, info.uid); ---- 按 processName + uid 查是否已有 ProcessRecord。冷启动时进程尚未创建,这里通常返回 null。它的存在主要是为了兼容“记录存在但线程未 attach”的边界情况,冷启动主干不依赖它。

ProcessRecord app = startProcessLocked(processName, info, knownToBeDead,
0 /* intentFlags */, hostingRecord,
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);

---- 它把进程启动参数交给 AMS 的 startProcessLocked,参数里有两个需要认识:

ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE:告诉 Zygote 这是延迟敏感的进程启动,影响 fork 时的调度策略。

knownToBeDead:正常冷启动为 false;只有 startSpecificActivity 里 RemoteException 兜底才为 true。

然后是调用到AMS的startProcessLocked方法:

然后是调用ProcessList的startProcessLocked方法。如下:

看重点,

按 processName + uid 查进程表。冷启动时目标进程不存在,app 为 null。后面的 isBadProcess / resetProcessCrashTime 是崩溃历史处理,冷启动正常通过。

冷启动时 app == null,不进入这一段。这个是进程已存在则复用的热启动路径。

newProcessRecordLocked(...) 创建新 ProcessRecord。这是冷启动主干的核心锚点。 冷启动时 app == null,进入这里新建一个 ProcessRecord——它代表目标应用进程在 system_server 侧的完整记录(processName、uid、info、hostingRecord 等)。到这一步,进程还没真正创建,但系统内部已经有了它的“档案”。

startProcessLocked(app, hostingRecord, ...) —— 真正启动

这里有两个点:

系统未就绪门禁:mProcessesReady 为 false 时(开机早期),进程会被放入 mProcessesOnHold 挂起。正常运行(包括 Launcher 冷启动)mProcessesReady 为 true,直接通过。

startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride):注意它调用的是另一个重载版本(参数是 ProcessRecord,不是 processName),那个重载内部才会真正走到 Process.start(...),通过 socket 请求 Zygote fork。继续跟踪下:

@GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, abiOverride); }

又调用了6个参数的重载方法:

开头是清理旧进程。

然后:

entryPoint 被硬编码为 "android.app.ActivityThread",它会作为参数一路传给 Zygote。Zygote fork 出子进程后,RuntimeInit.applicationInit() → findStaticMain() 会用这个类名反射找到 ActivityThread.main() 并执行。

Zygote fork → handleChildProc → RuntimeInit.applicationInit
→ findStaticMain("android.app.ActivityThread")
→ 反射调用 ActivityThread.main()

这个字符串就是“新进程 Java 入口”的交接棒,从这里开始,控制流正式指向ActivityThread的 main()。

app启动调用链太长了。后面的流程(ActivityThread.main())之前总结过了。ok.

再整体总结下流程:

┌─────────────────────────────────────────────────────────────────────────────┐
│ ① Launcher 进程(App) │
│ │
│ Launcher.onClick │
│ → startActivitySafely(intent) │
│ → Activity.startActivity(intent) │
│ → Activity.startActivityForResult(intent, -1) │
│ → Instrumentation.execStartActivity(...) │
│ ├── 准备 whoThread = (IApplicationThread) contextThread │
│ ├── intent.prepareToLeaveProcess(who) │
│ └── ActivityTaskManager.getService().startActivity(...) ───────┐ │
│ │ │
└─────────────────────────────────────────────────────────────────────────┼────┘
│
🔵 第一次切换:App → system_server(Binder) │
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ ② system_server 进程(ATMS 侧) │
│ │
│ ATMS.startActivity │
│ → ATMS.startActivityAsUser │
│ ├── assertPackageMatchesCallingUid / enforceNotIsolatedCaller │
│ ├── checkTargetUser │
│ └── obtainStarter(intent, "startActivityAsUser") │
│ .setCaller(whoThread).setCallingPackage(...)... │
│ .execute() │
│ │
│ ActivityStarter.execute() │
│ ├── resolveActivity(补解析 ActivityInfo) │
│ ├── Binder.clearCallingIdentity() │
│ └── executeRequest(mRequest) │
│ │
│ ActivityStarter.executeRequest() │
│ ├── getProcessController(caller) → callerApp │
│ ├── ActivityRecord.isInAnyTask(resultTo) → sourceRecord │
│ ├── 权限 / IntentFirewall / PermissionPolicy / BAL 门禁 │
│ ├── new ActivityRecord.Builder(...).build() → r │
│ └── startActivityUnchecked(r, ...) │
│ │
│ ActivityStarter.startActivityUnchecked() │
│ ├── createAndStartCollecting(TRANSIT_OPEN) │
│ ├── deferWindowLayout() │
│ ├── startActivityInner(r, ...) │
│ ├── handleStartResult(...) │
│ └── continueWindowLayout() │
│ │
│ ActivityStarter.startActivityInner() │
│ ├── getReusableTask() / computeTargetTask() → newTask = true │
│ ├── isAllowedToStart(r, newTask, targetTask) │
│ ├── getOrCreateRootTask(...) │
│ ├── setNewTask(taskToAffiliate) ← 新建 Task,挂载 r │
│ ├── mTargetRootTask.startActivityLocked(...) │
│ └── resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity) │
│ │
│ RootWindowContainer.resumeFocusedTasksTopActivities() │
│ └── targetRootTask.resumeTopActivityUncheckedLocked(target, ...) │
│ │
│ Task.resumeTopActivityUncheckedLocked() │
│ ├── if (mInResumeTopActivity) return false; ← 递归保护 │
│ ├── isLeafTask() && isFocusableAndVisible() │
│ └── resumeTopActivityInnerLocked(prev, options, deferPause) │
│ │
│ Task.resumeTopActivityInnerLocked() │
│ ├── topActivity = topRunningActivity(focusableOnly) │
│ ├── topFragment = topActivity.getTaskFragment() │
│ └── topFragment.resumeTopActivity(prev, options, deferPause) │
│ │
│ TaskFragment.resumeTopActivity() │
│ ├── next = topRunningActivity(focusableOnly) │
│ ├── if (pausing) { ... startProcessAsync(next, ...); return true; } │
│ │ ↑ 提前触发(有 back Task / 当前 fragment 有 resumed 时) │
│ └── if (next.attachedToProcess()) { 热启动 ... } │
│ else { │
│ mTaskSupervisor.startSpecificActivity(next, true, true); │
│ } │
│ │
│ ActivityTaskSupervisor.startSpecificActivity() │
│ ├── wpc = getProcessController(r.processName, r.info.applicationInfo.uid)│
│ ├── if (wpc != null && wpc.hasThread()) { realStartActivityLocked; return; }│
│ │ ↑ 热启动分支,冷启动不走 │
│ └── mService.startProcessAsync(r, knownToBeDead, isTop, hostingType) │
│ │
│ ATMS.startProcessAsync() │
│ ├── PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,│
│ │ mAmInternal, processName, applicationInfo, knownToBeDead, │
│ │ isTop, hostingType, intent.getComponent()) │
│ └── mH.sendMessage(m) ← 切到 system_server 主线程 │
│ │
│ ActivityManagerService.LocalService.startProcess(...) │
│ ├── synchronized (ActivityManagerService.this) │
│ ├── HostingRecord(hostingType, hostingName, isTop) │
│ ├── getProcessRecordLocked(processName, uid) │
│ └── startProcessLocked(processName, info, knownToBeDead, ...) │
│ │
│ ActivityManagerService.startProcessLocked(...) │
│ └── ProcessList.startProcessLocked(processName, info, ...) │
│ │
│ ProcessList.startProcessLocked()(入口版本) │
│ ├── getProcessRecordLocked(processName, uid) → app = null(冷启动) │
│ ├── newProcessRecordLocked(...) → app │
│ ├── 系统就绪门禁 mProcessesReady │
│ └── startProcessLocked(app, hostingRecord, zygotePolicyFlags, ...) │
│ │
│ ProcessList.startProcessLocked(app, ...)(第二层) │
│ ├── 清理旧 pid / death recipient / mProcessesOnHold │
│ ├── checkPackageStartable / getPackageGids / mountExternal │
│ ├── 计算 runtimeFlags(debug / hidden API / profile ...) │
│ ├── updateSeInfo(app) │
│ ├── entryPoint = "android.app.ActivityThread" ← 关键交接棒 │
│ └── startProcessLocked(hostingRecord, entryPoint, app, uid, gids, │
│ runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, │
│ requiredAbi, instructionSet, invokeWith, ...) │
│ │
│ ProcessList.startProcessLocked(hostingRecord, entryPoint, ...)(第三层) │
│ └── Process.start(...) ────────────────────────────────────────┐ │
│ │ │
└─────────────────────────────────────────────────────────────────────────┼────┘
│
🔵 第二次切换:system_server → Zygote(socket) │
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ ③ Zygote 进程 │
│ │
│ ZygoteServer / ZygoteConnection 接收 socket 请求 │
│ → Zygote.forkAndSpecialize(...) ← fork 子进程(COW 继承) │
│ → handleChildProc(...) │
│ → RuntimeInit.applicationInit(...) │
│ → findStaticMain("android.app.ActivityThread") ← 反射找到 main │
│ → 抛出 MethodAndArgsCaller 异常回退调用栈 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│
🔵 第三次切换:Zygote → 新 App 进程(fork 完成) │
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ ④ 新应用进程(App) │
│ │
│ ActivityThread.main() │
│ ├── Looper.prepareMainLooper() │
│ ├── new ActivityThread() │
│ ├── thread.attach(false, startSeq) │
│ │ └── AMS.attachApplication(...) ──┐ ← 和你已读链路汇合点 │
│ └── Looper.loop() │ │
│ ▼ │
│ ── 以下为已读链路 ── │
│ attachApplication → bindApplication → handleBindApplication │
│ → handleLaunchActivity → performLaunchActivity → Activity.onCreate() │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

ok. 太庞大了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 7:56:02

浅谈开源灰白盒模糊测试工具bufferfuzzer-青草莓科技

开发bufferfuzzer的初衷,主要是想白盒fuzz工具拥有这样的能力 对于那些带有结构的buffer测试目标,无论是文件,协议,消息,还是json,xml等类型, 通过建模,让白盒fuzz工具了解buffer的内部结构&am…

作者头像 李华
网站建设 2026/11/5 7:53:36

毕设/课设别再熬夜画图了!SpringBoot考务管理系统:功能结构图、流程图、数据流图、UML类图、时序图、用例图、三线表、用例表、开题报告,用捷码AI一键生成

考务管理系统-综合设计成果/ ├── 00-交付清单/ manifest.json README ├── 01-系统图表/ 8 类系统图(E-R / 功能结构 / 数据流 / 架构 / 流程 / 类图 / 时序 / 用例) ├── 02-设计资料/ 数据库脚本 └── 03-交付成果/ …

作者头像 李华
网站建设 2026/11/5 7:53:36

毕设/课设别再熬夜画图了!SpringBoot酒吧和夜店管理系统:功能结构图、流程图、数据流图、UML类图、时序图、用例图、三线表、用例表、开题报告,用捷码AI一键生成

酒吧和夜店管理系统-综合设计成果/ ├── 00-交付清单/ manifest.json README ├── 01-系统图表/ 8 类系统图(E-R / 功能结构 / 数据流 / 架构 / 流程 / 类图 / 时序 / 用例) ├── 02-设计资料/ 数据库脚本 └── 03-交付成…

作者头像 李华
网站建设 2026/11/5 7:51:31

网页视频资源嗅探:不开抓包工具,5 分钟下走视频直链

网页视频资源嗅探:不开抓包工具,5 分钟下走视频直链 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓(cat-c…

作者头像 李华
网站建设 2026/11/5 7:48:56

MinIO源码深度解读-第14章第14节-性能调优实战-网络磁盘到代码的全方位优化指南

MinIO源码深度解读 - 第14章第14节:性能调优实战——网络、磁盘、代码全方位优化指南 生产环境的 MinIO 需要精心调优才能达到最佳性能。本文从网络、磁盘到代码层面全面分析性能优化。 本文导航 性能基准数据磁盘优化网络优化代码层优化配置调优 性能基准数据 在…

作者头像 李华
网站建设 2026/11/5 7:48:22

Java 泛型:类型参数、通配符与类型擦除

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华