根据《Activity跨进程启动流程源码探究》我们可以清楚以下几点:
1)Context的通用实现是在ContextIml这个类中
2)Activity的启动过程需要借助ActivityManagerService(AMS)这个服务端来完成,其本质是借助于Binder通信。目标Activity的识别是通过ProcessRecord这个类存储的记录来完成的,如果首次启动进程,则通过提取Intent中携带进程信息完成启动。
3)Context作为客户端向AMS发起start请求,AMS持有IApplicationThread的实例完成最终的启动任务。
4)AMS通过H这个Handler切回了主线程。Application、Activity、ContextImpl等实例创建都在主线程中,那些耗时操作其实是在Binder线程完成的。
鉴于此,我们分析Service的启动过程从ContextImpl的startService方法开始。
1. 客户端发起启动service请求
ContextImpl中通过startService、startForegroundService、startServiceAsUser、startForegroundServiceAsUser四个方法启动服务,但是他们都把具体任务交给了startServiceCommon这个方法,下面给出startService的源码:
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
看一下startServiceCommon的核心代码吧,
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
跟启动Activity一样,它把任务交给了ActivityManager.getService(),也就是ActivityManagerService,AMS则是IActivityManager.Stub的具体实现,这么一来系统会单独开辟一个Binder线程完成服务的启动工作。
接着,我们看看AMS的启动情况,核心代码如下:
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
}
它调用了mServices的startServiceLocked方法,mServices就是ActiveServices,startServiceLocked返回了组件名ComponentName,并未执行启动工作,service参数就是我们启动时传入的Intent。通过它可以拿到目标服务的记录ServiceRecord,核心代码如下:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null ? res.permission : "private to package");
}
ServiceRecord r = res.record;
......
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
startServiceLocked通过调用retrieveServiceLocked方法获得服务记录信息存储在ServiceRecord的实例r中,r参数又传给了startServiceInnerLocked做进一步启动工作。
这里需要注意的是retrieveServiceLocked方法内部无法查询到目标进程的ServiceRecord的信息,因为我们假设目标进程还未启动。res.record是通过客户端源进程携带的模板进程信息封装的实例。
继续追踪会发现startServiceInnerLocked内部调用了bringUpServiceLocked方法,从字面意思就明白它是唤起Service的,该方法实现如下:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) { //代码1-b-1
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); //代码1-b-2
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
......
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null && !permissionsReviewRequired) { //代码1-b-3
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
...
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
...
return null;
}
由于我们分析的是目标进程未启动的开启服务流程,代码1-b-1处r.app返回的ProcessRecord实例和代码1-b-1返回的ProcessRecord实例都是空的,代码1-b-3的开启目标进程逻辑会被执行,它通过调用mAm.startProcessLocked方法执行开启进程任务,mAm就是AMS。procName、r.appInfo、r.name均取自于我们刚刚创建的ServiceRecord实例,其中r.appInfo存储了我们要启动的目标应用的所有信息,它是ApplicationInfo的实例。startProcessLocked连续调用2次其重载方法,第1次调用获取ProcessRecord实例,核心代码如下:
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) {
...
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge); // 代码1-start-1
checkTime(startTime, "startProcess: after getProcessRecord");
...
} else {
// If this is an isolated process, it can't re-use an existing process.
app = null;
}
...
if (app == null) {
checkTime(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);// 代码1-start-2
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 {
...
}
...
startProcessLocked( // 代码1-start-3
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
return (app.pid != 0) ? app : null;
}
可见,该方法首先在代码1-start-1处调用getProcessRecordLocked方法查询正在运行的进程中是否有相关记录,进入该方法代码如下:
final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
if (uid == SYSTEM_UID) {
...
}
ProcessRecord proc = mProcessNames.get(processName, uid);
...
return proc;
}
该方法就是通过进程名和用户ID从mProcessNames获取进程记录,mProcessNames的定义如下:
/**
* All of the applications we currently have running organized by name.
* The keys are strings of the application package name (as
* returned by the package manager), and the keys are ApplicationRecord
* objects.
*/
final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
所有正在运行的应用的进程记录都在这儿,由于我们的目标应用及其进程都还没启动,getProcessRecordLocked方法自然返回null。startProcessLocked方法执行1-start-2逻辑,调用newProcessRecordLocked方法创建了一个新的ProcessRecord实例。看一下该方法的实现逻辑:
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
boolean isolated, int isolatedUid) {
String proc = customProcess != null ? customProcess : info.processName;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
int uid = info.uid;
if (isolated) {
...
}
final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
...
addProcessNameLocked(r);
return r;
}
其内部实现特别干脆,直接将ApplicationInfo信息和进程名传入ProcessRecord构造方法,new了一个ProcessRecord实例返回。
函数startProcessLocked方法接着执行代码1-start-3逻辑,再次调用自己的重载方法,ProcessRecord实例作为其第一个参数传入,然后执行Process.start方法开启目标进程,核心代码如下:
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
......
try {
......
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
...
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
} catch (RuntimeException e) {
Slog.e(TAG, "Failure starting process " + app.processName, e);
...
}
}
我们要开启的是进程不是WebView服务,自然会调用Process.start方法,注意:app就是我们传入的ProcessRecord参数,启动目标进程全靠它了。entryPoint就是目标进程的主线程ActivityThread,一旦目标进程开启,首先执行ActivityThread的main方法。在ActivityThread.main方法内部,创建了目标进程主线程的mainLooper、mainHandler并将具体任务交给了ActivityThread.attach方法,在attach方法内部又将任务交给了AMS的attachApplication方法,核心代码如下:
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
...
}
// Watch for getting close to heap limit.
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)) {
...
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
...
}
}
}
});
} else {
...
}
......
}
by the way,当我们申请的内存大于最大允许内存的75%时,就会触发系统的内存回收机制。接下来我们看看mgr.attachApplication方法做了什么,这里的mgr就是AMS实例。它的内部调用了AMS的attachApplicationLocked方法,并将当前进程的ApplicationThread实例传入。attachApplicationLocked的具体实现如下:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// 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.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid); // 代码1-aal-1
}
} else {
app = null;
}
...
try {
...
// Check if this is a secondary process that should be incorporated into some
// currently active instrumentation. (Note we do this AFTER all of the profiling
// stuff above because profiling can currently happen only in the primary
// instrumentation process.)
if (mActiveInstrumentation.size() > 0 && app.instr == null) { // 代码1-aal-2-1
for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
if (aInstr.mTargetProcesses.length == 0) {
// This is the wildcard mode, where every process brought up for
// the target instrumentation should be included.
if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
app.instr = aInstr;
...
}
} else {
for (String proc : aInstr.mTargetProcesses) {
if (proc.equals(app.processName)) {
app.instr = aInstr;
....
break;
}
}
}
}
}
}
...
if (app.instr != null) { // 代码1-aal-2-2
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 { // 代码1-aal-3
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);
}
...
} catch (Exception e) {
...
startProcessLocked(app, "bind fail", processName);
return false;
}
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName); // 代码1-aal-4
...
} catch (Exception e) {
...
}
}
...
return true;
}
代码1-aal-1处的mPidsSelfLocked就是当前已经运行的目标应用中的所有进程信息,其定义如下:
/**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
* <p>NOTE: This object is protected by its own lock, NOT the global
* activity manager lock!
*/
final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
可见它是一个SparseArray内部以pid为键值存储,由于进程已经启动,通过mPidsSelfLocked.get(pid)就可拿到对应的ProcessRecord记录信息。
由于目标进程的Instrumentation还未创建,代码1-aal-2-1和代码1-aal-2-2处的条件都不满足,代码1-aal-3处逻辑开始执行。thread.bindApplication方法会完成创建Instrumentation、ContextImpl、Application、ContentProvider的任务,详细请参考《ContentProvider注册、启动流程源码解析》。
接着,代码1-aal-4逻辑被执行,mServices.attachApplicationLocked内部会调用一个叫做realStartServiceLocked方法,调用核心代码如下:
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
...
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
...
}
} catch (RemoteException e) {
....
}
}
......
return didSomething;
}
其中,mPendingServices是一个列表,存储了目标进程所有将要被启动的服务记录,其定义如下:
/**
* List of services that we have been asked to start,
* but haven't yet been able to. It is used to hold start requests
* while waiting for their corresponding application thread to get
* going.
*/
final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();
我们根据processName和proc.uid拿到目标ServiceRecord赋值给sr,将sr和proc作为参数传给realStartServiceLocked完成真正的服务启动工作。其中proc是ProcessRecord(Full information about a particular process that is currently running. 译文:当前正在运行的进程的所有信息。它内部存储了自己的Activity集合、Service集合等)的实例,sr是ServiceRecord(A running application service.译文:一个正在运行应用服务)的实例。realStartServiceLocked方法的具体实现如下:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
...
r.app = app;
...
boolean created = false;
try {
...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState); // 1-0
...
created = true;
} catch (DeadObjectException e) {
...
} finally {
if (!created) {
...
}
}
...
sendServiceArgsLocked(r, execInFg, true); // 1-1
...
}
其核心实现只有1-0和1-1两处,1-0处调用了app.thread.scheduleCreateService方法。这里的app.thread就是IApplicationThread,依赖这个引用调用目标进程主线程的scheduleCreateService接口创建服务实例。
2. 目标进程创建service实例
ActivityThread.ApplicationThread这个服务端通过scheduleCreateService这个方法完成了创建Service数据初始化和切换主线程这两个任务,代码如下:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
感兴趣的话,可以进入CreateServiceData看一下,你应该能学到些什么。
3. Service的创建任务
Service的创建任务通过H.CREATE_SERVICE这个消息切换给了主线程来完成。通过fn+option+F7可以在handleMessage内部找到该消息对应的处理方法handleCreateService:
public void handleMessage(Message msg) {
switch (msg.what) {
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj);
break;
}
...
}
// handleCreateService实现
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
// 3-0 通过ClassLoader创建Service实例
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
...
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
// 3-1 通过createAppContext方法创建ContextImpl实例
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
// 3-2 通过makeApplication方法创建Application实例,内部会调用Application的onCreate方法,
// mInstrumentation在刚刚的bindApplication方法中已经创建过
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 3-3 通过attach方法将Service与Context关联起来
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 3-4 调用Service的onCreate方法。
service.onCreate();
...
} catch (Exception e) {
...
}
}
在主线程中,依次执行如下步骤:
1)通过ClassLoader类加载器创建Service实例
2)通过createAppContext方法创建ContextImpl实例
3)通过makeApplication方法创建Application实例,内部会调用Application的onCreate方法
4)通过attach方法将Service与Context关联起来
5)调用Service的onCreate方法。
3. Service的onStartCommand任务
Service的启动周期,当然代码要执行到onStartCommand才能处于暂态,这时需要回到第1节源进程 客户端ActiveServices#realStartServiceLocked方法的1-1处,它调用了ActiveServices#sendServiceArgsLocked方法,该方法核心代码如下:
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
...
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take care of this.
...
} catch (Exception e) {
...
}
...
}
它会首先检测是否有等待启动的服务,如果没有就返回。否则,就调用r.app.thread.scheduleServiceArgs方法并传入ServiceRecord信息。同样,这里的r.app.thread就是IApplicationThread的具体实现ActivityThread.ApplicationThread,看一下代码:
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
ServiceStartArgs ssa = list.get(i);
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = ssa.taskRemoved;
s.startId = ssa.startId;
s.flags = ssa.flags;
s.args = ssa.args;
sendMessage(H.SERVICE_ARGS, s);
}
}
在IApplicationThread这个Binder线程中完成了初始化和切换主线程两个任务,搜索H.SERVICE_ARGS这条消息会找到handleMessage中的handleServiceArgs方法,该方法实现相对于handleCreateService简单了不少,如下:
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId); //代码3-0
} else {
...
}
...
} catch (Exception e) {
...
}
}
}
我们想看到的代码只有一行,代码3-0处的s.onStartCommand方法的调用。这样整个服务的启动工作就完成了,做一下总结吧~
4. Service的启动总结
首先,Context通过startService调用ContextImpl的startService方法,ContextImpl作为客户端,或者叫Binder代理向AMS(ActivityManagerService)发起start service的请求
接着,AMS这个服务端,或者叫做Binder.Stub存根的派生类,通过桥接的方式,先调用thread.bindApplication方法创建Instrumentation实例、App实例、安装ContentProvider等进行 模板进程 Application 初始化工作。
然后,AMS 继续通过目标进程的IApplicationThread引用执行createService任务,并借助于H在目标进程完成切回到主线程处理CREATE_SERVICE消息工作。该消息对应的handleCreateService方法依次完成如下任务:
4-1 获取Service实例创建的必备信息
4-2 创建ContextImpl实例
4-3 通过ClassLoader创建Service实例
4-4 通过LoadedApk的makeApplication方法,最终由classLoader创建Application实例。其内部还调用了instrumentation.callApplicationOnCreate()方法
4-5 通过Service的attach方法,将Service和ContextImpl关联起来,有一个叫mBase的Context实例其实就是ContextImpl。
4-6 调用 service.onCreate()方法,可见从源码上决定了Application的onCreate方法先于Service的onCreate方法执行。
一言以蔽之,就是创建service实例并调用onCreate方法。
最终,在这些工作完成后,源进程客户端调用了app.thread.scheduleServiceArgs方法,在ActivityThread.ApplicationThread这个Binder进程中,通过H.SERVICE_ARGS切换到主线程,该消息对应的handleServiceArgs被执行,在handleServiceArgs方法中完成Service#onStartCommand的调用任务。
这样服务就启动起来了。
诗云: