public class ContextWrapper extendsContext {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
returnmBase.bindService(service, conn, flags);
}
ContextImpl.java
// bindService
@Override
public boolean bindService(Intent service, ServiceConnection conn, intflags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn,flags, Process.myUserHandle());
}
// bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnectionconn, int flags, UserHandle user) {
IServiceConnection sd;
...
//包装ServiceConnection
sd =mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(),flags);
...
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(),user.getIdentifier());
...
}
这里是通过binder和AMS进行通信,一次binder调用。
在通信的时候,构造了一个InnerConnection的binder对象作为参数传给了AMS,以便于实现方法回调。
private static class InnerConnectionextends IServiceConnection.Stub {
finalWeakReference
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = newWeakReference
}
public void connected(ComponentNamename, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name,service);
}
}
}
另外构造了ServiceDispatcher对象将ServiceConnection和InnerConnection进行了包装。
在回调的时候,AMS端作为Proxy调用connected方法。
在AMS中的调用比较复杂,时序图如下
AMS的bindService方法
public intbindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType,IServiceConnection connection, int flags, String callingPackage,
int userId) throwsTransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked filedescriptors
if (service != null &&service.hasFileDescriptors() == true) {
throw newIllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw newIllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token,service,
resolvedType, connection,flags, callingPackage, userId);
}
}
里面调用到mServices.bindServiceLocked
在ActivityManagerService.java中有定义
final ActiveServices mServices;
继续调用到其realStartServiceLocked方法
public final class ActiveServices {
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, booleanexecInFg) throws RemoteException {
...
r.app = app;
...
app.thread.scheduleCreateService(r,r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
...
//
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
...
}
private final boolean requestServiceBindingLocked(ServiceRecordr, IntentBindRecord i,
boolean execInFg, boolean rebind)throws TransactionTooLargeException {
if (r.app == null || r.app.thread ==null) {
// If service is not currentlyrunning, can't yet bind.
return false;
}
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) {
……
}
}
return true;
}
由于AMS中已经保存了系统中已启动的应用和服务的信息,这里的r.app.thread是服务的一个proxy,通过这个binder调用,服务中的scheduleBindService方法被执行,里面调用了
public final void scheduleBindService(IBindertoken, Intent intent,
boolean rebind, intprocessState) {
updateProcessState(processState,false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
sendMessage(H.BIND_SERVICE, s);
}
处理该消息时调用ActivityThread的
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);
ActivityManagerNative.getDefault().publishService(
data.token,data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token,SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throwex.rethrowFromSystemServer();
}
} catch (Exception e) {
}
}
}
在server进程中,通过调用AMS服务publishService把binder对象传给AMS
这里,再回顾下这个时序图
可以看出,进程间的调用都是binder通信调用。
在AMS调用scheduleBindService的时候,有一个很巧妙的设计,就是把RecordService作为参数传递给了server端,其实server端并没有实际使用RecordService,只是把RecordService再通过publishService又传递给了AMS,为什么这么曲折呢?
因为server端的sheduleBindService方法中进行了异步调用。采用这种方式,连接了RecordService和server端传递的服务binder的对应关系。AMS根据这个RecordService找到调用的client端,再通过调用connected方法把server的binder传送过去。
ActivityManagerService中有方法
public void publishService(IBindertoken, Intent intent, IBinder service) {
// Refuse possible leaked filedescriptors
if (intent != null &&intent.hasFileDescriptors() == true) {
throw newIllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceofServiceRecord)) {
throw newIllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token,intent, service);
}
}
ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
for (int conni=r.connections.size()-1;conni>=0; conni--) {
ArrayList
for (int i=0;i ConnectionRecord c= clist.get(i); ... try { //binder调用,AMS调用client的方法,把service的binder传过去 c.conn.connected(r.name, service); } catch (Exceptione) { Slog.w(TAG,"Failure sending service " + r.name + " toconnection " + c.conn.asBinder() + "(in " + c.binding.client.processName + ")", e); } } } ... } 这里根据ServiceRecord找到对应的IServiceConnection, ServiceRecord中有定义 //IBinder -> ConnectionRecord of all bound clients finalArrayMap = new ArrayMap 由于一个service中可能会提供多个binder服务,每个binder又会有多个客户端连接,所以这里使用了ArrayMap 再通过遍历connections找到对应的ConnectionRecord,ConnectionRecord中存储有客户端的IServiceConnection conn作为通信proxy。 ConnectionRecord.java final class ConnectionRecord { final AppBindRecord binding; //The application/service binding. final ActivityRecord activity; //If non-null, the owning activity. final IServiceConnection conn; // The client connection.