Android 面试抱佛脚:进程间通讯学习,从 Binder 使用看起
先看谷歌官方开发者文档的介绍 我们可以利用 AIDL 定义客户端与服务均认可的编程接口,以便二者使用进程间通信 (IPC) 进行相互通信。在安卓中,编写进程间通信的代码较为繁琐,Android 会使用 AIDL 帮我们处理这类问题。 我们先从一个典型的 AIDL 实例入手来探究。
定义 AIDL 接口
我们来定义一个 aidl 接口文件
//IHelloManager.aidl
package top.guuguo.wanandroid.tv;
import top.guuguo.wanandroid.tv.User;
interface IHelloManager {
User getFriend();
void setFriend(in User friend);
}
//User.aidl
package top.guuguo.wanandroid.tv;
parcelable User;
其中用到了 User 对象,所以上文还定义了该User.aidl
,该对象实现 Parcelable 接口。 我们找到generated/aidl_source_output_dir
观察对应生成的 java 类:IHelloManager.java
。
public interface IHelloManager extends android.os.IInterface {
/**
Default implementation for IHelloManager.
*/
public static class Default implements top.guuguo.wanandroid.tv.IHelloManager {
/***/
}
/**
Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements top.guuguo.wanandroid.tv.IHelloManager {
/***/
private static class Proxy implements top.guuguo.wanandroid.tv.IHelloManager {
/***/
}
}
public top.guuguo.wanandroid.tv.User getFriend() throws android.os.RemoteException;
public void setFriend(top.guuguo.wanandroid.tv.User friend) throws android.os.RemoteException;
}
可以看到生成了IHelloManager
接口,实现IInterface
。可以看到默认生成了三个该接口的实现类。Default
,Stub
和Stub.Proxy
。 Stub
是一个Binder
类,是一个实例是服务端对象。Stub.Proxy
是Proxy
的服务端代理类,其中执行方法的时候,调用了服务端的 transact 方法进行进程间数据交互转换,这两个实现类就是IHelloManager
的核心类。 看看 Stub 类的代码:
public static abstract class Stu
b extends android.os.Binder implements top.guuguo.wanandroid.tv.IHelloManager {
private static final java.lang.String DESCRIPTOR = "top.guuguo.wanandroid.tv.IHelloManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static top.guuguo.wanandroid.tv.IHelloManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof top.guuguo.wanandroid.tv.IHelloManager))) {
return ((top.guuguo.wanandroid.tv.IHelloManager) iin);
}
return new top.guuguo.wanandroid.tv.IHelloManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {}
@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_getFriend: {
data.enforceInterface(descriptor);
top.guuguo.wanandroid.tv.User _result = this.getFriend();
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_setFriend: {
data.enforceInterface(descriptor);
top.guuguo.wanandroid.tv.User _arg0;
if ((0 != data.readInt())) {
_arg0 = top.guuguo.wanandroid.tv.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.setFriend(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
static final int TRANSACTION_getFriend = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setFriend = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public static boolean setDefaultImpl(top.guuguo.wanandroid.tv.IHelloManager impl) {
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static top.guuguo.wanandroid.tv.IHelloManager getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
下面介绍一下Stub
类中成员的含义:
Binder的唯一标识,一般是当前Binder的类名。本例是
"top.guuguo.wanandroid.tv.IHelloManager"
将服务端的 Binder 对象转换成对应 AIDL 接口对象。通过queryLocalInterface
区分进程,如果双端是在同一进程中,返回的对象就是 Stub 对象,如果是在不同的进程中,则返回其 Proxy 代理对象。
返回当前 Binder 实例
该方法对传输的数据进行序列化和反序列化操作。完整的方法是public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
。该方法中,通过 code 定位客户端所请求的方法是什么,接着从 data 中取出方法所需的参数,然后执行目标方法,如果目标方法有返回值,向reply
写入返回结果。 该方法如果返回 false,那么客户端的请求就会失败。我们可以在该方法做一些调用限制,避开一些不期望的进程调用该方法。
这两个代理方法先处理传入参数,将其写入到Parcel
中,然后调用mRemote.transact
发起 RPC(远程过程调用)请求。同时当前线程挂起,直到 RPC 过程返回后,再继续执行当前线程,并取出reply
的返回结果。反序列化后返回数据。
通过上面 AIDL 及其生成代码的分析,我们知道了 AIDL 只是个便于我们快速生成 Binder 通讯模板代码的方式。我们要在相关组件中使用该 Binder 进行 IPC 时,需要通过绑定服务获取Binder
实例。 下面是绑定服务获取binder
的相关代码:
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
"onServiceConnected".toast()
binder = IHelloManager.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
"onServiceDisconnected".toast()
}
}
override fun onStart() {
super.onStart()
val intent = Intent(this, HelloService::class.java)
intent.action = ":startHello"
bindService(intent, connection, BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
unbindService(connection)
}
从上面的代码中,我们就可以通过bindService
获取aidl
定义的Binder
实例。通过该 Binder 实例,直接就可以对远程进程进行方法调用了。绑定服务具体的流程是什么呢? 现在看一下整个调用路径
发起绑定服务:
mBase.bindService
定位到具体的绑定方法:经过查阅
Activity#attach
方法、ActivityThread#performLaunchActivity
方法和createBaseContextForActivity
方法,得知mBase
是ContextImpl
实例。
mBase.bindService
调用到了ContextImpl#bindServiceCommon
方法
获取
ActivityManager
Binder 代理对象:在ActivityManager.``*getService*``()
方法中,从ServiceManager.getService(Context.ACTIVITY_SERVICE)
获取 IBinder 实例(BinderProxy)
通过
ActivityManager
调用ActivityManagerService
的绑定服务方法,进行绑定服务。
查阅源码和网络搜索中发现,获取Binder
和binder
通信原理,涉及到 AOSP 源码中的ServiceManager
,Binder
的 native C/S
实现等,暂不学习,放到以后针对性得学习 aosp 中的 binder 通信机制。对应地,先学习一下Skytoby大佬的Binder机制分析文章,了解个大概。 借用作者的 Binder 机制结构图如下:
接下来再看,以及如何手写 binder 的实现。
通过上面的分析,我们大致了解了Binder
的工作机制。所以我们尝试一下不使用 aidl,使用 binder 进行进程通讯。 基础的实现只需要写三个类就行
定义接口类
interface IActivityManager : IInterface {
fun startActivity(code: Int): String?
}
服务端 Binder 抽象类,在 onTransact 完成远程输送的数据反序列化以及服务端执行任务的工作。
abstract class ActivityManager : Binder(), IActivityManager {
companion object {
val DESCRIPTOR = "top.guuguo.aidltest.IActivityManager"
val CODE_START_ACTIVITY = FIRST_CALL_TRANSACTION + 0
fun asInterface(obj: IBinder?): IActivityManager? {
if (obj == null) return null
return (obj.queryLocalInterface(DESCRIPTOR)
?: Proxy(obj)) as IActivityManager
}
}
override fun asBinder(): IBinder {
return this
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
when (code) {
INTERFACE_TRANSACTION -> {
reply?.writeString(DESCRIPTOR);
return true;
}
CODE_START_ACTIVITY -> {
data.enforceInterface(DESCRIPTOR)
reply?.writeNoException()
reply?.writeString(startActivity(data.readInt()))
return true
}
}
return super.onTransact(code, data, reply, flags)
}
}
客户端代理类(完成数据的序列化反序列化工作,具体交给代理的对象完成)
class Proxy(val remote: IBinder) : ActivityManager() {
override fun startActivity(code: Int): String? {
val params = Parcel.obtain()
val reply = Parcel.obtain()
params.writeInterfaceToken(DESCRIPTOR)
params.writeInt(code)
remote.transact(CODE_START_ACTIVITY, params, reply, 0)
reply.readException()
评论