在Android开发中,对于应用开发者来说,通过Context的startService来启动一个服务的方法再熟悉不过了,那么startService到底是怎么启动一个Service的呢?这里为了直观的分析流程,就从startService方法开始。
一、Service启动流程总结
本来启动流程的总结应该放在最后,这里为了便于以后阅读时更清析,把两张总结图放在前面。下面这张图相对比较抽象。
再来看一张具体的流程图
二、启动流程及原理详细分析
通常我们在Activity、Application等地方调用的startService()方法,根据Context的类继承关系,实际上是在ContextImpl中实现的startService方法,如下
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
//核心方法
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
...
//拿到AMS的binder对象,调用AMS中的startService方法
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
return cn;
}
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
...
synchronized (this) {
...
//核心步骤
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, userId);
return res;
}
}
//继续跟进
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
...
//根据intent查询到service的ServiceRecord对象
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
callingPid, callingUid, userId, true, callerFg);
...
ServiceRecord r = res.record;
...
//用作之后准备调用startCommand用
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
...
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
到这里了,我们重点看一下startServiceInnerLocked(),最终会调用到ActivityService中的bringUpServiceLocked()方法。
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
//service所在进程已经启动,且进程已经和AMS互相绑定
if (r.app != null && r.app.thread != null) {
//Service中onStartCommand的调用地方
sendServiceArgsLocked(r, execInFg, false);
return null;
}
//Service所在进程已经启动,但Service还没有启动
ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
//真正启动Service
//调用Service的onCreate方法与onStartCommand()方法
realStartServiceLocked(r, app, execInFg);
}
//Service所在进程没有启动的情况
if (app == null) {
//启动进程
app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)
}
...
//添加到列表中,等进程启动完之后再来处理service的启动。
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
...
return null;
}
上面代码块中启动Service所在进程的方法可以参考前面应用程序进程启动流程分析,逻辑是一样的。
下面继续跟进一步realStartService()方法,看看具体是怎么实现的,还是在ActivityService中
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
//这里的ServiceRecord实际上是binder对象
r.app = app;
...
//AMS向应用端发起IPC调用,当应用端收到消息之后就会创建Service,执行Service里面的onCreate().
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
//触发onStartCommand()方法
sendServiceArgsLocked(r, execInFg, true);
}
从上面这段围代码我们知道,当AMS向应用端发起IPC调用创建Service并调用onCreate(),那么当应用端收到这个IPC消息之后,到底是如何创建Service并调用onCreate()方法的呢?在我们熟悉的ActivityThread类中
private void handleCreateService(CreateServiceData data) {
...
//获取到Service的相关信息,比如packageName, className等
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//通过LoadedApk的ClassLoader加载出来Service的实例对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
...
//创建该Service所需要的上下文
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//创建Application,实际上是应用程序启动的时候Application就已经创建好了,这里直接返回创建好的
Application app = packageInfo.makeApplication(false, mInstrumentation);
//调用Service中的attach()方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//Service的onCreate()方法调用
service.onCreate();
mServices.put(data.token, service);
}
从上面的注释已经很清楚的知道Service是如何创建,以及生命周期方法attach()、onCreate()的调用。我们知道Service中还有一个重要的方法onStartCommand(),这个方法是在我们每次startService的时候都会回调一次,那这个方法到底是怎么调用起来的呢?其实从上面代码中已经出现过,就是在ActivityService中执行了realStartServiceLocked()函数中调用的sendServiceArgsLocked()函数,看看这个函数是如何实现的
private final void sendServiceArgsLocked(ServiceRecord r,...) {
while(r.pendingStarts.size() > 0) {
StartItem si = r.pendingStarts.remove(0);
...
//通过binder对象调用到应用端ActivityThread中的scheduleServiceArgs()
r.app.thread.scheduleServiceArgs(r, ...);
}
}
//在ActivityThread中
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags, Intent args) {
ServiceArgsData s = new ServiceArgsData();
...
//发送到主线程消息队列
sendMessage(H.SERVICE_ARGS, s);
}
//处理消息的函数
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
...
//onStartCommand()终于被调用了,从前面通过发送Message到主线程消息队列
//我们知道onStartCommand()是在主线程中调用的,因此是不处理耗时操作
res = s.onStartCommand(data.args, data.flags, data.startId);
...
}
}
到这里,Service的启动流程就讲完了。