我们可以使用bindService来跨进程通信,其使用方法如下
Intent intent = new Intent("xxx");
intent.setPackage("xxx");
boolean result = bindService(intent,new ServiceConn(),BIND_AUTO_CREATE);
private class ServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public 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 {
@UnsupportedAppUsage
final 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) {//1
return 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);//1
return 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,//2
hostingRecord, 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);//创建context
Application 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();//1
mServices.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);//1
ActivityManager.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 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);//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流程图如下