AndroidService

《Android开发艺术探索》9.3章
Service分为两种工作状态,一种是启动状态,主要用于执行后台计算;另一种是绑定态,主要用于其他组件和Service的交互。需要注意的是,Service的这两种状态是可以共存的,即Service既可以处于启动状态也可以同时处于绑定状态。
通过ContextstartService方法即可启动一个Service:

1
2
Intent intent = new Intent(content,Service.class);
startService(intent);

通过ContextbindService方法可以绑定一个Service

1
2
Intent intent = new Intent(content,Service.class);
bindService(intent,connection,BIND_AUTO_CREATE);

Service启动过程

Service的启动时从ContextWrapperstartService开始的:

1
2
3
4
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}

mBaseContext的实现类ContextImpl在Activity启动的时候会通过attach方法关联一个ContextImpl,这个ContextImpl就是上面的mBase,从ContextWrapper的实现来看,大部分的实现都是通过mBase来实现的,这是一种典型的桥接模式。在ContextImplstartService方法中又调用了startServiceCommon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 @Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,UserHandle user) {

validateServiceIntent(service);
service.prepareToLeaveProcess(this);
//api 27
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
//api 25
//ComponentName cn = ActivityManagerNative.getDefault().startService(
// mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
// getContentResolver()), getOpPackageName(), user.getIdentifier());

return cn;

}

startServiceCommon中通过getService这个对象来启动一个服务,这个对象就是AMS,需要注意的是,在上述代码中通过AMS来启动服务的过程是一个跨进程调用。AMS的startService如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
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, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}

AMS会通过mServices来完成service的启动过程,mServices的对象类型是ActiveServicesActiveServices是一个辅助AMS进行Service管理的类,包括Service的启动、绑定和停止。在startService方法的尾部会调用startServiceInnerLocked方法

1
2
3
4
5
6
7
8
9
10
11
12
13
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
return r.name;
}

上述代码中ServiceRecord是描述一个Service记录,ServiceRecord一直贯穿整个Service流程,startServiceInnerLocked并没有完成启动Service的完整流程,而是将后续的过程交给了bringUpServiceLocked,在该方法中又调用了realStartServiceLocked方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {

r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();

boolean created = false;
try {

synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
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;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);

// Cleanup.
if (newService) {
app.services.remove(r);
r.app = null;
}

// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}

if (r.whitelistManager) {
app.whitelistManager = true;
}

requestServiceBindingsLocked(r, execInFg);

updateServiceClientActivitiesLocked(app, null, true);

// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}

sendServiceArgsLocked(r, execInFg, true);

if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}

if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}

realStartServiceLocked方法中,首先通过app.threadscheduleCreateService方法来创建Service对象并调用其onCreate,接着再通过sendServiceArgsLocked方法来调用Service的其他方法,比如onStartCommand,这两个过程均是进程间通信。app.thread对象是IApplicationThread类型,它实际上是一个Binder,它的具体实现是ApplicationThreadApplicationThreadNative。由于ApplicationThread继承了ApplicationThreadNative,因此只需要看ApplicationThreadService启动过程的处理即可,这对应着它的scheduleCreateService方法,如下所示:

1
2
3
4
5
6
7
8
9
10
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);
}

通过发送消息给Handler H来完成的。H会接收这个CREATE_ SERVICE消息并通过ActivityThreadhandleCreateService方法来完成Service的最终启动,handleCreateService的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
Service service = null;

java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();

ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);

Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}

handleCreateService主要完成了以下几件事:
首先通过类加载器创建了Service实例,接着创建ContextImpl对象和Application对象 并通过service.attach方法建立联系,最后调用service.onCreate方法,并将service存储在ActivityThread中的一个列表mServices

1
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();

由于serviceonCreate方法执行了,也就意味着Service已经启动了。除此之外,ActivityThead中还会通过handleServiceArgs方法调用ServiceonStartCommand方法。

Service绑定过程

和启动过程一样,也是从ContextWrapper开始的:

1
2
3
4
5
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}

然后是ContextImplbindService方法调用bindServiceCommon方法,然后远程调用AMS的bindService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

在该方法中,首先将客户端的ServiceConnection转化为ServiceDispatcher.InnerConnection对象,因为服务绑定是跨进程的,所以ServiceConnection对象必须借助Binder对象才能让远程服务端调用自己的方法。ServiceDispatcher起着连接ServiceConnectionInnerConnection的作用。这个过程由LoadedApk.getServiceDispatcher方法完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}

在上面的代码中,mServices是一个ArrayMap,它存储了一个应用当前活动的ServiceConnectionServiceDispatcher的映射关系,其声明如下:

1
2
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();

系统首先会查找是否存在相同的ServiceConnection,如果不存在就重新创建一个ServiceDispatcher对象,并将其存储在mServices中,其中映射关系的key是ServiceConnection,value是ServiceDispatcher,在ServiceDispatcher的内部又保存了ServiceConnectionInnerConnection对象。当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceConnection中的onServiceConnected方法,这个过程有可能是跨进程的。当ServiceDispatcher创建好了以后,getServiceDispatcher会 返回其保存的InnerConnection对象。
接着调用AMS的bindService 方法,该方法又调用了bindServiceLocked–>bringUpServiceLocked–>realStartServiceLocked,这个过程和上面的StartService过程逻辑类似,最终都是通过ApplicationThread来完成Service的实例创建并调用onCreate方法。和启动Service过程不同的是,绑定过程会调用app.threadscheduleBindService方法,这个过程的实现在ActivityServicerequestServiceBindingsLocked方法中:

1
2
3
4
5
6
7
8
9
10
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}

该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:

1
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();

具体保存方法在AMS一开始的方法bindServiceLocked中:

1
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);

requestServiceBindingsLocked方法中调用了了requestServiceBindingLocked方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
// Keep the executeNesting count accurate.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
return false;
}
}
return true;
}

在上述代码中,app.thread这个对象多次出现过,它实际上就是ApplicationThreadApplicationThread的一系列以schedule开头的方法,其内部都是通过Handler H来中转的,对于scheduleBindService方法来说也是如此,它的实现如下所示:

1
2
3
4
5
6
7
8
9
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
sendMessage(H.BIND_SERVICE, s);
}

在H内部,接收到BIND_SERVICE这类消息时,会交给ActivityThreadhandleBindService方法来处理。在handleBindService中,首先根据Servicetoken取出Service对象,然后调用ServiceonBind方法,ServiceonBind方法会返回一个Binder对象给客户端使用,原则上来说,ServiceonBind方法被调用以后,Service就处于绑定状态了,但是onBind方法是Service的方法,这个时候客户端并不知道已经成功连接Service了,所以还必须调用客户端的ServiceConnection中的onServiceConnected,这个过程是由ActivityManager.getService()publishService方法来完成的,而前面多次提到,ActivityManager.getService()就是AMS。handleBindService的实现过程如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}

Service有一个特性,当多次绑定同一个Service时,Service的onBind方法只会执行一次,除非Service被终止了。当Service的onBind执行以后,系统还需要告知客户端已经成功连接Service了。根据上面的分析,这个过程由AMS的publishService方法来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}

synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}

从_上面代码可以看出,AMS的publishService方法将具体的工作交给了ActiveServices类型的mServices对象来处理。ActiveServicespublishServiceLocked方法看起来很复杂,但其实核心代码就只有一- 句话: c.conn.connected(r.name,service), 其中c的类型是ConnectionRecordc.comn的类型是ServiceDispatcher.InnerConnection, service就是Service的onBind方法返回的Binder对象。为了分析具体的逻辑,下面看一下ServiceDispatcher.InnerConnection的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}

public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}

InnerConnection的定义可以看出来,它的connected方法又调用了ServiceDispatcherconnected方法

1
2
3
4
5
6
7
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}

对于Service的绑定过程来讲,ServiceDispatcher中的mActivityThread就是一个handler,它就是ActivityThread中的H,从Service的创建过程来讲,mActivityTHread不会为null,这样一来,RunConnection就可以经由Hpost方法从而运行在主线程中,因此,客户端的ServiceConnection中的方法回调是在主线程中执行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}

public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}

final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}

很显然,RunConnectionrun方法也是简单调用了ServiceDispatcherdoConnected方法,由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,因此它可以很方便地调用ServiceConnection对象的onServiceConnected方法,如下所示。
至此,bindService的过程完成。


以上


AndroidService
https://blog.huangyuanlove.com/2018/08/01/AndroidService/
作者
HuangYuan_xuan
发布于
2018年8月1日
许可协议
BY HUANG兄