本文是《Android进阶解密》的读书笔记。所以,可能不会为大家提供多少帮助,我写本文的目的只是为了自己再学习的时候能够有个印象,为自己提供一个方便。
Service的启动过程分为两个部分,分别是ContextImpl到ActivityManagerService的调用过程和ActivityThread启动Service的过程。
一、ContextImpl到ActivityManagerService的调用过程
我们在Activity中启动Service首先调用startService方法,它在ContextWrapper类中实现,其方法体中仅有一行代码:
@Override public ComponentName startService(Intent service) { return mBase.startService(service); }
现在看一下Context类型的mBase对象指的是什么。在ActivityThread启动Activity的过程中,在ActivityThread的performLaunchActivity方法中调用了createBaseContextForActivity方法创建了ContextImpl类型的上下文对象。然后将创建的上下文对象AppContext传递到了app.attach方法中。看一下createBaseContextForActivity方法中做了什么处理。代码如下:
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
// 代码省略。。。
// 调用createActivityContext创建上下文对象
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
// 代码省略。。。
return appContext;
}
由此可以看到,传入到activity.attach方法中的appContext对象是ContextImpl类型的。在Activity类中attach方法内调用了ContextWrapper类的attachBaseContext方法。该方法代码如下:
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
// 将传递进来的ContextImpl(继承自Context)类型的base对象赋值给了mBase变量
mBase = base;
}
因此,mBase具体指代的就是ContextImpl。因此我们的启动Service的过程就是从ContextImpl类开始的。代码如下:
@Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); // 调用了startServiceCommon方法 return startServiceCommon(service, false, mUser); }
代码中可以看出ContextImpl.startService方法中返回了startServiceCommon方法。现在看一下这个方法中做了什么操作。
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
// 代码省略。。。
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
该方法中出现了我们熟悉的ActivityManager.getService().startService(....);代码,熟悉Activity启动过程的应该知道,其实这句代码就会调用到ActivityManagerService中的startService方法。至此,ContextImpl到AMS的调用过程就结束了。其时序图如下:
二、ActivityThread启动Service的过程
经过上一过程,代码逻辑执行到了AMS的startService方法。该方法中调用了ActiveServices的startServiceLocked方法。其代码如下:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
// 代码省略。。。
// 注释1:查找是否有与参数service对应的ServiceRecord
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");
}
// 注释2:得到参数service对应的ServiceRecord
ServiceRecord r = res.record;
// 代码省略。。。。
// 注释3
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
注释1处,调用了retrieveServiceLocked方法,其作用是查找是否有与参数service对应的ServiceRecord。其代码实现如下:
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
if (r == null) {
try {
// 注释1:
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId, callingUid);
// 注释2
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
}
if (r != null) {
// 代码省略。。。
// 注释3
return new ServiceLookupResult(r, null);
}
return null;
}
注释1处,最终会调用到PackageManagerService去获取参数service对应的Service信息。注释2处,将第一步获取到的与参数service对应的Service信息封装到ServiceRecord。注释3处,将ServiceRecord以ServiceLookupResult对象的形式返回到ActiveServices的startServiceLocked方法中。startServiceLocked方法的注释2处,通过注释1处返回的ServiceLookupResult得到参数service对应的ServiceRecord,并将其传入到注释3处的startServiceInnerLocked方法。该方法的代码主要就是调用了bringUpServiceLocked方法,这里就不再展示。直接看一下bringUpServiceLocked方法的代码:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 代码省略。。。
// 注释1
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
// 注释2
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
// 注释3
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 注释4
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
// 。。。。
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
// 注释5
if (app == null && !permissionsReviewRequired) {
// 注释6
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 (isolated) {
r.isolatedProc = app;
}
}
// 。。。。
return null;
}
注释1处,得到ServiceRecord的processName值并赋给procName,其中processName用来描述Service想要在哪个进程中运行,默认是当前进程。注释2处,将procName和Service的uid传入到AMS的getProcessRecordLocked方法中,查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来描述运行的应用程序进程的信息。注释3处的判断表示用来运行Service的应用程序进程存在,此时就会调用注释4处的realStartServiceLocked方法。注释5处的判断表明Service对应的应用程序进程还没有创建,此时便会去调用注释6处的代码。注释6处调用的是AMS的startProcessLocked方法去创建Service对应的应用程序进程。现在我们接着看一下注释4处的realStartServiceLocked方法,其代码如下:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// 注释1
if (app.thread == null) {
throw new RemoteException();
}
try {
// 注释2
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
// 代码省略。。。
}
// 代码省略。。。
}
该方法代码有点多,但是我们需要看的只有两处。注释1,需要注意一下,此时如果Service对应的应用程序进程还未创建就会抛出异常。注释2处,调用了app.thread的scheduleCreateService方法。而app.thread是IApplicationThread类型的,它的实现时ActivityThread的内部类ApplicationThread。该方法代码如下:
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);
}
该方法将启动Service需要的信息封装成了CreateServiceData,通过sendMessage方法向H类发送了一条CREATE_SERVICE的信息。我们直接看H类的handleMessage方法中对CREATE_SERVICE的处理:
private class H extends Handler {
// 代码省略。。。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
// 省略代码。。。
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
// 调用了handleCreateService方法
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
对CREATE_SERVICE的处理就是调用了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();
// 注释1
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 注释2
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
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 注释4
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 注释5
service.onCreate();
// 注释6
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
// 。。。
}
}
该方法做了如上的一些内容。注释1,获取要启动的Service的应用程序的LoadedApk。注释2处,获取类加载器,并根据类加载器来创建Service实例。注释3处,创建Service的上下文环境ContextImpl对象。注释4处,调用service的attach方法来初始化Service,并且将上一步创建的ContextImpl对象context传递进去。Service的该方法中调用了ContextWrapper的attachBaseContext方法,将参数context赋值给了mBase。注释5处调用了service的onCreate生命周期方法,这样Service就启动了。注释6处,将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是以IBinder为key以Service为value的ArrayMap集合。
至此,Service的启动过程就学习完了,最后附上这一过程的时序图就结束本文了。
至此文章就结束了,在这里非常感谢《Android进阶解密》一书的作者。