阅读 296

瞥一眼 AIDL 让 Binder 的使用变得简单

Android 中的多进程

  • 扩大应用使用内存

adb shell getprop dalvik.vm.heapsize 查看当前应用内存上限

  • 可以将容易出错的代码丢进特定进程, 这样,在特定进程崩掉,不至于引起应用所有进程崩掉。
  • 推送

推送需要通过跨进程的方式,完成消息传递。 极光推送,本质是集成了各家运营商的推送服务。极光内部做了分发。

多进程的实现

  • binder
  • socket
  • 共享内存

Android 从安全性、性能方面,最终选择了综合考虑选择了 binder. 其中的 性能通过 mmp 保证。

mmp: memory map. 将客户端进程的内存信息拷贝至 内核后, 通过 mmp 将 客户端的内存地址和服务端的内存地址放在了同一逻辑地址中。

Binader 如何用

AIDL, binder 的使用是很复杂了, 为了让开发者逃离琐碎复杂语法, Android 提供了 AIDL 简化了整个跨进程的流程。

应用场景

  1. 在 Service 中,维持一个列表,并暴露方法 addBook 往列表中添加数据。
  2. Client 想展示 Service 中列表个数。

现象

如果 service 与 client 在统一进程, 那么 onConnect 中 binder 就是 service 中 onBind 中返回的 binder。

onBind())  binder: com.aidldemo.MyService$1@27bd08d  currentThread:Thread[main,5,main]
onServiceConnected: binder:  com.aidldemo.MyService$1@27bd08d currentThread:Thread[main,5,main]
复制代码

如果 service 设置在 remote Process, client 中 onConnect 中 binder 和 service 中 onBind 中 binder 是不一样的对象。 client 中的是一个 proxy.

onBind())  binder: com.aidldemo.MyService$1@f3115ed  currentThread:Thread[main,5,main]
onServiceConnected: binder:  android.os.BinderProxy@7537253 currentThread:Thread[main,5,main]
复制代码

分析

以上现象表明,如果服务和绑定者在同一个进程,那么Client的onServiceConnected(ComponentName name, IBinder binder) binder 就是服务端的 binder. 否则就返回android.os.BinderProxy

很明显,BinderProxy 中就有跨进程的能力。

接着执行 IBookManager.Stub.asInterface(binder) 如果是同一个进程逻辑,就直接通过 binder 执行服务端的 binder 逻辑。 如果非一个进程, 就要将 BinderProxy 丢进 IBookManager.Stub.Proxy, 在 Proxy 中, 就利用 BinderProxy的跨进程能力,进行跨进程操作。即此时我在 client 端调用 addBook 的逻辑已经流转至 IBookManager.Stub.Proxy , 具体我们可以来看看源码:

private static class Proxy implements com.aidldemo.IBookManager {
    private android.os.IBinder mRemote;

    Proxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    @Override
    public android.os.IBinder asBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

	````
    @Override
    public void addBook(com.aidldemo.Book book) throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            if ((book != null)) {
                _data.writeInt(1);
                book.writeToParcel(_data, 0);
            } else {
                _data.writeInt(0);
            }
            boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
            if (!_status && getDefaultImpl() != null) {
                getDefaultImpl().addBook(book);
                return;
            }
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }
}
复制代码

上面的流程, 就帮我们将 addBook 的流程从客户端流转到了服务端。

文章分类
Android
文章标签