Android系统涉及到许多进程间通信,也提供了实名及匿名Binder,例如:AMS是属于实名Binder,在系统启动中通过ServiceManager来启动并在ServiceManager中进行注册;如果两个非系统应用之间进行通信,那么可以通过AIDL和bindService来进行通信,一个做server端,一个做client端,server端提供匿名的Binder。本文通过一个实例来讲解一下AIDL和bindService的使用及流程分析。
一.AIDL具体实现
a.创建IData.aidl文件,定义Server端提供的能力
interface IData {
int getSharedDisplayNum(int currDisplay, int appType);
}
接着说一下在AIDL文件中支持的数据类型包括:
1.基本数据类型
2.String和CharSequence
3.List:只支持ArrayList,里面的元素都必须被AIDL支持
4.Map:只支持HashMap,里面的元素必须被AIDL 支持
5.实现Parcelable接口的对象
6.所有AIDL接口
此时编译器会对aidl文件自动编译生成IData.java文件,该文件是Android为了快速能使用Binder而做的一个模板,即生成通信层代码模板,用户只用关心业务层的逻辑,降低开发难度。
b.IData.java文件
public interface IData extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
//Stub继承了Binder,实现了IData接口,内部的方法需要在Service创建Stub时实现
public static abstract class Stub extends android.os.Binder implements com.hly.learn.IData {
//用来区分binder
private static final java.lang.String DESCRIPTOR = "com.hly.learn.IData";
/** Construct the stub at attach it to the interface. */
//本地创建Stub时,会将DESCRIPTOR传到Binder里面,后续可以通过queryLocalInterface()来查询到对应的Binder实体
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.hly.learn.IData asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
//去查找 Binder 本地对象,如果找到了就说明 Client 和 Server 在同一进程,那么这个binder本身就是 Binder本地对象,可以直接使用
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.hly.learn.IData))) {
return ((com.hly.learn.IData)iin);
}
//否则返回的是实现了IData接口的Proxy对象,但不是Binder
return new com.hly.learn.IData.Stub.Proxy(obj);
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
//client调用后,server端需要的逻辑处理
........
}
//代理对象是IData,不是Binder
private static class Proxy implements com.hly.learn.IData {
private android.os.IBinder mRemote;
//client获取到这个代理对象时,传参是Binder引用,最终是通过该引用来与server进行通信
Proxy (android.os.IBinder remote) {
mRemote = remote;
}
.......
//由于是实现了IData接口,需要实现其方法
@Override public int getSharedDisplayNum(int currDisplay, int appType) throws android.os.RemoteException {
........
}
}
//本地Stub需要实现的方法
public int getSharedDisplayNum(int currDisplay, int appType) throws android.os.RemoteException;
}
c.Server端实现Binder
public class DataService extends Service {
private static final String TAG = DataService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
FLog.d(TAG, "data service is bound");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
private IData.Stub mBinder = new IData.Stub() {
@Override
public int getSharedDisplayNum(int currDisplay, int appType) {
if (mService != null) {
return mService.getInSharedDisplayNum(currDisplay, appType);
}
return 0;
}
};
}
d.Client端绑定服务
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection;
private IData mDataService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.bind_service);
tv.setOnClickListener(v -> bindServer());
}
private void bindServer() {
mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
mDataService = IMyAidlInterface.Stub.asInterface(service);
} catch (Exception e) {
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
try {
mDataService = null;
} catch (Exception e) {
}
}
};
Intent intent = new Intent("com.hly.action.DataService");
intent.setClassName("com.hly.server", "com.hly.server.DataService");
bindService(intent, mFlowConnection, Service.BIND_AUTO_CREATE);
}
}
e.IData.java文件详解
Client端调用Server端的方法:
@Override public int getSharedDisplayNum(int currDisplay, int appType) throws android.os.RemoteException {
//Client进程创建传输数据的Parcel对象
android.os.Parcel _data = android.os.Parcel.obtain();
//client进程创建返回数据的Parcel对象,目标方法执行后的结果
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//1.将需要传送的数据写入到Parcel对象中
_data.writeInt(currDisplay);
_data.writeInt(appType);
//2.调用mRemote[Binder引用]的transact()将上述数据发送到Binder驱动
mRemote.transact(Stub.TRANSACTION_getSharedDisplayNum, _data, _reply, 0);
//在发送数据后,Client进程的该线程会暂时被挂起
// 所以,若Server进程执行的耗时操作,请不要使用主线程,以防止ANR
// 3. Binder驱动根据 mRemote 找到对应的真身Binder对象所在的Server 进程(系统自动执行)
// 4. Binder驱动把数据发送到Server 进程中,并通知Server进程执行解包(系统自动执行)
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
static final int TRANSACTION_getSharedDisplayNum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
Server端收到调用后处理:
// 1. 收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION:{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getSharedDisplayNum:{
// 解包Parcel中的数据
data.enforceInterface(descriptor);
// 获得目标方法的参数
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
//调用本地已实现的方法
int _result = this.getSharedDisplayNum(_arg0, _arg1);
reply.writeNoException();
//返回结果
reply.writeInt(_result);
return true;
}
default:{
return super.onTransact(code, data, reply, flags);
}
}
Server进程将结果返回client进程:
mRemote.transact(Stub.TRANSACTION_getSharedDisplayNum, _data, _reply, 0);
// 1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
// 2. 通过代理对象接收结果(之前被挂起的线程被唤醒)
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
以上就是通过AIDL和bindService()来进行进程通信。
二.bindService()执行流程
Client端通过bindService()来与Server端进行了绑定,从而可以跟本地调用接口一样调用Server端的接口,先画出bindService的流程图,主要总结了以下几种场景的流程图:
a.基于Server端进程已经启动,Service未启动的场景
b.基于Server端进程已经启动,service已经启动和service已经启动且被bind()的场景
三.源码分析
从上述流程图可以看到,在activity、service或通过context来进行bindService(),最终会通过ActivityManagerService来进行调用:
a.ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
//该方法是通过传入的ServiceConnection获取到IServiceConnection
//后续绑定成功后,会通过该实例回调client的onServiceConnected()方法
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
......
//调用ActivityManagerService的方法
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
.....
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
首先通过LoaderApk里面getServiceDispatcher()将ServiceConnection转换为IServiceConnection对象,里面进行了多层封装,当绑定成功后,会一层层的执行到client端的onServiceConnected();
最后会调用ActivityManagerServce的bindService()方法,其中bindService的入参mMainThread.getApplicationThread()方法返回的是ApplicationThread对象, 该对象继承于ApplicationThread.Stub(Binder服务端),这个ApplicationThread对象串联起了后续AMS对发起端进程ActivityThread的交互(如果把ApplicationThread当作服务端,那么此时AMS相关于ApplicationThread而言就是客户端)。
b.ActivityManagerService.bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
......
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
通过以上可以看到,ActivityManagerService将事务委托给ActiveServices类实例对象进行处理。
c.ActiveServices.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
......
......
//创建对象ConnectionRecord,此处connection来自发起方
ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);
//保存ConnectionRecord省略......
.......
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//启动service
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
......
......
//Service进程启动,且Service启动,且该Service已经被绑定过,直接将binder回调给client端
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder, false);
} 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.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//Service进程启动,且Service启动,会调用以下逻辑
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
在bindServiceLocked()里面会根据发起端创建对应的ConnectionRecord对象的成员变量c,该ConnectionRecord对象里面存储了IServiceConnection,再通过clist.add( c ),将该ConnectionRecord对象添加到clist队列,后面便可以通过clist来查询发起方的信息,当绑定成功后,会通过该ConnectionRecord.IServiceConnection.connected()进行回调。然后调用bringUpServiceLocked()来启动进程及创建service,如果之前有绑定过,则会直接将binder返回给client端。
d.ActiveServices.bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//Service进程已经启动,Service已经启动
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
//Service进程已经启动,Service未启动,来启动Service
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
}
//Service进程未启动,先启动进程
//AMS--->Process.start()--->ZygoteProcess.startxx()--------->AcitivityThread.main()---->attach()-------
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
.......
//把要绑定的service加入到mPendingServices里面,后续在进程启动完成后,会attach()
//继而调用到attachAppliactionLocked()在里面启动service
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
}
当需要创建新的进程时候,会调用AMS.startProcessLocked启动进程,然后通过AMS--->Process.start()--->ZygoteProcess.startxx()--------->AcitivityThread.main()---->attach()调用到attachApplicationLocked方法,进而调用realStartServiceLocked()方法。
若不用创建进程,则直接调用realStartServiceLocked方法,进行启动service的工作。
e.ActiveServices.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
.......
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
//发送延迟消息,如果在20s内没有收到service onCreate()完毕的ServiceDoneExecuting
//则会报timeout error
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked();
boolean created = false;
try {
......
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//在service进程创建要绑定的service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
}
.......
//执行bind()
requestServiceBindingsLocked(r, execInFg);
.......
}
在bumpServiceExecutingLocked会发送一个延迟处理的消息SERVICE_TIMEOUT_MSG。在方法scheduleCreateService执行完成,也就是onCreate回调执行完成之后收到ServiceDoneExecuting便会remove掉该消息。但是如果没能在延时时间之内remove该消息,则会进入执行service timeout流程触发ANR,这就是为啥Android四大组件不能执行耗时操作的原因。
在执行app.thread.scheduleCreateService后,会进行requestServiceBindingsLocked()来进行service的绑定。
f.ActivityThread
private void handleCreateService(CreateServiceData data) {
......
Service service = null;
try {
//通过反射创建service对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
}
......
}
try {
.......
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用service的onCreate()
service.onCreate();
mServices.put(data.token, service);
try {
///调用AMS发送service创建完成,在ActiveServices里面将ANR消息除去
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
在handleCreateService()里面,通过反射创建对应的service,然后调用onCreate()方法,最后通过AMS发送serviceDoneExecuting()来告知service已经create完成,消除TIME_OUT消息。
g.ActiveServices.requestServiceBindingLocked
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
//如果service没有启动,直接返回false,在serivice进程没有启动,进行bind时,有的分支会调用到这里
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
......
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
//发送bind开始的消息,跟create是类似的
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//回调service进程来执行onBind
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
........
}
return true;
}
在该方法中,首先也是先发送TIME_OUT消息,跟create()是类似的,接着与service进程的ActivityThread的ApplicationThread进行通信执行scheduleBindService(),会执行service的onBind()方法。
h.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) {
//执行Service.onBind()回调方法获取到binder
IBinder binder = s.onBind(data.intent);
//通过AMS将onBind返回值传递回去
ActivityManager.getService().publishService(
data.token, data.intent, binder);
}
......
}
}
上步讲到执行r.app.thread.scheduleBindService(),最终会通过sendMessage()调用到ActivityThread内的handleBindService(),先通过执行service的onBind()方法获取到本地实现的Binder,然后通过ActivityManagerService的publishService()来将binder传递。
i.ActiveServices.publishServiceLocked
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
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;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList clist = r.connections.valueAt(conni);
for (int i=0; i
ActivityManagerService内的publishService会调用到ActiveServices里面的publishServiceLocked(),从clist里面获取到对应的client对应的ConnectionRecord,然后回调内部变量connection的connected()方法,该方法最终会调用到LoaderApk里面的逻辑,前面在bindService的getServiceDispatcher()已经埋下了伏笔。
j.LoadedApk.ServiceDispatcher
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap map = mServices.get(context);
//先从map里面获取
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
//如果没有获取到,则创建对象,然后加入map
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
//调用ServiceDispatcher的方法返回IServiceConnection对象。
return sd.getIServiceConnection();
}
}
再看一下ServiceDispatcher这个内部类:
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
.......
//构造方法
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
//构造方法中创建InnerConnection,,即IServiceConnection实例
mIServiceConnection = new InnerConnection(this);
//构造方法中将client的ServiceConnection传进来
mConnection = conn;
.......
}
//返回创建的IServiceConnection对象
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
ServiceDispatcher内部会创建ServiceDispatcher.InnerConnection实例,该InnerConnection继承IServiceConnection.Stub,该binder用来跟AMS进行通信的,在bindSerice时作为参数传入的,当被bind的service准备好时,会通过该binder回调onConnected()方法。
//内部类继承IServiceConnection.Stub
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference(sd);
}
//1.绑定成功后会先调用该connected()方法
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.InnerConnection内部的onConnected()内部又会调用到ServiceDispatcher自身的onConnected()方法,通过mActivityThread.post()[RunConnection内部command为1,表示执行doConnected();command为0,表示执行doDeath()]来最终调用doConnected()方法,再最终调用到本地bindService时实现的onServiceConnected()方法。
//2.通过InnerConnection.connected()来调用ServiceDispatcher的connected()方法
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
//3.再调用doConnected()方法
public void doConnected(ComponentName name, IBinder service, boolean dead) {
.......
........
// If there is a new service, it is now connected.
if (service != null) {
//最终会回调ServiceConnection的onServiceConnected()方法。
mConnection.onServiceConnected(name, service);
}
}
以上就是client进行bindService()的整个流程。
四.其他
1.假设被bind的service出现异常导致crash,那本地应该如何操作呢?
2.假设本地执行unBindService时,那server端的service会如何处理呢?
跟着问题1,我们一起看一下源码实现,看一下LoadedApk中的ServiceDispatcher这个类的实现:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
......
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
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) {
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 now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
通过以上可以看到,在bind成功后,先执行了service.linkToDeath(info.deathMonitor, 0),然后才会回调本地实现的onServiceConnected()方法,接下来看一下DeathMonitor的逻辑,实现了IBinder.DeathRecipient,当binder异常后,会回调binderDied()方法:
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;
}
}
public void death(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 1, false));
} else {
doDeath(name, service);
}
}
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
return;
}
mActiveConnections.remove(name);
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
mConnection.onServiceDisconnected(name);
}
在server端出现异常crash时,会调用IBinder.DeathRecipient的binderDied()方法,即DeathMonitor的binderDied(),然后调用death()--->runnable--->doDeath(),先调用unlinkToDeath(),最后调用本地实现的onServiceDisconnected(),所以我们本地实现时,不需要自己手动执行service.linkToDeath()了,直接在onServiceDisconnected()内部重新进行bindService()就可以了。
跟着问题2,本地在执行unBindService()后,会调用到AMS,然后还是交由ActiveServices来进行处理:
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
ArrayList clist = mServiceConnections.get(binder);
......
final long origId = Binder.clearCallingIdentity();
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
clist.remove(0);
}
.....
.....
}
}
return true;
}
在unbindServiceLocked()内部会执行removeConnectionLocked(),看一下实现:
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
ArrayList clist = s.connections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
s.connections.remove(binder);
}
}
b.connections.remove(c);
if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) {
c.activity.connections.remove(c);
}
}
if (b.client != skipApp) {
b.client.connections.remove(c);
......
}
clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
if (b.connections.size() == 0) {
b.intent.apps.remove(b.client);
}
if (!c.serviceDead) {
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
bumpServiceExecutingLocked(s, false, "unbind");
......
b.intent.hasBound = false;
b.intent.doRebind = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceProcessGoneLocked(s);
}
}
......
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
.......
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
在执行removeConnectionLocked()内部会先将删除对应的ConnectionRecord,接下来会调用server端的scheduleUnbindService(),会回调到ActivityThread中的handleUnbindService(),内部调用如下:
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
//默认为false
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
ActivityManager.getService().unbindFinished(
data.token, data.intent, doRebind);
} else {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
}
.........
}
}
在handleUnbindService()内部先取到被绑定的service,然后调用service的onUnbind()方法,该方法一般不会做操作,直接super.onUnbind(),返回false,即执行跟AMS通信调用serviceDoneExecuting()来清除队列消息。
接着上面分析,最后会调用到bringDownServiceIfNeededLocked(s, true, hasAutoCreate),判断是否需要关闭service,如果没有绑定的,需要关闭service,会调用到bringDownServiceLocked(),看一下该方法:
private final void bringDownServiceLocked(ServiceRecord r) {
......
.......
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app, true);
r.app.thread.scheduleStopService(r);
}
}
............
}
......
}
内部会调用到server端的ActivityThread来执行scheduleStopService()来关闭service。即如果一个service通过bindService()来启动后,如果没有client端都执行了unBindService(),那么这个server端对应的service也就没有必要一直运行了,就需要关闭。
五.流程概括
客户端在绑定服务端的service时,主要经历了六个过程,概括如下:
a.客户端进程与ServiceManager通信获取AMS对应的IBinder
b.客户端进程通过AMS的IBinder与AMS通信,请求执行bindService()
c.AMS与服务端进程进行通信,执行scheduleBindService(),继而会执行Service的onBind()
d.服务端进程与ServiceManager通信获取AMS对应的IBinder
e.服务端进程通过AMS的IBinder与AMS通信,执行publishService(),将IBinder给AMS
f.AMS与客户端进程进行通信,将服务端的IBinder转发给客户端
bindService涉及到的类主要为ContextImpl,LoadedApk,ActivityManagerService,ActiveServices,ActivityThread等,需要进一步深入还需要看源码。