我们可以使用bindService来跨进程通信,其使用方法如下
Intent intent = new Intent("xxx");
intent.setPackage("xxx");
boolean result = bindService(intent,new ServiceConn(),BIND_AUTO_CREATE);private class ServiceConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {}@Overridepublic void onServiceDisconnected(ComponentName name) {}
}
服务绑定成功后,会回调onServiceConnected方法,然后我们就可以利用返回的IBinder 对象,和服务端通信了。本文来分析下bindService的内部实现。
@Override
public boolean bindService(Intent service, ServiceConnection conn,int flags) {return mBase.bindService(service, conn, flags);
}
这里的mBase是一个ContextImpl对象,接着来看ContextImpl的bindService方法
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,getUser());
}
继续调用ContextImpl的bindServiceCommon方法
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,String instanceName, Handler handler, Executor executor, UserHandle user) {// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.IServiceConnection sd;//省略if (mPackageInfo != null) {if (executor != null) {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);} else {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);//1}} else {throw new RuntimeException("Not supported in system context");}validateServiceIntent(service);try {//省略int res = ActivityManager.getService().bindIsolatedService(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());//2//省略return res != 0;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
注释1处将我们传进来的ServiceConnection 对象封装成可以跨进程通信的IServiceConnection对象。注释2处是跨进程调用,调用到AMS的bindIsolatedService方法
先来看一下注释1处是如何将我们的ServiceConnection 对象封装成IServiceConnection对象的,mPackageInfo是一个LoadedApk对象getServiceDispatcher最后会调用其getServiceDispatcherCommon方法
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,Context context, Handler handler, Executor executor, 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) {if (executor != null) {sd = new ServiceDispatcher(c, context, executor, flags);} else {sd = new ServiceDispatcher(c, context, handler, flags);//1}if (map == null) {map = new ArrayMap<>();mServices.put(context, map);}map.put(c, sd);} else {sd.validate(context, handler, executor);}return sd.getIServiceConnection();//2}}
注释1处创建一个ServiceDispatcher对象,注意第一个参数为我们传入的ServiceConnection 对象。注释2处调用ServiceDispatcher的getIServiceConnection方法然后返回
//getIServiceConnection
@UnsupportedAppUsage
IServiceConnection getIServiceConnection() {return mIServiceConnection;
}ServiceDispatcher(ServiceConnection conn,Context context, Handler activityThread, int flags) {mIServiceConnection = new InnerConnection(this);mConnection = conn;mContext = context;mActivityThread = activityThread;mActivityExecutor = null;mLocation = new ServiceConnectionLeaked(null);mLocation.fillInStackTrace();mFlags = flags;
}//
private static class InnerConnection extends IServiceConnection.Stub {@UnsupportedAppUsagefinal WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) {mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
可以看出getIServiceConnection返回的是一个 InnerConnection对象。InnerConnection继承自IServiceConnection.Stub类,是跨进程通信的Bn端。InnerConnection对象中的mDispatcher 指向的是 ServiceDispatcher对象,而ServiceDispatcher对象的mConnection 成员为我们传进来的IServiceConnection对象。
接着来看AMS的bindIsolatedService方法(实际上是通过跨进程调用,调用到AMS里面的,具体的跨进程调用过程本文不详细分析,直接看AMS里面对应的方法)
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,String resolvedType, IServiceConnection connection, int flags, String instanceName,String callingPackage, int userId) throws TransactionTooLargeException {//省略synchronized(this) {return mServices.bindServiceLocked(caller, token, service,resolvedType, connection, flags, instanceName, callingPackage, userId);}}
mServices是ActiveServices对象,接着来看ActiveServices的bindServiceLocked方法
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,String resolvedType, final IServiceConnection connection, int flags,String instanceName, String callingPackage, final int userId)throws TransactionTooLargeException {//省略if ((flags&Context.BIND_AUTO_CREATE) != 0) {s.lastActivity = SystemClock.uptimeMillis();if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired) != null) {//1return 0;}}//省略if (s.app != null && b.intent.received) {//省略}else if (!b.intent.requested) {requestServiceBindingLocked(s, b.intent, callerFg, false);//2}//省略
bindServiceLocked方法比较长,省略了大部分代码,主要是执行以下两个方法
- bringUpServiceLocked
- requestServiceBindingLocked
接下来分开来看一下这两个方法都干了什么事情
bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)throws TransactionTooLargeException {//省略if (!isolated) {app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);if (app != null && app.thread != null) {try {app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);realStartServiceLocked(r, app, execInFg);//1return null;} catch (TransactionTooLargeException e) {throw e;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);}// If a dead object exception was thrown -- fall through to// restart the application.}} else {//省略}if (app == null && !permissionsReviewRequired) {// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service// was initiated from a notification tap or not.if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,//2hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {bringDownServiceLocked(r);return msg;}if (isolated) {r.isolatedProc = app;}}//省略
}
注释1处调用realStartServiceLocked来启动服务。注释2处如果要启动的服务的进程不存在,则需要先创建进程。我们假设进程已经存在,重点来看realStartServiceLocked方法
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {//省略app.thread.scheduleCreateService(r, r.serviceInfo,mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),app.getReportedProcState());//省略
}
这里又是一个跨进程通讯,调用服务端的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);}
对于CREATE_SERVICE消息,最终调用到handleCreateService方法
private void handleCreateService(CreateServiceData data) {//省略try {if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//创建contextApplication app = packageInfo.makeApplication(false, mInstrumentation);java.lang.ClassLoader cl = packageInfo.getClassLoader();service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);// Service resources must be initialized with the same loaders as the application// context.context.getResources().addLoaders(app.getResources().getLoaders().toArray(new ResourcesLoader[0]));context.setOuterContext(service);service.attach(context, this, data.info.name, data.token, app,ActivityManager.getService());service.onCreate();//1mServices.put(data.token, service);//省略}
注释1处Service的onCreate方法就会被执行。
requestServiceBindingLocked
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) throws TransactionTooLargeException {//省略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.getReportedProcState());//1} catch (TransactionTooLargeException e) {} catch (RemoteException e) {}}return true;}
注释1处又是一个跨进程调用,调用服务端的scheduleBindService方法
public final void scheduleBindService(IBinder token, Intent intent,boolean rebind, int processState) {//省略sendMessage(H.BIND_SERVICE, s);
}
对于BIND_SERVICE消息,调用handleBindService方法
private void handleBindService(BindServiceData data) {Service s = mServices.get(data.token);if (DEBUG_SERVICE)Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);if (s != null) {try {data.intent.setExtrasClassLoader(s.getClassLoader());data.intent.prepareToEnterProcess();try {if (!data.rebind) {IBinder binder = s.onBind(data.intent);//1ActivityManager.getService().publishService(data.token, data.intent, binder);//2} else {s.onRebind(data.intent);ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}} 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);}}}}
注释1处会导致Service的onBind方法被调用,onBind方法中返回一个IBinder 对象。重点来看注释2处的publishService的方法干了什么事情。publishService方法也是一个跨进程调用,又调用到AMS的publishService方法
public void publishService(IBinder token, Intent intent, IBinder service) {// Refuse possible leaked file descriptorsif (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);//1}}
注释1处继续调用ActiveServices的publishServiceLocked方法
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {try {if (r != null) {Intent.FilterComparison filter= new Intent.FilterComparison(intent);IntentBindRecord b = r.bindings.get(filter);if (b != null && !b.received) {b.binder = service;b.requested = true;b.received = true;ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();for (int conni = connections.size() - 1; conni >= 0; conni--) {ArrayList<ConnectionRecord> clist = connections.valueAt(conni);for (int i=0; i<clist.size(); i++) {ConnectionRecord c = clist.get(i);if (!filter.equals(c.binding.intent.intent)) {continue;}if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);try {c.conn.connected(r.name, service, false);//1} catch (Exception e) {Slog.w(TAG, "Failure sending service " + r.shortInstanceName//省略
注释1处c.conn就是之前我们封装成的InnerConnection 对象,这里调用其connected方法,注意这里也是一个跨进程调用
private static class InnerConnection extends IServiceConnection.Stub {final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;public void connected(ComponentName name, IBinder service, boolean dead)throws RemoteException {LoadedApk.ServiceDispatcher sd = mDispatcher.get();if (sd != null) {sd.connected(name, service, dead);}}
}
继续调用ServiceDispatcher 的connected方法
public void connected(ComponentName name, IBinder service, boolean dead) {if (mActivityExecutor != null) {mActivityExecutor.execute(new RunConnection(name, service, 0, dead));} else if (mActivityThread != null) {mActivityThread.post(new RunConnection(name, service, 0, dead));} else {doConnected(name, service, dead);//1}
}
注释1处调用doConnected
public void doConnected(ComponentName name, IBinder service, boolean dead) {ServiceDispatcher.ConnectionInfo old;ServiceDispatcher.ConnectionInfo info;//省略// If there is a new viable service, it is now connected.if (service != null) {mConnection.onServiceConnected(name, service);} else {// The binding machinery worked, but the remote returned null from onBind().mConnection.onNullBinding(name);}
可以看出,这里就调用了mConnection的onServiceConnected方法,而这个mConnection就是之前我们封装是传入的ServiceConnection对象。我们传入的ServiceConnection的onServiceConnected就被调用了。
总结
bindService流程图如下