我们可以通过startService来启动一个服务, 当然也可以通过bindService绑定一个服务,本篇文章我们来讲一讲绑定服务的完整流程, 阅读此文之前,建议先阅读一下笔者的这三篇文章 Android 进程间通信机制(三) 系统进程与应用进程通信
Android 进程间通信机制(四) 应用进程启动过程
Android 进程间通信机制(五) startService流程
整个流程我们从 应用进程到AMS的的调用过程 和 Sevice的绑定过程 来梳理一下
绑定服务,一般流程在客户端调用bindService()方法, 待绑定服务端的service成功后, 再回调客户端的ServiceConnection中的onServiceConnected()方法. 好了,接下来就一起看看代码
预先准备:自己写了一个客户端MyClient.apk 一个服务端MyService.apk
比如客户端MyClient.apk 调用代码如下:
Intent intent = new Intent();ComponentName componentName = new ComponentName("com.example.mysevicejava","com.example.mysevicejava.MyService");intent.setComponent(componentName);this.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
第一个参数传入Intent,第二个参数传入创建的ServiceConnection, ServiceConnection本身是一个接口. 其中包括两个回调方法, bindService()是在ContextWrapper.java类中实现的。
@Overridepublic boolean bindService(Intent service, ServiceConnection conn,int flags) {return mBase.bindService(service, conn, flags);}
mBase是ContextImpl类型对象,调用ContextImpl的bindService()方法。
@Overridepublic boolean bindService(Intent service, int flags, Executor executor, ServiceConnection conn) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, null, null, executor, getUser());}
继续调用ContextImpl.java中的 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 也是一个接口,继承android.os.IInterface 说明是一个Binder,用于跨进程通信用的, 后文有用到它的地方IServiceConnection sd;if (mPackageInfo != null) {//注释1if (executor != null) {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);} else {sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);}} else {throw new RuntimeException("Not supported in system context");}//检查service intent的有效性, 在高于L版本之后, 启动servie必须是显示的intent//要带上包名和类名validateServiceIntent(service);//注释2int res = ActivityManager.getService().bindIsolatedService(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
}
注释1处创建sd对象
注释2处调用bindIsolatedService()方法与系统进程中的AMS交互
在注释1处调用了 LoadedApk类型的对象 mPackagelnfo 的getServiceDispatcher方法.
接着又调用 getServiceDispatcherCommon这个方法
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,Context context, Handler handler, Executor executor, int flags) {.....LoadedApk.ServiceDispatcher sd = null;ArrayMap map = mServices.get(context);//第一次绑定sd为null executor为nullif (sd == null) {if (executor != null) {sd = new ServiceDispatcher(c, context, executor, flags);} else {//走这里的代码,创建一个ServiceDispatcher实例。sd = new ServiceDispatcher(c, context, handler, flags);}//创建好后, 用map存起来 key为 ServiceConnection对象(客户端传递过来的ServiceConnection), value为ServiceDispatcher对象map.put(c, sd);//返回一个InnerConnection对象。return sd.getIServiceConnection();
}
在来看看 ServiceDispatcher这个类, 首先它属于LoadedApk.java中的一个静态类
/frameworks/base/core/java/android/app/LoadedApk.java
static final class ServiceDispatcher {private final ServiceDispatcher.InnerConnection mIServiceConnection;
.....private static class ConnectionInfo {IBinder binder;IBinder.DeathRecipient deathMonitor;}//注释1 内部类 InnerConnection是一个Binder//看见这块比较熟悉的代码,在跨进程通信来看, 这里就属于服务端的代码, 那谁是客户端呢?//答案是 AMS private static class InnerConnection extends IServiceConnection.Stub {@UnsupportedAppUsagefinal WeakReference mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) {mDispatcher = new WeakReference(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);}}}//ServiceDispatcher构造方法@UnsupportedAppUsageServiceDispatcher(ServiceConnection conn,Context context, Handler activityThread, int flags) {//创建一个InnerConnection对象,是一个IBindermIServiceConnection = new InnerConnection(this);//将客户端conn赋值给mConnectionmConnection = conn;mContext = context;mActivityThread = activityThread;mActivityExecutor = null;mLocation = new ServiceConnectionLeaked(null);mLocation.fillInStackTrace();mFlags = flags;}IServiceConnection getIServiceConnection() {return mIServiceConnection;}.....
}
在看看IServiceConnection.aidl 文件, 用关键字oneway修饰,说明在远程调用时(是异步调用,即客户端AMS不会被阻塞), 它只是发送事务数据并立即返回, oneway修饰了的方法不可以有返回值.
/** @hide */
oneway interface IServiceConnection {@UnsupportedAppUsagevoid connected(in ComponentName name, IBinder service, boolean dead);
}
上面这段代码IServiceConnection 跨进程通信模型如下:
IServiceConnection 用于在 AMS 在bindService成功后通知app(此时AMS作为客户端, app进程作为服务端), 然后回调app的 ServiceConnection的 onServiceConnected方法.
好了把注释1 和 注释2 分析完后, 先总结一下时序图:
接下来就进入到 AMS 中
调用到ActivityManagerService的bindIsolatedService方法
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);}
....}
接下来调用 frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
中的 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 {..... ServiceRecord s = res.record;boolean permissionsReviewRequired = false;.....//注释1记录需要bind的serviceAppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent,callerApp.uid, callerApp.processName, callingPackage);//注释2 这个就是 bindservice()方法的第三个参数 Context.BIND_AUTO_CREATEif ((flags&Context.BIND_AUTO_CREATE) != 0) {s.lastActivity = SystemClock.uptimeMillis();//会调用到service服务端进程进行onCreate onBindif (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired) != null) {return 0;}}.....// 注释3 s为ServiceRecord s.app为ProcessRecord 第一次绑定是s.app为null // b.intent.received 为false 所以走else分支.if (s.app != null && b.intent.received) {// Service is already running, so we can immediately// publish the connection.//直接翻译英文注释: 服务已经正在运行, 所以我们立马能回调 connection//即回调 IServiceConnection 接口中的 connected(3个参数)方法了try {c.conn.connected(s.name, b.intent.binder, false);} catch (Exception e) {Slog.w(TAG, "Failure sending service " + s.shortInstanceName+ " 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.// 注释4 应用进程与服务进行绑定,并且服务已经调用过onUnbind方法if (b.intent.apps.size() == 1 && b.intent.doRebind) {requestServiceBindingLocked(s, b.intent, callerFg, true);}} else if (!b.intent.requested) {//注释5 如果应用进程没有发送过绑定service的请求, 第一次绑定会走这里requestServiceBindingLocked(s, b.intent, callerFg, false);}.....
}
先看注释1的调用代码
public AppBindRecord retrieveAppBindingLocked(Intent intent,ProcessRecord app) {Intent.FilterComparison filter = new Intent.FilterComparison(intent);IntentBindRecord i = bindings.get(filter);if (i == null) {i = new IntentBindRecord(this, filter);bindings.put(filter, i);}AppBindRecord a = i.apps.get(app);if (a != null) {return a;}a = new AppBindRecord(this, i, app);i.apps.put(app, a);return a;}
讲到这 有必要先介绍几个与 Service 关的对象类型 ,这样有助于对源码进行理解,
如下所示
ServiceRecord :用于描述一个 Service
ProcessRecord : 一个进程的信息。
ConnectionRecord :用于描述应用进程和 Service 建立的一次通信。
AppBindRecord :应用进程通过 Intent 绑定 Service 时,会通过 AppBindRecord
来维护 Service 与应用程序进程之间的关联。其内部存储了谁绑定的 Service
( ProcessRecord 、被绑定的 Service ( AppBindRecord )、绑定 Service Intent
( IntentBindRecord )和所有绑定通信记 的信息( ArraySet
注释2处部分
在注释2处调用 bringUpServiceLocked 方法,在 bringUpServiceLocked 方法中又调用
realStartServiceLocked 方法,最终由 ActivityThread 来调用 Service onCreate 方法启动
Service ,这也说明了 bindService 方法内部会启动 Service
关于startService的启动流程 请查阅笔者的 Android 进程间通信机制(五) startService流程
注释3处部分:
s为ServiceRecord s.app为ProcessRecord 第一次绑定是s.app为null b.intent.received 为false 所以走else分支(走注释5处代码)
b.intent.received只有在服务端MyService执行 onBind()并且publishService()之后才为true
s.app是在realStartServiceLocked()的时候被赋值.
注释4处表示:应用进程与服务进行绑定,并且服务已经调用过onUnbind方法
继续分析 注释5 部分
注释5处表示: 如果应用进程没有发送过绑定service的请求,第一次绑定就会走这个分支
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);//这里就通过IApplicationThread进行跨进程通信, 跳转到app进程的 ActivityThread.java的scheduleBindService方法了r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.getReportedProcState());if (!rebind) {i.requested = true;}i.hasBound = true;i.doRebind = false;
}
继续跳转到
frameworks/base/core/java/and oid/app/ActivityThread .java 的scheduleBindService方法 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;if (DEBUG_SERVICE)Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());//发送BIND_SERVICE消息sendMessage(H.BIND_SERVICE, s);}//处理消息的代码:case BIND_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");handleBindService((BindServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;
....
继续调用frameworks/base/core/java/android/app/ActivityThread java的handleBindService方法
private void handleBindService(BindServiceData data) {Service s = mServices.get(data.token); //1if (s != null) {try {data.intent.setExtrasClassLoader(s.getClassLoader());data.intent.prepareToEnterProcess();try {if (!data.rebind) { //2IBinder binder = s.onBind(data.intent); //3ActivityManager.getService().publishService(data.token, data.intent, binder); //4} 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
在2处BindServiceData成员变量rebind值为false
在3处,就执行来调用 Service中的 onBind方法, 比如我自己写MyService.java
@Overridepublic IBinder onBind(Intent intent) {Log.e("test", "==服务端==onBind========");// TODO: Return the communication channel to the service.return new MyBinder();}
如果 rebind 的值为 true 则调用 5处的 Service onRebind 方法
在4会调用
ActivityManager.getService()的publishService方法,调用ActivityManagerService的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);}}
接着又会调用 mServices.publishServiceLocked((ServiceRecord)token, intent, service);
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {final long origId = Binder.clearCallingIdentity();try {if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r+ " " + intent + ": " + service);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> connections = r.getConnections();for (int conni = connections.size() - 1; conni >= 0; conni--) {ArrayList clist = connections.valueAt(conni);for (int i=0; i
重点关注 c.conn.connected(r.name, service, false);
可以再回过头看下2.1 小结中的 IServiceConnection 通信的示意图(见2.1小结的分析图)
调用 c.conn.connected方法,其中 c.conn指的是 IServiceConnection , 它的实现为ServiceDispatcher.InnerConnection ,实现代码在 /frameworks/base/core/java/android/app/LoadedApk.java 中
其中ServiceDispatcher 是LoadedApk 的内部类, 而InnerConnection又是ServiceDispatcher的内部类.
c.conn.connected(xxx) 就调用的如下的代码
private static class InnerConnection extends IServiceConnection.Stub {@UnsupportedAppUsagefinal WeakReference mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) {mDispatcher = new WeakReference(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);}}}
继续调用 sd.connected(name, service, dead)方法:
public void connected(ComponentName name, IBinder service, boolean dead) {if (mActivityExecutor != null) {mActivityExecutor.execute(new RunConnection(name, service, 0, dead));} else if (mActivityThread != null) {//注释1mActivityThread.post(new RunConnection(name, service, 0, dead));} else {doConnected(name, service, dead);}}
注释1处调用 Handler 类型的对象 mActivityThread post 方法, mActivityThread
际上指向的是H 。通过调用H 的post方法将 RunConnection 对象的内容运行在主线
程中。 下面再看看RunConnection 里面的run方法
/frameworks/base/core/java/android/app/LoadedApk.java
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() {//上面传递进来的第三个参数 mCommand 为 0,所以走这里的代码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;}
继续调用doConnected(mName, mService, mDead)方法
public void doConnected(ComponentName name, IBinder service, boolean dead) {
.....// If there was an old service, it is now disconnected.if (old != null) {mConnection.onServiceDisconnected(name);}if (dead) {mConnection.onBindingDied(name);}// If there is a new viable service, it is now connected.//这里就回调到了 客户端的 onServiceConnected 方法了if (service != null) {mConnection.onServiceConnected(name, service);} else {// The binding machinery worked, but the remote returned null from onBind().mConnection.onNullBinding(name);}
.....
}
这样在客户端实现了 ServiceConnection 接口类的 onServiceConnected方法就会被执
行。至此,Service 的绑定过程就分析完成。
在自己写的demo(客户端 MyClient.apk 服务端MyService.apk)中加入log,也和上面分析的流程图是一致的
03-21 21:50:57.942 4221 9156 E test : =ActiveServices===创建==scheduleCreateService==
03-21 21:50:57.943 4221 9156 E test : ===ActiveServices scheduleBindService===
03-21 21:50:57.945 29708 29708 E test : =服务端MyService==onCreate=====
03-21 21:50:57.946 29708 29708 E test : ==服务端MyService==onBind========
03-21 21:50:57.964 29831 29831 E test : 客户端MyClient 回调方法 onServiceConnected