Android两个进程间内存相互独立不能互相访问,跨进程传输非默认类型对象需要先序列化,而不能直接简单传递引用,序列化的目的是将对象数据以能够在内存中流通的形式从一个进程传递到另一个进程,两个进程对象的传递类似深度clone,client端将对象数据写入Parcel(writeToParcel),server端从Parcel(readFromParcel)读取对象数据并重新创建一个同样的对象将读取到的数据填充到此对象,但这两个对象并不是一样的,只是他们的数据完全一样。
AIDL作为一种跨进程通信的方案,底层依赖Binder,跨进程通信时会调用AIDL中定义的方法,会把 caller(调用者,后文只用caller)的参数数据 copy 到 callee(接收者,后文只用callee),然后在callee进程中调用另外一个代理对象的相同方法,这个逻辑由Binder框架封装;使用者上层看起来,感觉是直接调用了对方进程中对象的方法。
AIDL文件在编译后会生成2个重要的实现类:
- Stub
callee被调用时,会通过Stub.onTransact(code, data, reply, flag)间接地调用本地对象(Local Binder)的对应方法。- Proxy
caller调用AIDL方法时,最终通过Proxy调用remote.transact(code, _data, _reply, flag),然后通过Binder机制调用到远程的相应方法。
上面的onTransact() 和 transact() 方法都是Binder定义的方法,更底层的跨进程逻辑由Binder机制实现,就不是本文的重点了。
根据源码和 demo 的验证结果,我们可以得出结论了:
Directional Tag | Desc |
in | 数据从 caller传到 callee,callee 调用结束后不会把数据写回 caller 中。 |
out | caller 数据不会传入 callee(因为就没有写数据), callee 调用结束后(不管数据有没有更新)会把数据写回 caller 中。 |
inout | 数据从 caller 传到 callee,callee 调用结束后(不管数据有没有更新)会把数据写回 caller 中。 |
提了这么多次 caller 和 callee ,是不想把它们与 client 和 server 混淆;因为 client 与 server 可以互相调用,AIDL文件编译后的代码是一样的,client 与 server 在作为 caller 或 callee 时执行的(AIDL层)逻辑是相同的,所以不能说in / out / inout 是明确地表示 client 到 server 的方向(或者相反)。