背景
事情的起因是解决如何判断aidl服务端使用的客户端对象是否为同一个对象。于是引发了asBinder的使用,RemoteCallbackList使用,以及很少使用的IBinder.DeathRecipient。
需求场景
此篇介绍可以帮助解决aidl使用中的生命周期控制、对象维护以及资源释放,保活服务问题。
对象判等
当服务端接口有接收客户端aidl定制的对象时,例如维护一个listener列表。你可能需要避免相同对象被重复添加到集合。这个时候需要在服务端接口内对对象执行asBinder操作,此操作返回的是客户端的Binder对象。
原理:
1、看Proxy代理
private static class Proxy implements IAssistantOemService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
}
2、Proxy创建是在Stub代理中
public static abstract class Stub extends android.os.Binder implements IAssistantOemService {
/**
* Cast an IBinder object into an com.google.assistant.IAssistantOemService interface,
* generating a proxy if needed.
*/
public static com.google.assistant.IAssistantOemService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.google.assistant.IAssistantOemService))) {
return ((com.google.assistant.IAssistantOemService) iin);
}
return new com.google.assistant.IAssistantOemService.Stub.Proxy(obj);
}
结论:很明显,stub是客户端代理,proxy服务端代理最后总是取得客户端的对象。所以aidl服务端判断相等需要取asBinder对象,否则取到的就是Proxy对象,无法判等。
服务端如何存储对象
1、比较简答的写法,维护一个map就好了。
private SafeIterableMap<IBinder, IListener> mObservers =
new SafeIterableMap<>();
但是客户端死掉了怎么处理垃圾Listener?
2、使用可以绑定IBinder死掉的工具类RemoteCallbackList。
private final class Callback implements IBinder.DeathRecipient {
final E mCallback;
final Object mCookie;
Callback(E callback, Object cookie) {
mCallback = callback;
mCookie = cookie;
}
public void binderDied() {
synchronized (mCallbacks) {
mCallbacks.remove(mCallback.asBinder());
}
onCallbackDied(mCallback, mCookie);
}
}
里边最主要的实现了IBinder.DeathRecipient。当然RemoteCallbackList是一个很不错的对象集合实现,当你需要在服务端保存一个对象集合时,可以考虑用它。
IBinder的死亡监听
1、IBinder关于死亡监听的几个方法
/**检查需要使用的Binder是否存活
* Check to see if the object still exists.
*
* @return Returns false if the
* hosting process is gone, otherwise the result (always by default
* true) returned by the pingBinder() implementation on the other
* side.
*/
public boolean pingBinder();
/**需要监听Binder死亡的需要实现这个接口,这个接口在调用linkToDeath后会被注册
* Interface for receiving a callback when the process hosting an IBinder
* has gone away.
*
* @see #linkToDeath
*/
public interface DeathRecipient {
public void binderDied();
}
/**简单说你需要调用这个方法传入自定义的DeathRecipient进行注册。
* Register the recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
* (typically because its hosting process has been killed),
* then the given {@link DeathRecipient}'s
* {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
* will be called.
*
* <p>You will only receive death notifications for remote binders,
* as local binders by definition can't die without you dying as well.
*
* @throws RemoteException if the target IBinder's
* process has already died.
*
* @see #unlinkToDeath
*/
public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
throws RemoteException;
2、IBinder.linkToDeath的实现
/**Binder.java中这个方法的实现是个空方法,也就是说Binder创建的进程不需要处理这个
* Local implementation is a no-op.
*/
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
}
/**BinderProxy.java这个是跨进程的代理Binder,实现是个native方法
* See {@link IBinder#linkToDeath(DeathRecipient, int)}
*/
public native void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException;
AIDL特殊使用
1、pingBinder()方法会返回当前远程服务的状态(true|false)
2、客户端可以捕获RemoteException(DeadObjectException)得知服务端状态,可以用于释放资源或者重启服务。
3、使用RemoteCallbackList存储对象集合,用于避免对象重复。
3、客户端实现IBinder.DeathRecipient接口,用于监听服务器死亡状态,可以用于释放资源或者重启服务。
4、服务端实现IBinder.DeathRecipient接口,用于监听客户端死亡状态,去除保留的客户端对象。(这点还蛮重要的,有利于避免aidl服务端对多个客户端时的空指针,内存占用问题)