ActivityManagerService服务负责管理Service服务,下面通过Service服务的启动流程来分析下AMS是如何管理Service服务的
Service的启动方式有两种:
1:startService
2:bindService
startService分析
我们要启动一个Service服务一般都是在Activity类中直接调用startService(Intent)来启动,而Activity类中并没有相关的方法,我们知道Activity继承自ContextWrapper,ContextWrapper类中的startService方法直接调用了ContextImpl的startService方法。
Service的可以在当前的进程中启动,也可以在新的进程中启动。在新的进程中启动的逻辑和前面分析的Activity的启动流程类似,所以此处我们仅仅分析在当前进程中启动Service的情况。
我们分析Service的启动流程首先从ContextImpl的startService方法开始分析。
1. ContextImpl.StartService
public ComponentName startService(Intent service) {
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess();
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
return cn;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
StartService调用了startServiceCommon方法来启动Service,在startServiceCommon方法中通过进程间通信请求,调用了AMS服务的startService方法。以上代码在应用进程中。通过进程间调用,下面代码逻辑进入系统服务进程中。
2. AMS.startService
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
……
synchronized(this) {
//获取调用进程的UID和PID
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
//调用startServiceLocked来继续处理service启动的逻辑
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
这个方法处理也是比较简单,获取调用者的Uid和Pid,调用ActiveService的startServiceLocked方法来继续处理Service启动的逻辑。
3. ActiveService.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, int userId)
throws TransactionTooLargeException {
//获取调用程序的进程信息
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
……
}
//调用要启动的service的Intent信息,在PMS服务中查找对应的service,并将它封装在一个ServiceLookupResult对象中
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg);
//得到要启动service的ServiceRecord信息
ServiceRecord r = res.record;
final ServiceMap smap = getServiceMap(r.userId);
……
//调用startServiceInnerLocked方法继续启动service服务
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
在AMS服务中,每个Service都使用一个ServiceRecord对象来描述,就像Activity一样,每个Activity都用一个ActivityRecord对象描述。然后调用retrieveServiceLocked方法来查找一个和目标Service对应的ServiceRecord,最后将这个ServiceRecord对象封装在ServiceLookupResult对象中。
最后条用startServiceInnerLocked方法来继续启动目标Service
下面在了解下retrieveServiceLocked方法的处理逻辑。
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null;
//获取当前的用户ID
userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
false, ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
找到该用户下的保存Service的集合ServiceMap
ServiceMap smap = getServiceMap(userId);
final ComponentName comp = service.getComponent();
//根据component信息从ServiceMap中查找
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
//根据IntentFilter信息从ServiceMap中查找
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
//如果ServiceMap中没有找到目标Service的ServiceRecord信息,则从PMS中查找并创建一个ServiceRecord对象,然后保存到ServiceMap中
if (r == null) {
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveService(
service, resolvedType,
ActivityManagerService.STOCK_PM_FLAGS, userId);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
……
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
}
……
return null;
}
retrieveServiceLocked方法用来查找目标Service的ServiceRecord对象,首先从AMS服务中的ServiceMap中查找,ServiceMap中保存了AMS服务中所有激活的Service信息,如果在ServiceMap中没有找到,说明该Service还没有启动。那么就需要从PMS服务中查找目标Service的信息并创建一个ServiceRecord对象。最后把他保存在对应的ServiceMap集合中。
接着看startServiceInnerLocked方法,该方法中处理逻辑直接较简单,直接调用了bringUpServiceLocked方法来处理。
4. ActiveService. bringUpServiceLocked
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
final String procName = r.processName;
ProcessRecord app;
//判断目标Service所在的进程是否已经存在,如果已经存在则直接调用目标进程启动Service
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);
realStartServiceLocked(r, app, execInFg);
return null;
}
……
}
//如果目标进程不存在,则需要先创建目标进程,然后再创建Service
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
……
}
这个方法首先根据目标Serivce的进程信息,来查询对应的进程是否存在,如果对应的目标进程已经存在,则通过通知目标进程来启动Service,如果目标进程还没有创建,则电泳AMS服务的startProcessLocked方法启动一个目标进程,然后在启动service。启动目标进程的方法和Activity中启动目标进程的方法类似,此处不再分析。
我们分析在同一个进程中启动Service的逻辑,目标进程肯定已经存在了,不需要新创建进程,所以直接调用realStartServiceLocked方法来启动service服务。
5. ActiveService.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
……
//将即将要启动ServiceRecord和一个进程关联起来
r.app = app;
boolean created = false;
try {
……
//通过进程间通信请求,调用目标进程的scheduleCreateService方法创建一个Service服务
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
}
……
}
将即将要启动的ServiceRecord r的成员变量设置为ProcessRecord对象app,表示这个ServiceRecord对象锁描述的Service组件是在app所描述的进程中启动运行的。
在Activity的启动过程中描述过:ProcessRecord的成员变量thread是一个ApplicationThreadProxy的binder代理对象,它指向了应用程序进程中一个Applicationthread的binder服务端对象。因此可以通过thread进行进程间通信请求,调用binder服务端ApplicationThread的scheduleCreateService来创建Service。
同样,ApplicationThread接收到请求后,最终发送消息CREATE_SERVICE由Hander来处理,Handler的handleMessage又调用了ActivityThread的handleCreateService方法来处理。
6. ActivityThread.handleCreateService
private void handleCreateService(CreateServiceData data) {
//获取当前应用程序的LoadedApk对象
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//使用当前应用程序的类加载器加载目标service,并创建它的一个对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
……
}
try {
//创建并初始化Context对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//创建一个Application对象,用来描述service所在的应用程序信息
Application app = packageInfo.makeApplication(false, mInstrumentation);
//使用上面的信息初始化刚创建的service对象
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//调用service的onCreate方法
service.onCreate();
//最后将servcie保存在ActivityThread的mServices变量中。
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} ……
}
第一步:在该方法中首先获得一个LoadedAPK对象,在之前我们曾经分析过,LoadedApk主要用来描述进程中所加载的一个应用程序,里面保存了应用程序的资源路径等信息。
第二步:使用LoadedApk对象中保存的ClassLoader来加载目标Service类到内存中,并创建一个目标Service的对象。
第三步,创建ContextImpl对象,并初始化,用来当做Service对象的上下文信息,Service对象就可以通过它来访问程序的资源和方法。
第四步,创建一个Application对象,用来描述Service所在应用程序的信息。
第五步,用上面创建的信息,context,Application等信息来初始化刚创建的service对象。
第六步,service对象初始化完成后就调用了它的onCreate方法。这样Service服务就基本上启动起来了