继续上篇的分析,接下来是第三个问题”Service与其客户端的绑定如何实现,即跨进程调用问题“
(一)、Service的生命周期
(二)、Service的自动重启问题
(一)、Service的生命周期
(二)、Service的自动重启问题
(三)、Service与其客户端的绑定如何实现,即跨进程调用问题。
服务于客户端的绑定通过binder来实现的,就是客户端去bind服务。来看看ContextImpl的bindServiceCommon方法
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
}
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();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
}
}
然后会去LoadedApk.java里面会创建用于跨进程连接的binder对象,就是一个ServiceDispatcher的InnerConnection。
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
//这里用一个map将所有的连接记录都保存起来了
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathMonitor;
}
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
//这个方法就是在ActivityManagerService中执行绑定链接时的方法调用
//这里的service毫无疑问就是远程对象执行onBind时返回的那个咯
//所以这里才是服务端和客户端传递一个binder对象的通道,因为这个过程涉及到两个跨进程操作,所以这么设计是必须也是合理的
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
ServiceConnection getServiceConnection() {
return mConnection;
}
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
public void death(ComponentName name, IBinder service) {
.......................
}
//实际执行connect
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
// We unbound before receiving the connection; ignore
// any connection received.
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
if (service != null) {
// A new service is being connected... set it all up.
mDied = false;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is not disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
// 眼熟了吧,这就是我们在绑定服务后获取远程对象代理的回调咯
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
public void doDeath(ComponentName name, IBinder service) {
mConnection.onServiceDisconnected(name);
}
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
}
private final class DeathMonitor implements IBinder.DeathRecipient
{
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
}
后面就是bind操作了,前面讲生命周期时已经有提到过的,这里再把那个方法列一下:
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
....................
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
....................
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
...................
//bindings中添加一起绑定请求,后续requestServiceBindingsLocked()流程中处理绑定接口
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
....................
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//如果携带的标志位中包含自动启动,则进行创建服务的操作,代码可以看前面,如果已经启动了,其实是什么操作也不干的
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
if (s.app != null) {
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
mAm.updateOomAdjLocked(s.app);
}
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
// 如果服务已经启动并且有绑定过了,直接返回binder对象,这里的conn就是前面提到的InnerConnection的代理,这里看到了connected操作其实是由<pre name="code" class="java"> // InnerConnection它来完成的
try {
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
// 从这里可以看出,一般情况下,onBind只会执行一次,除非请求doRebind
// 这个标志位是旧的客户端全部unbind之后自动设置上的
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//服务还没有绑定者,则执行后续操作将调用到onBind操作
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
大家有没有在上面注意一个问题,InnerConnection中并没有unConnected方法,那么解绑的时候又是如何通过这个连接通道执行回调的呢?大家可以看看前面讲的unBind流程中,里面也是没有任何地方会执行到这个操作的,它有的只是服务端的unBind和可能执行onDestory。那么什么时候会执行到ServiceConnection.onServiceDisconnected,事实上只有在远程服务端那个binder死亡才会执行到的。这个就是通过为这个binder对象注册一个IBinder.DeathRecipient,这是binder的死亡通知机制。这里就不讲了。
到这里Android中的服务已经简要的分析了一下,不可能面面俱到也不会全都正确,还请大家多多指教。