进程启动-2: 从ActivityThread的main函数和Application的onCreate
基于android-8.1.0_r60
AMS提供了一个startProcessLocked
函数,用于启动进程。
触发启动
就应用层而言,启动进程的方式基本上就是如下四种方式:
- Activity
- Service
- Broadcast
- Provider
# 打开Activity时
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
if (app != null && app.thread != null) {
try {
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}
}
// 当查询不到Activity对应进程的时候,启动进程。
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
启动Activity的最后都会进到startSpecificActivityLocked
函数。这里会判定目标进程是否存在,如果不存在那么调用startProcessLocked
。
# Service唤起进程
Service启动最终会执行到ActivServices的bringUpServiceLocked
函数如下:
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 如果Service所在进程存在,并且有效。那么直接调用onStartCommand??,这里的逻辑比较奇怪。
if (r.app != null && r.app.thread != null) {
// 最后Service的onStartCommand将会被执行
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 启动Service,最终Service的onCreate会被执行
realStartServiceLocked(r, app, execInFg);
return null;
}
}
}
if (app == null && !permissionsReviewRequired) {
// 触发启动进程。
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
// 启动失败
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
...
// 将当前Service添加到待启动Service列表中。
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
...
return null;
}
- 如果Service所在进程存在,并且有效。那么直接调sendServiceArgsLocked启动,这里最终对应的是最后Service的onStartCommand将会被执行。这里的逻辑看起来比较奇怪。
- 重新通过进程名称在其获取一次ProcessRecord,如果存在且有效,则进入
realStartServiceLocked
函数。这里调用到了ApplicationThread的handleCreateService,最终Service的onCreate将被执行。 - 最后,如果都不满足。那么就
startProcessLocked
,并且将当前ServiceRecord加入到mPendingServices列表。当ActivityThread回调到attachApplication时,会真正的Service跑起来。
# 广播
是的,众所周知广播也是可以将应用唤起的。
// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
mService.updateCpuStats();
if (fromMsg) {
mBroadcastsScheduled = false;
}
// 获取广播记录(BroadcastRecord)过程,略。
...
// 这里是用户注册的广播,因此直接发送即可。不用考虑进程启动的事情。如果进程挂了也就拉倒吧。
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
...
return;
}
// 这是一个ResolveInfo,对应的是Manifest中注册的广播。
ResolveInfo info = (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
...
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
...
// 如果Manifest注册的Receiver对应的进程存活着,发送广播即可。
if (app != null && app.thread != null && !app.killed) {
try {
// 通知目标进程scheduleReceiver,此时目标进程中注册了的Receiver对象将被拉起。
processCurBroadcastLocked(r, app);
return;
}
...
}
// 启动进程。并且标记来自后台。
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) {
// 启动失败
return;
}
// 记录pendingBroadcast。这里并不是一个列表,只是一个变量
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
}
这里的广播是相对于Manifest而言,才会唤起进程的逻辑。
- 用户注册的广播:注册的receiver对应的是一个BroadcastFilter对象,直接发送即可。不用考虑进程启动的事情。如果进程挂了也就拉倒吧。
- Manifest注册进程:如果对应进程已经启动。那么通知目标进程scheduleReceiver,此时目标进程中注册了的Receiver对象将会在ActivityThread被实例化并回调onReceive函数。
- 最后,调用
startProcessLocked
启动静态广播对应的进程,并将当前的BroadcastRecord记录到mPendingBroadcast
中临时保存。等进程其中之后,会再次处理mPendingBroadcast。
# Provider
与上面都不同的是Provider对应进程被唤起之后,不用异步等待pending任务的回调。
原因在于,获取provider本身就是同步的调用。
下面来看看这一过程是怎么做的:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
// 通过name,即uri,拿到providerMap中对应的ContentProviderRecord
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
...
boolean checkCrossUser = true;
// mProviderMap为应用起来之后,自动将provider实例化,并注册到AMS中。
cpr = mProviderMap.getProviderByName(name, userId);
if (cpr == null && userId != UserHandle.USER_SYSTEM) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
...
}
// 运行中的provider,忽略。
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (!providerRunning) {
try {
// 调用PMS获取ProviderInfo,此处对应的是Manifest中注册的信息。
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
...
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
try {
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
}
...
// 检查provider是否正在被启动
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// 如果没有正在被启动,那么就需要从现在开始启动。
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
...
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
// 如果目标进程存在,并且正常存活。
// 但是此时attachApplication之后还没回调到子进程。
// 那么就不需要再次启动进程,只需要告知子进程provider。
// 需要优先install,而不用等到bindApplication后publish到AMS。
if (proc != null && proc.thread != null && !proc.killed) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
}
}
} else {
// 进程无效,那么startProcessLocked(重新)启动进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
// 启动失败,直接退出。
if (proc == null) {
return null;
}
}
cpr.launchingApp = proc;
// 添加进正在启动的provider列表
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
// 注册到缓存中去
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
synchronized (cpr) {
while (cpr.provider == null) {
// 一直等,直到进程启动完成,并且将当前进程的provider通过
// publishContentProviders注册到上面提到的providerMap中去。
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
简单分析provider的过程见上面的简略代码。
直接拉到最下面,当一个provider不存的时候。最后也会调用startProcessLocked
对进程的启动。
在最后会有一个while循环,一直等待ContentProviderRecord对应的provider参数(client)赋值,即子进程将Provider唤起install到AMS中。
启动进程
其实 startProcessLocked
更多的只是对启动参数的封装。生成ProcessReocrd,并缓存到列表中。
# startProcessLocked
startProcessLocked
函数如下:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
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) {
...
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
...
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
return (app.pid != 0) ? app : null;
}
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
...
try {
...
int debugFlags = 0;
// 如果applicatoinInfo包含DEBUGGABLE标志,那么会加上如下关于debug的标识位。在Zygote中会用到。
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
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)) {
// Enable all debug flags required by the native debugger.
debugFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
mNativeDebuggingApp = null;
}
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (new File(wrapperFileName).exists()) {
invokeWith = "/system/bin/logwrapper " + wrapperFileName;
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
app.gids = gids;
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
...
boolean isActivityProcess = (entryPoint == null);
// entryPoint默认为ActivityThread
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
// 如果是浏览器,WebView有专门对应WebViewZygote进程来孵化。这里不讨论了。
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
// 最终让ZygoteProcess通过socket同Zygote发送消息,
// 最后ZygoteInit执行ActivityThread的main函数。
// 这个过程省略,参考进程启动过程
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
...
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
// 监听启动进程是否超时,如超时则放弃。
// 见: processStartTimedOutLocked
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
PROC_START_TIMEOUT_WITH_WRAPPER为1200秒,20分钟。
而PROC_START_TIMEOUT则为10秒。
}
}
} catch (RuntimeException e) {
...
}
}
- 创建进程通过调用:Process.start进行启动。这里最终调用到了Zygote中间,fork出子进程。
- ZygoteInit的entrypoint则是在这里设定的,默认为
android.app.ActivityThread
- 如果是启动Activity则存在启动进程超时:默认PROC_START_TIMEOUT则为10秒。
# Zygote子进程
这里将ZygoteProcess到ZygoteInit->Zygote->RuntimeInit最后到ActivityThread的过程省略。
直接看ActivityThread的main函数:
// frameworks/base/core/java/android/app/ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 实例化ApplicationThread并将其Attach到AMS
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
// trigger:这里可以监控MessageQueue每次处理消息的耗时。
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
}
ActivityThread的main函数,实例化ActivityThread对象,并attach到AMS。
最后将创建的MainLooper进行loop,接收输入事件/VSYNC等将应用跑起来。
下面来看看attach做了什么:
// frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// 普通进程
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
// 第一次draw时会发送一个post消息回调到这里
ensureJitEnabled();
}
});
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
// 通知AMS进程已经启动
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// 监控GC,并适当情况下,释放当前的一些Activity实例。以满足内存要求
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// SystemServer进程
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
}
}
...
}
子进程调用mgr.attachApplication(mAppThread);
,将自己的ApplicationThread注册到AMS。之后AMS可以通过这个binder实现对ActivityThread的调用。
回调到AMS
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
}
这里如果找不到ProcessRecord,很有可能是启动进程超时。被被销毁了。
if (app == null) {
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
} else {
thread.scheduleExit();
}
return false;
}
...
final String processName = app.processName;
try {
// 监控ApplicatoinThread的binder死亡消息
// 即监控应用进程的死亡。
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
}
...
app.makeActive(thread, mProcessStats);
...
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
...
try {
...
ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
...
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
} else {
// 通知进程启动Application
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
LRU策略更新ProcessRecord在mLruProcesses的位置。
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
return false;
}
mProcessesOnHold.remove(app);
boolean badApp = false;
boolean didSomething = false;
// 查看是否有需要启动的Activity
if (normalMode) {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
}
// 查看是否有需要启动的Service
if (!badApp) {
didSomething |= mServices.attachApplicationLocked(app, processName);
}
// 查看是否有广播需要处理
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
didSomething |= sendPendingBroadcastsLocked(app);
}
// 查看是否有需要启动的备份消息
if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
mBackupTarget.backupMode);
}
}
...
return true;
}
- 启动超时
如果启动进程超时,那么ProcessRecord会被清除。此时这个进程将会被劝退。
具体逻辑看startProcessRecord时发送的PROC_START_TIMEOUT_MSG
消息。
- 监听死亡
通过Binder的death消息,监控子进程的生命周期。
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService$AppDeathRecipient.java
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
...
@Override
public void binderDied() {
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
具体见appDiedLocked
函数。
- bindApplication:
调用applicationThread的bindApplication,通知子进程启动Application。
这一步主要是三件事:
创建baseContext
实例化Applicatoin
实例化所有provider并publish回AMS
By @hyongbai 共23962个字 本文链接 http://yourbay.me/all-about-tech/2019/08/23/android-8.0-startApplication/