Service启动方式追踪
前言
在安卓开发过程中我们除了Activity之外最常用的组件就是Service,特别是在和用户没有界面交互的终端设备中更是常见,那么Service作为安卓四大组件之一是如何运作的?
我们一般使用Service有两种方式,startService和bindService,这两种方法使用场景各有不同,下面我们从startService来分析Service完整的运作过程。
图1 .启动 流程什么是ContextImpl
首先给出如下一张XML表认识ContextImpl
图2. 类图
从上面这张图我们可以看到Activity继承了ContextWrapper类,而在ContextWrapper类中,实现了startService方法。在ContextWrapper类中,有一个成员变量mBase,它是一个ContextImpl实例,而ContextImpl类和ContextWrapper类一样继承于Context类。
我们在代码中通过startService(Intent service)来启动一个服务,调用的方法是:
//ContextWrapper类
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
可以看出ContextWrapper类的startService方法最终是通过调用ContextImpl类的startService方法来实现的。继续追踪ContextImpl.startService() :
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里通过 startService——>startServiceCommon,然后在startServiceCommon里通过ActivityManagerNative.getDefault()返回的就是一个ActivityManagerProxy对象,这里使用Binder机制将代理Proxy返回给客户端,而客户端通过将参数写入Proxy类,接着Proxy就会通过Binder去远程调用服务端的具体方法,因此,我们只是借用ActivityManagerProxy来调用ActivityManagerService的方法。所以这里其实是调用了远程ActivityManagerService的startService方法。
到这里就解释完了图1中Service启动过程Activity所在线程所做的操作。接下来我们就看看ActivityManagerService是如何实现的。
AMS如何进一步启动Service
查看ActivityManagerService中的源码:
//ActivityManagerService类
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
//...
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
调用mService的startServiceLocked方法,那mService是干嘛的呢?此处的mServices是一个ActiveServices对象,从名字上也能看出该类主要是封装了一些处于活动状态的service组件的方法的调用。那接下来就看看他的startServiceLocked是如何实现的。
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
//...
final boolean callerFg;
if (caller != null) {
//mAm 是ActivityManagerService.
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
} else {
callerFg = true;
}
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType,
callingPid, callingUid, userId, true, callerFg);
if (res == null) {
return null;
}
if (res.record == null) {//权限拒绝.
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
//
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
//...
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
最重要的逻辑在于最后一句的startServiceInnerLocked方法,他的内部实现是这样的。
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
ServiceRecord r, boolean callerFg, boolean addToStarting) {
//...
//真正开启service的地方。
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
//注意此处反回值是null的时候,证明没有异常.
if (error != null) {
return new ComponentName("!!", error);
}
//...
return r.name;
}
startServiceInnerLocked方法内部调用了bringUpServiceLocked方法来进行后续的启动。
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
//...
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
}
//...
return null;
}
在bringUpServiceLocked方法中调用了realStartServiceLocked方法,在Activity的启动过程中我们也曾看过相似的方法,说明到了这里我们也快看到真正的Service启动了,接着来看realStartServiceLocked。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//...
boolean created = false;
try {
//...
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
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;
}
//这里会调用Service的onStartCommand,注意后文要用到
sendServiceArgsLocked(r, execInFg, true);
//...
}
这里需要对上面的app.thread做一下特殊的说明。如果你已经了解了Binder的通信机制,那你应该知道一般我们的服务都是由客户端向服务端发出请求,接着服务端向客户端返回结果,这个是单向的通信,但是如果反过来服务端要向客户端发送请求的话,那么同样的,在服务端也应该持有另外一个Proxy,而在客户端也同样需要一个Manager与之对应。
在这里app是要运行 Service 的进程对应的ProcessRecord对象,代表一个应用进程,而thread是一个ApplicationThreadProxy对象,它运行在AMS(现在AMS就是客户端了),而与之对应的服务端则是在应用程序中的ApplicatonThread,还是有点绕,我们用一张图来展示他们的关系。
图3. 应用程序进程与系统服务进程之间的双向通信ApplicationThread与ApplicationThreadProxy
public interface IApplicationThread extends IInterface```
IApplicationThread其实是一个IBinder类型的接口。并且在这个接口中声明了许多与Activity,Service生命周期相关的方法,那么它的实现类又是谁呢?答案就是ApplicationThreadNative。
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread
private class ApplicationThread extends ApplicationThreadNative
ApplicationThread就是真正意义上的服务端,它的父类ApplicationThreadNative就是将具体的操作将给它来执行的。
class ApplicationThreadProxy implements IApplicationThread
在客户端运行的ApplicationThreadProxy在哪里呢?其实如果理解了Binder机制,那么我们应该知道他就是ApplicationThreadNative的内部类,客户端(AMS)就是通过它与service所在的进程进行通信的。因此我们接着要看的当然是ApplicationThread的scheduleCreateService了
#### ApplicationThread.scheduleCreateService
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);
}
可以看到在scheduleCreateService方法中发送了一个message,其消息类型为CREATE_SERVICE,它是在H类中定义的一个常量,而H类其实就是继承于Handler的,它专门用来处理发送过来的请求。接下来就来看看它是如何处理创建service这个消息的。
#### H.handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj); //【见流程15】
break;
case BIND_SERVICE:
handleBindService((BindServiceData)msg.obj);
break;
case UNBIND_SERVICE:
handleUnbindService((BindServiceData)msg.obj);
break;
...
}
}
可以看到handleMessage处理了很多类型的消息,包括service的创建、绑定、解绑、销毁等等,我们直接看创建的逻辑,也就是handleCreateService方法。不过有一个问题,那就是Handler创建之前必须要创建Looper,否则会报错,那么Looper是在哪里创建的呢?答案就是ActivityThread的main方法。
public static void main(String[] args) {
//...
//在主线程创建Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们可以看到Looper就是在这里创建的,而Handler也是在Service进程中的主线程,也就是说它处理消息也是在主线程,那么Service的创建自然也就是在主线程中。可是ActivityThread是什么鬼呢?其实刚才的ApplicationThread就是它的内部类。
接下来继续看Handler如何处理消息。
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//通过反射创建目标服务对象
Service service = (Service) cl.loadClass(data.info.name).newInstance();
...
try {
//创建ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//创建Application对象
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//调用服务onCreate()方法
service.onCreate();
mServices.put(data.token, service);
//调用服务创建完成
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (Exception e) {
...
}
}
在这里Handler通过反射机制拿到Service对象,于是就调用了service的onCreate方法,所以Service就算是启动了。我们通过层层的寻找总算是见到了onCreate的庐山真面目。
上面流程图没有onStartCommand?不急,我们刚才在sendServiceArgsLocked方法中还有另外一个sendServiceArgsLocked方法没有讲到,他就是onStartCommand的入口,我们看看他是如何实现的。
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
try {
//与调用scheduleCreateService方法一样,远程调用ApplicationThread的scheduleServiceArgs方法
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
break;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
break;
}
}
}
这里依旧调用了远程服务端ApplicationThread的方法来执行后面的逻辑,其实通过上面分析onCreate的逻辑大家应该能够知道调用onStartCommand也是大同小异的,具体的调用逻辑就交给大家去分析啦!
#### 后记
到这里呢,我们就把Service的启动流程完整的讲解了一遍,bindService的启动过程也是类似的。