美文网首页Android开发经验谈Android开发
深入Android系统 Binder-2-使用

深入Android系统 Binder-2-使用

作者: Android进阶架构 | 来源:发表于2020-09-07 21:00 被阅读0次

作者:apigfly

如何使用 Binder

就开发语言而言,Binder服务可以用Java实现,也可以用C++实现,通常,我们在Java代码中调用Java语言实现的服务,在C++代码中调用C++编写的服务。但是从原理上讲,Binder并没有这种语言平台的限制,混合调用也是可以的。

应用可以在任意的进程和线程中使用Binder服务的功能,非常方便、灵活。也不用关心同步、死锁等问题

使用Binder服务

C++层和Java层使用Binder服务的方式基本一样,包括函数的接口类型都相同,这里以C++为例:

  • 使用Binder服务前要先得到它的引用对象,比如:

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService("serviceName");

    • defaultServiceManager()用来获得ServiceManager服务的Binder引用对象。前面已经说过ServiceManagerBinder引用对象是直接用数值0作为引用号构造出来的
    • sm->getService("media.camera")是查找注册的Binder服务,找到后会返回服务的IBinder对象,否则返回NULL
  • 返回的IBinder对象,其实是Binder引用对象,但是应用需要使用的是Binder代理对象,因此需要进行如下转化:

    ICameraService service = ICameraService.Stub.asInterface(binder)

    • 话说这部分应该是Java的转换方式,换成C++的版本应该是

      sp<ICameraService> service = ICameraService::asInterface(binder)

  • Binder中提供了asInterface方法来完成Binder代理对象的转换,asInterface会检查参数中的IBinder对象的服务类型是否相符,如果不符将返回NULL

正常情况下,ServiceManager进程会在所有应用启动前启动,而且不会停止服务,因此使用defaultServiceManager()不必检查返回为NULL的情况,但是对于方法getService()的返回值需要检查是否为NULL,因为服务可能不存在或者未启动。

Binder的混合调用

Binder是可以混合调用的,在C++中可以调用Java实现的Binder服务,在Java中也可以调用C++实现的Binder服务

ActivityManagerService服务为例,其中定义的方法为

public int checkPermission(String permission, int pid, int uid, int mode);

,我们看下C++调用的大体流程(有注释哈):

//获取Binder引用对象
sp<Binder> binder = defaultServiceManager()->getService("activity");
//创建Parcel data 放置方法调用是的参数信息
Parcel data = Parcel.obtain();
//创建Parcel reply 接收返回信息
Parcel reply = Parcel.obtain();
//添加接口识别Token
data.writeInterfaceToken("android.app.IActivityManager");
//添加请求的权限、pid、uid、mode等方法调用信息
data.writeString16(permission);
data.writeInt32(pid);
data.writeInt32(uid);
data.writeInt32(mode);
//调用远程函数号为54的远程服务
binder->transact(54, data, &reply, 0);

示例代码中最重要的是54这个参数,叫做远程函数号。这个号码在服务端代码中定义,而且随着系统版本不同可能会有所改变,所以示例方法并不是一个很科学和常用的方法,不要学坏哈。只是想说明Binder很强大。。。

Java层的Binder服务

我们先用组件Service来回顾一下流程:

首先,编写一个AIDL文件

interface ICommandService {
    void setResult_bool(String cmdid, boolean result);
    void setResult_byte(String cmdid, in byte[] resultMsg);
    void setResult_string(String cmdid, String resultMsg);
    void finishCommand(String cmdid, String param);
}

然后,我们创建一个自定义的Service,然后这样写:

public class CommandService extends Service{
    protected final ICommandService.Stub mBinder = new ICommandService.Stub() {
        @Override
        public void setResult_bool(String cmdid, boolean result) throws RemoteException {
            //do something
        }
        @Override
        public void setResult_byte(String cmdid, byte[] resultMsg) throws RemoteException {
            //do something
        }
        @Override
        public void setResult_string(String cmdid, String resultMsg) throws RemoteException {
            //do something
        }
        @Override
        public void finishCommand(String cmdid, String param) throws RemoteException {
            //do something
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        //do something
        return mBinder;
    }
}

ICommandService.Stub类就是真正的Binder服务类,它是通过我们前面定义的AIDL文件自动生成的,不过它是抽象的,所以我们需要继承并重写自己的业务逻辑。

C++层的Binder服务

C++层实现Bidner服务比较麻烦,主要是没有了AIDL的辅助,需要我们手动完成中间层的代码。

书中的源码部分看的有些没太看懂,本人从9.0项目源码中找了一份,我们来看下:

温馨提示:下面代码中会出现继承BnInterfaceIInterfaceBpInterface的操作,以及DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE两个宏,这里暂不做详细解释,后面会有Binder应用层的核心类详解。我们暂先理解为:继承BnInterface为实现服务端功能、继承BpInterface为实现客户端、继承IInterface表示定义要提供的服务接口

首先,是一个IImagePlayerService.h的头文件,定义了:

  • IImagePlayerService:通过纯虚函数函数定义计划提供的Binder服务接口
  • BnImagePlayerService:根据IImagePlayerService中提供的接口,定义对应的枚举对象;重载onTransact()虚拟函数

相关文章

网友评论

    本文标题:深入Android系统 Binder-2-使用

    本文链接:https://www.haomeiwen.com/subject/gdalektx.html