本文基于android-13.0.0_r1,源码参考: cs.android.com/android/pla…
四、ProcessList#startProcess
startProcess函数整体有systrace追踪(可在systrace搜索"Start proc:"),该函数内容较多,可以根据checkSlow判断都做了什么事情。
根据checkSlow,这个函数的内容是请求zygote启动进程,并且结束时zygote已返回结果。
注意checkSlow带的字符串代表“正要做的事情”
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
int mountExternal, String seInfo, String requiredAbi, String instructionSet,
String invokeWith, long startTime) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkSlow(startTime, "startProcess: asking zygote to start proc");
// ...这里内容好多先跳过
final Process.ProcessStartResult startResult;
boolean regularZygote = false;
if (hostingRecord.usesWebviewZygote()) {
// 第一种类型:webview Zygote
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
app.getDisabledCompatChanges(),
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
} else if (hostingRecord.usesAppZygote()) {
// 第二种类型:App Zygote
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
// We can't isolate app data and storage data as parent zygote already did that.
startResult = appZygote.getProcess().start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
false, false,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
} else {
// 第三种类型:常规 Zygote
regularZygote = true;
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
}
// ...
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
最后这部分根据webview Zygote、App Zygote、常规 Zygote进行启动,没有仔细看区别。
按照常规Zygote的话,请求Zygote启动进程就是在Process.start中做的。
前面的entryPoint是"android.app.ActivityThread",这里作为第一个参数processClass传入,作为进程的入口类。
frameworks/base/core/java/android/os/Process.java
/**
* State associated with the zygote process.
* @hide
*/
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags,
int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
whitelistedDataInfoMap,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
后续是继续请求zygote启动新的进程,新的进程将会执行ActivityThread的静态main函数。
五、ProcessList#handleProcessStartedLocked
上接三,在startProcess中请求zygote启动新的进程后,调用handleProcessStartedLocked
打印am_proc_start、ActivityManager: Start proc两个log,以及更新ProcessRecord都在这个函数中进行。
@GuardedBy("mService")
boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
long expectedStartSeq, boolean procAttached) {
mPendingStarts.remove(expectedStartSeq);
final String reason = isProcStartValidLocked(app, expectedStartSeq);
if (reason != null) {
// 从expectedStartSeq判断启动不符合预期,静默查杀启动的进程,返回false
Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" +
pid
+ ", " + reason);
app.setPendingStart(false);
killProcessQuiet(pid);
Process.killProcessGroup(app.uid, app.getPid());
noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_INVALID_START, reason);
return false;
}
mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
checkSlow(app.getStartTime(), "startProcess: done updating battery stats");
// 打印am_proc_start的event log
// 分别是:UserID、pid、Uid、processName、hostingType、hostingName(正在启动的进程的组件)
// am_proc_start: [0,29705,10283,com.taobao.taobao,next-top-activity,{com.taobao.taobao/com.taobao.tao.welcome.Welcome}]
EventLog.writeEvent(EventLogTags.AM_PROC_START,
UserHandle.getUserId(app.getStartUid()), pid, app.getStartUid(),
app.processName, app.getHostingRecord().getType(),
app.getHostingRecord().getName() != null ? app.getHostingRecord().getName() : "");
try {
// PKMS:将进程启动信息(包括基本 APK 哈希)记录到安全日志中。
AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName,
app.processName, app.uid, app.getSeInfo(), app.info.sourceDir, pid);
} catch (RemoteException ex) {
// Ignore
}
Watchdog.getInstance().processStarted(app.processName, pid);
// 打印 ActivityManager: Start proc 日志
// ActivityManager: Start proc 9113:com.taobao.taobao/u0a211 for next-top-activity {com.taobao.taobao/com.taobao.tao.welcome.Welcome}
checkSlow(app.getStartTime(), "startProcess: building log message");
StringBuilder buf = mStringBuilder;
buf.setLength(0);
buf.append("Start proc ");
buf.append(pid);
buf.append(':');
buf.append(app.processName);
buf.append('/');
UserHandle.formatUid(buf, app.getStartUid());
if (app.getIsolatedEntryPoint() != null) {
buf.append(" [");
buf.append(app.getIsolatedEntryPoint());
buf.append("]");
}
buf.append(" for ");
buf.append(app.getHostingRecord().getType());
if (app.getHostingRecord().getName() != null) {
buf.append(" ");
buf.append(app.getHostingRecord().getName());
}
mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.getStartUid());
// 设置pid
synchronized (mProcLock) {
app.setPid(pid);
app.setUsingWrapper(usingWrapper);
app.setPendingStart(false);
}
checkSlow(app.getStartTime(), "startProcess: starting to update pids map");
ProcessRecord oldApp;
synchronized (mService.mPidsSelfLocked) {
oldApp = mService.mPidsSelfLocked.get(pid);
}
// If there is already an app occupying that pid that hasn't been cleaned up
// 是否已经有一个ProcessRecord占用了这个pid,但还没被清理
if (oldApp != null && !app.isolated) {
// Clean up anything relating to this pid first
// 先清理与这个pid有关的任何东西
Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName
+ " startSeq:" + app.getStartSeq()
+ " pid:" + pid
+ " belongs to another existing app:" + oldApp.processName
+ " startSeq:" + oldApp.getStartSeq());
mService.cleanUpApplicationRecordLocked(oldApp, pid, false, false, -1,
true /*replacingPid*/, false /* fromBinderDied */);
}
// 把 ProcessRecord 放进map中
mService.addPidLocked(app);
synchronized (mService.mPidsSelfLocked) {
if (!procAttached) {
// 看了下在startProcessLocked中同步和异步启动进程时,都是直接传进来false
Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mService.mHandler.sendMessageDelayed(msg, usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkSlow(app.getStartTime(), "startProcess: done updating pids map");
return true;
}
六、新进程执行的ActivityThread.main和attach
6.1 main静态函数和请求attach
main静态函数中最主要的就是实例化ActivityThread,并调用attach函数,attach中主要是通过Binder调用AMS的attachApplication
frameworks/base/core/java/android/app/ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// ...
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
// 如果命令行上提供了 PROC_START_SEQ_IDENT 的值,请查找该值。 格式为“seq=114”
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 实例化ActivityThread,调用attach
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 完成之后开始loop,等待执行msg
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {
if (!system) {
final IActivityManager mgr = ActivityManager.getService();
try {
// 通过binder调用到AMS的attachApplication
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {
// ...
}
}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
新进程通过Binder在AMS的线程中调用attachApplication,获取发起端也就是新进程的Pid、Uid等,加AMS锁继续调用attachApplicationLocked
attachApplicationLocked函数内容比较多,分三部分,分别是bindApplication之前、bindApplication、和bindApplication之后
6.2 attach第一部分:bindApplication之前
主要是针对ProcessRecord做得操作,注意这里和AMS启动进程时的ProcessRecord操作不一样,这里是进程已经启动,通过Binder调用AMS的attach,AMS此时只知道发起端的pid等信息。
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
// 查找正在被attach的application record(怀疑这里其实指的是ProcessRecord)..
// 如果我们在多个进程中运行,则通过 pid,
// 或者如果我们 使用匿名线程模拟进程,则仅提取下一个app record。
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
if (pid != MY_PID && pid >= 0) {
// 上面说还有“匿名线程模拟进程”的情况,这里按新进程启动的话,肯定是pid != MY_PID
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
// ...看不懂省略
} else {
app = null;
}
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
// 有可能 在我们有机会更新内部状态之前,进程已经调用了 attachApplication。
if (app == null && startSeq > 0) {
// ...没细看
}
// 这里发现app还是空的话,就开始杀进程了,因为身份未知
if (app == null) {
// ...killProcessQuiet
return false;
}
// If this application record is still attached to a previous
// process, clean it up now.
// 如果application record(ProcessRecord)仍然绑定到之前的进程,就现在清理掉
if (app.getThread() != null) {
handleAppDiedLocked(app, pid, true, true, false /* fromBinderDied */);
}
// 打印 am_proc_bound 日志,通常紧跟在am_proc_start之后
// 类似 am_proc_bound: [0,29702,com.taobao.taobao]
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
// 设置一些初始状态,包括adj等
app.mState.setCurAdj(ProcessList.INVALID_ADJ);
app.mState.setSetAdj(ProcessList.INVALID_ADJ);
// ....
}
// 超时监测的msg,在ProcessList#handleProcessStartedLocked发出来的
// 即与zygote通信完成后发出,到新进程请求AMS attach时结束
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
// bindApplication前的准备工作完成,主要是针对ProcessRecord app,
// 从 mPidsSelfLocked 中根据pid获取app,然后做一系列初始化
checkTime(startTime, "attachApplicationLocked: before bindApplication");
6.3 attach第二部分:bindApplication
这部分主要是用传进来的ApplicationThread进行bindApplication,ApplicationThread可以看前面ActivityThread,是其中的一个内部类,用来和新进程Binder通信的。
有点绕,其实就是新进程起来后,通过Binder调用到AMS进行attach,而AMS又通过Binder调用到新进程进行bindApplication
// ...
try {
// 前面这段干啥的看不懂
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
if (app.getIsolatedEntryPoint() != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
// 这是一个isolated进程,它应该只调用一个entry point而不是绑定到一个app。
// 这里可以看出isolated进程的含义,isolated进程不会绑定到app
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo,/*...*/);
} else {
thread.bindApplication(processName, appInfo,/*...*/);
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
// 绑定后使ProcessRecord处于活跃状态,或者客户端可能在准备就绪之前运行请求(例如启动activity)。
synchronized (mProcLock) {
app.makeActive(thread, mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
}
// 更新LRU队列
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
final long now = SystemClock.uptimeMillis();
synchronized (mAppProfiler.mProfilerLock) {
app.mProfile.setLastRequestedGc(now);
app.mProfile.setLastLowMemory(now);
}
} catch (Exception e) {
// ...
}
ApplicationThread在ActivityThread中,可以看到bindApplication实际是异步地发送BIND_APPLICATION的msg,不过注意的是,虽然发送并没有带延时,但是此时还处于新进程的attach阶段,attach完成之后才开始loop接收消息,所以真正的接收BIND_APPLICATION消息开始执行还得等一会儿。
frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
// ...
@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,/*...*/) {
// ...
sendMessage(H.BIND_APPLICATION, data);
}
现在知道attach中所谓的bindApplication只是Binder调用回新进程发了个消息,继续看attach后续做的事情吧
6.4 attach第三部分:bindApplication之后
回到AMS的attachApplicationLocked,bindApplication之后依次检查是否有新的activity、service等要在这个进程上运行。比如有应用的activity需要在这个进程上运行,那么AMS就需要通知到WMS,mAtmInternal就是wm下面的ATMS,调用ATMS的attachApplication,接下来就属于activity启动的范畴了。
boolean badApp = false;
boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
// 康康 顶部可见activity 是否正在等待要在此进程中运行...
if (normalMode) {
try {
// mAtmInternal是ATMS,调用mRootWindowContainer.attachApplication
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// Find any services that should be running in this process...
// 查找 应在此进程中运行的 任何service...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
// Check if a next-broadcast receiver is in this process...
// 检查下一个广播接收者是否在此过程中...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
// ...
}
// ...
if (badApp) {
app.killLocked("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
true);
handleAppDiedLocked(app, pid, false, true, false /* fromBinderDied */);
return false;
}
if (!didSomething) {
// 什么都没做时,调整到process begin级别的adj
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
}
return true;
}
用badApp和didSomething两个布尔变量记录是否出错、是否做了什么事情(activity、service等),最后attach结束。
七、ActivityThread#handleBindApplication
六中讲到main函数中做了attach后开始loop,而attach中AMS通过Binder调用回新进程发送了一个BIND_APPLICATION的msg
class H extends Handler {
public static final int BIND_APPLICATION = 110;
// ...
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
// ...其他的case
}
}
}
新进程的Handler接收到BIND_APPLICATION消息,在systrace追踪中进行handleBindApplication
handleBindApplication中的内容非常多,看不懂,systrace中看主要耗时的是makeApplication和app.onCreate
if (ii != null) {
initInstrumentation(ii, data, appContext);
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
// ...
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
// ...
}
大概到这里新的进程就启动完成了,Looper开始接收消息并执行。