Framework篇 - 如何使用 Binder

今天来写两个 Binder 的例子,一个 native 层,一个 Framework 层。

 

目录:

  1. native 层使用 Binder
  2. Framework 层使用 Binder

 

 

1. native 层使用 Binder

 

  • 1.1 源码目录

ClientDemo.cpp:客户端程序
ServerDemo.cpp:服务端程序
IMyService.h:自定义的 MyService 服务的头文件
IMyService.cpp:自定义的 MyService 服务
Android.mk:源码 build 文件

 

  • 1.2 IMyService.h
//
// Created by Mr.Kuang on 2019/3/4.
//

#ifndef BINDERAIDLDEMO_IMYSERVICE_H
#define BINDERAIDLDEMO_IMYSERVICE_H

namespace android {
    class IMyService : public IInterface {
        public:
            // 使用宏,申明MyService
            DECLARE_META_INTERFACE(MyService);
            // 定义方法
            virtual void sayHello() = 0;
    };

    // 定义命令字段
    enum {
        HELLO = 1,
    };

    // 声明客户端 BpMyService
    class BpMyService: public BpInterface<IMyService> {
        public:
            BpMyService(const sp<IBinder>& impl);

            virtual void sayHello();
    };

    // 声明服务端 BnMyService
    class BnMyService: public BnInterface<IMyService> {
        public:
            virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
            
            virtual void sayHello();
    };
}
#endif //BINDERAIDLDEMO_IMYSERVICE_H

主要功能:

  • 声明 IMyService。
  • 声明 BpMyService (Binder 客户端)。
  • 声明 BnMyService (Binder 的服务端)。

 

  • 1.3 IMyService.cpp
//
// Created by Mr.Kuang on 2019/3/4.
//

#include "IMyService.h"

namespace android {

      // 使用宏,完成 MyService 定义
      IMPLEMENT_META_INTERFACE(MyService, "android.demo.IMyService");

      // 客户端
      BpMyService::BpMyService(const sp<IBinder>& impl) : BpInterface<IMyService>(impl) {
      }

      // 实现客户端 sayHello 方法
      void BpMyService::sayHello() {
          printf("BpMyService::sayHello\n");
          Parcel data, reply;
          data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
          remote()->transact(HELLO, data, &reply);
          printf("get num from BnMyService: %d\n", reply.readInt32());
      }

      // 服务端,接收远程消息,处理onTransact方法
      status_t BnMyService::onTransact(uint_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
          switch (code) {
             // 收到 HELLO 命令的处理流程
             case HELLO: {
                  printf("BnMyService:: got the client hello\n");
                  CHECK_INTERFACE(IMyService, data, reply);
                  sayHello();
                  reply->writeInt32(2015);
                  return NO_ERROR;
              }
                  break;
              default:
                  break;
              }
              return NO_ERROR;
          }

      // 实现服务端 sayHello 方法
      void BnMyService::sayHello() {
          printf("BnMyService::sayHello\n");
      };
}

 

  • 1.4 ServerDemo.cpp
//
// Created by Mr.Kuang on 2019/3/4.
//

#include "IMyService.h"

int main() {
    // 获取service manager 引用
    sp<IServiceManager> sm = defaultServiceManager();
    // 注册名为 "service.myservice" 的服务到 service manager
    sm->addService(String16("service.myservice"), new BnMyService());
    // 启动线程池
    ProcessState::self()->startThreadPool();
    // 把主线程加入线程池
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

将名为 "service.myservice" 的 BnMyService 服务添加到 ServiceManager,并启动服务。

 

  • 1.5 ClientDemo.cpp
//
// Created by Mr.Kuang on 2019/3/4.
//

#include "IMyService.h"

int main() {
    // 获取service manager引用
    sp<IServiceManager> sm = defaultServiceManager();
    // 获取名为 "service.myservice" 的 binder 接口
    sp<IBinder> binder = sm->getService(String16("service.myservice"));
    // 将 biner 对象转换为强引用类型的 IMyService
    sp<IMyService> cs = interface_cast<IMyService>(binder);
    // 利用binder引用调用远程sayHello()方法
    cs->sayHello();
    return 0;
}

获取名为 "service.myservice" 的服务,再进行类型转换,最后调用远程方法 sayHello()。

 

  • 1.6 原理图

 

 

  • 1.7 运行

1. 编译生成:利用 Android.mk 编译上述代码,在 Android 的源码中,通过 mm 编译后,可生成两个可执行文件ServerDemo,ClientDemo。

2. 将这 ServerDemo,ClientDemo 可执行文件 push 到手机。

adb push ServerDemo /system/bin
adb push ClientDemo /system/bin

如果 push 不成功,那么先执行 adb remount,再执行上面的指令;如果还不成功,可能就是权限不够。

如果上述开启成功,通过开启两个窗口运行 (一个运行 client 端,另一个运行 server 端)。

3. adb shell,进入 shell 模式。然后分别执行:/system/bin/ServerDemo,/system/bin/ClientDemo。

 

 

2. Framework 层使用 Binder

上面是在 native 层实现了一个 Binder demo,现在用 Java 来实现一个 Binder demo。

 

  • 2.1 源码目录

Server 端:

ServerDemo.java:可执行程序
IMyService.java:定义 IMyService 接口
MyService.java:定义 MyService

Client 端:

ClientDemo.java:可执行程序
IMyService.java:与 Server 端完全一致
MyServiceProxy.java:定义 MyServiceProxy

 

  • 2.2 代码实现 
public interface IMyService extends IInterface {

    static final java.lang.String DESCRIPTOR = "io.kzw.frameworkBinder.MyServer";

    public void sayHello(String str) throws RemoteException;

    static final int TRANSACTION_say = android.os.IBinder.FIRST_CALL_TRANSACTION;
}
public class MyService extends Binder implements IMyService{

    public MyService() {
        this.attachInterface(this, DESCRIPTOR);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    /** 将MyService转换为IMyService接口 **/
    public static IMyService asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
        if (((iInterface != null) && (iInterface instanceof IMyService))){
            return ((IMyService) iInterface);
        }
        return null;
    }

    /** 服务端,接收远程消息,处理onTransact方法 **/
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_say: {
            data.enforceInterface(DESCRIPTOR);
            String str = data.readString();
            sayHello(str);
            reply.writeNoException();
            return true;
        }}
        return super.onTransact(code, data, reply, flags);
    }

    /** 自定义sayHello()方法 **/
    @Override
    public void sayHello(String str) {
        System.out.println("MyService:: Hello, " + str);
    }
}
public class ServerDemo {

    public static void main(String[] args) {
        System.out.println("MyService Start");
        // 准备Looper循环执行
        Looper.prepareMainLooper();
        // 设置为前台优先级
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);
        // 注册服务
        ServiceManager.addService("MyService", new MyService());
        Looper.loop();
    }
}
public class MyServiceProxy implements IMyService {
    // 代表 BpBinder
    private android.os.IBinder mRemote;  

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

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

    /** 自定义的sayHello()方法 **/
    @Override
    public void sayHello(String str) throws RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeString(str);
            mRemote.transact(TRANSACTION_say, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }
}
public class ClientDemo {

    public static void main(String[] args) throws RemoteException {
        System.out.println("Client start");
        // 获取名为"MyService"的服务
        IBinder binder = ServiceManager.getService("MyService"); 
        // 创建MyServiceProxy对象
        IMyService myService = new MyServiceProxy(binder); 
        // 通过MyServiceProxy对象调用接口的方法
        myService.sayHello("binder"); 
        System.out.println("Client end");
    }
}

 

  • 2.3 运行

首先将 ServerDemo,ClientDemo 以及可执行文件 ServerDemo.jar,ClientDemo.jar 都 push 到手机:

adb push ServerDemo /system/bin 

adb push ClientDemo /system/bin 

adb push ServerDemo.jar /system/framework 

adb push ClientDemo.jar /system/framework 

如果 push 不成功,那么先执行 adb remount,再执行上面的指令;如果还不成功,可能就是权限不够。 如果上述开启成功,通过开启两个窗口运行 (一个运行 client 端,另一个运行 server 端)。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值