[DEMO] Android Binder 的使用

参考:

The Android binderfs Filesystem — The Linux Kernel documentation

前言:

Android Binder 是一种 IPC 机制,IPC 键值/标识 是一个字符串,收发双方通过 键值/标识 建立通讯路径。

Binder 是通过模板类实现的,因此使用起来并不是那么简明通俗,如果没有demo可以参考的话是需要琢磨好一阵子。

相关头文件:

//  \frameworks\native\include\binder\IInterface.h
#include <binder/IInterface.h>
//  \frameworks\native\include\binder\IBinder.h
#include <binder/IBinder.h>

重要的类:

class IInterface 

IPC 的收发双方需要约定交互接口,因此收发双方都需要通过某种方式集成这个类,一般情况下会定义一个类来继承IInterface,然后收发双方再通过类模板的方式对新定义的接口类做集成。

//  \frameworks\native\include\binder\IInterface.h
class IInterface : public virtual RefBase
{
public:
            IInterface();
            static sp<IBinder>  asBinder(const IInterface*);
            static sp<IBinder>  asBinder(const sp<IInterface>&);

protected:
    virtual                     ~IInterface();
    virtual IBinder*            onAsBinder() = 0;          //需要子类实现
};

//  \frameworks\native\libs\binder\IInterface.cpp
IInterface::IInterface() 
    : RefBase() {
}

IInterface::~IInterface() {
}

// static
sp<IBinder> IInterface::asBinder(const IInterface* iface)
{
    if (iface == nullptr) return nullptr;
    return const_cast<IInterface*>(iface)->onAsBinder();
}

// static
sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
{
    if (iface == nullptr) return nullptr;
    return iface->onAsBinder();
}

class BpInterface

BpInterface 是模板类,他继承自一个 IInterface 的子类,同时也继承 BBinder,如果我们实现 Binder的 Client 端,则可以使用这个类作为父类。

//  \frameworks\native\include\binder\IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
    explicit                    BpInterface(const sp<IBinder>& remote);

protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
{
}

template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote();
}

前面说到 IInterface 的 onAsBinder 为纯虚函数,这里 BpInterface 就实现了这个纯虚函数,通过调用父类 BpRefBase 的 remote() 方法返回一个 IBinder。

//  \frameworks\native\include\binder\Binder.h
class BpRefBase : public virtual RefBase
{
protected:
    explicit                BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);

    inline  IBinder*        remote()                { return mRemote; }
    inline  IBinder*        remote() const          { return mRemote; }

private:
                            BpRefBase(const BpRefBase& o);
    BpRefBase&              operator=(const BpRefBase& o);

    IBinder* const          mRemote;
    RefBase::weakref_type*  mRefs;
    std::atomic<int32_t>    mState;
};

class BnInterface

BnInterface 和 BpInterface 类似,它一般用作 Binder Server 端。区别在于切换至 IBinder 角色的方法不一样,Bp是 return remote() ,Bn 是直接返回自己。

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};

template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
        const String16& _descriptor)
{
    if (_descriptor == INTERFACE::descriptor) return this;
    return nullptr;
}

template<typename INTERFACE>
inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
{
    return INTERFACE::getInterfaceDescriptor();
}

template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
    return this;
}

BnInterface 是继承自 BBinder 的,这个类规定了作为 Binder 服务端应该具备哪些特质,一般情况下我们需要重写 onTransact 函数以完成我们自己的消息处理逻辑。

class BBinder : public IBinder
{
public:
                        BBinder();

    virtual const String16& getInterfaceDescriptor() const;
    virtual bool        isBinderAlive() const;
    virtual status_t    pingBinder();
    virtual status_t    dump(int fd, const Vector<String16>& args);

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    transact(   uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
                                    void* cookie = nullptr,
                                    uint32_t flags = 0);

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                        void* cookie = nullptr,
                                        uint32_t flags = 0,
                                        wp<DeathRecipient>* outRecipient = nullptr);

    virtual void        attachObject(   const void* objectID,
                                        void* object,
                                        void* cleanupCookie,
                                        object_cleanup_func func);
    virtual void*       findObject(const void* objectID) const;
    virtual void        detachObject(const void* objectID);

    virtual BBinder*    localBinder();

    bool                isRequestingSid();
    // This must be called before the object is sent to another process. Not thread safe.
    void                setRequestingSid(bool requestSid);

protected:
    virtual             ~BBinder();

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);

private:
                        BBinder(const BBinder& o);
            BBinder&    operator=(const BBinder& o);

    class Extras;

    Extras*             getOrCreateExtras();

    std::atomic<Extras*> mExtras;
            void*       mReserved0;
};

Demo

DemoInterface.h

#include <binder/IInterface.h>

// 一定要是I 开头
class IDemo : public IInterface {

//  client use
  enum {
     MSG_1,
     MSG_2,
     MSG_3,
     MSG_CNT
  }
  //  通过虚函数强制要求client实现,client通过下面这几个函数里向server侧发送MSG,并同步等待应答
  virtual void postMSG1(int i) = 0;  //带参数,组装到 MSG 里面发送给server
  virtual void postMSG2() = 0;
  virtual int postMSG3() = 0;  //可以是有返回值的

  DECLARE_META_INTERFACE(Demo);  //对应类名 I 之后的那部分
  IMPLEMENT_META_INTERFACE(Demo,"Demo"); //实现部分
}

BpDemo.h

#include "DemoInterface.h"

class BpDemo : public BpInterface<IDemo> 
{
public:
   //BpInterface本身没有默认构造函数,所以只能使用唯一的一个构造函数来构造,
   //这个构造函数接受一个IBinder指针作为输入,这个IBinder指向一个Binder对象,
   //所以我们实现的其子类 BpDemo 也必须有一个接受 IBinder 指针入参的构造函数来
   //构造其父类 BpInterface, 并且需要用这个 IBinder 指针构造 BpInterface。
   //
   // 小结 : 作为client侧,需要在构造的时候就知道 server 侧对应的那个 Binder是什么,这很合理
   //
   BpDemo(const sp<IBinder>& impl)
     :BpInterface<IDemo>(impl) 
   {

   }
   virtual ~BpDemo() {;}

   //必须实现IDemo中的纯虚函数
   virtual void postMSG1(int i){
      Parcel data, replay;
      //写Binder的键值(token)
      data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
      data.writeInt32(i); //写需要传输的字段

      //使用BpInterface父类的remote()方法获取BBinder对象,调用transact()传输MSG
      remote()->transact(MSG1,data,&reply);
   }

   virtual void postMSG1(){
      Parcel data, replay;
      data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
      remote()->transact(MSG2,data,&replay,IBinder::FLAG_ONEWAY); //异步
   }

   virtual int postMSG3(){
      Parcel data, replay;
      data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
      remote()->transact(MSG3,data,&replay);
      int ret;
      reply.readInt32(ret);    //
      return ret;
   }

}


/*
BpInterface<IDemo> 展开为

class BpInterface : public IDemo, public BpRefBase
{
public:
    explicit         BpInterface(const sp<IBinder>& remote);

protected:
    typedef IDemo           BaseInterface;
    virtual IBinder*        onAsBinder();
};
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/36737.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gigachad1靶机详解

gigachad_vh靶机详解 扫描到ip后对ip做一个全面扫描&#xff0c;发现有一个匿名服务器&#xff0c;是可以免密登陆的。 登陆上后发现就一个文件&#xff0c;get到我们电脑上。 file一下发现是一个zip文件&#xff0c;unzip解压一下&#xff0c;发现给了一个用户名chad&#xf…

【数据挖掘】时间序列教程【二】

2.4 示例:颗粒物浓度 在本章中,我们将使用美国环境保护署的一些空气污染数据作为运行样本。该数据集由 2 年和 5 年空气动力学直径小于或等于 3.2017 \(mu\)g/m\(^2018\) 的颗粒物组成。 我们将特别关注来自两个特定监视器的数据,一个在加利福尼亚州弗雷斯诺,另一个在密…

软考:中级软件设计师:存储管理,分区存储,页式存储,逻辑地址,物理地址

软考&#xff1a;中级软件设计师:存储管理&#xff0c;分区存储 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是…

LLM - Baichuan7B Tokenizer 生成训练数据

目录 一.引言 二.Tokenizer 原始数据 1.原始数据样例 2.加载并 Token 原始数据 2.1 参数准备 2.2 单条样本处理逻辑 2.3 批量处理逻辑 2.4 主函数与完整代码 三.shell 执行 四.总结 一.引言 前面提到了自己在微调 Baichuan7B Lora 的过程中遇到了一些问题&#xff0c…

leetcode 236. 二叉树的最近公共祖先

2023.7.11 这道题是道面试高频题&#xff0c;并且有点抽象。 首先确定终止条件。如果根节点为空&#xff0c;或者其中一个节点是根节点本身&#xff08;即 p root 或 q root&#xff09;&#xff0c;那么根节点就是它们的最低共同祖先&#xff0c;因此我们直接返回根节点 roo…

产品经理怎么管理项目进度?

作为在职七年的项目管理人员&#xff0c;在项目进度管理上确实有一点发言权。产品经理作为企业的核心骨干岗位之一&#xff0c;在进行项目进度管理时也会有很多问题出现&#xff0c;那么应该怎样去管理项目进度呢&#xff1f;以下是答主的一些拙见&#xff0c;有需要的朋友们就…

接口测试之postman使用详解

我们平常要做接口测试时&#xff0c;可能需要使用一些工具&#xff0c;其实最简单的的做接口测试的工具就是postman&#xff0c;它可以用来模拟http中的get、post接口等&#xff0c;然后我们去验证接口的返回参数及数据是否符合我们的逻辑。那么怎么使用呢&#xff1f;也就是今…

C++之工厂模式

目录 一、为什么要使用工厂模式 优点 缺点 二、简单工厂&#xff08;Simple Factory&#xff09; 好处&#xff1a; 不足&#xff1a; 三、工厂方法&#xff1a; 好处&#xff1a; 不足&#xff1a; 四、抽象工厂&#xff08;Abstract Factory&#xff09; 一、为什…

【工具推荐】企业微信、企业飞书接口调用工具

github地址: GitHub - fasnow/idebug: 企业微信、企业飞书接口调用工具。 简介 企业微信、企业飞书接口调用工具。 使用方法 wechat模块 使用use wechat 选择模块。 首先设置corpid和corpsecret&#xff0c;如有需要可以设置代理&#xff0c;之后再执行run命令。 导出通信…

chatgpt 与传统3D建模对比分析

推荐&#xff1a;将NSDT场景编辑器加入你的3D工具链 随着人工智能技术的发展&#xff0c;越来越多的领域正逐渐被AI模型所取代。ChatGPT作为一种自然语言处理技术&#xff0c;越来越为人们所熟悉。最近&#xff0c;一些3D建模领域的专家想知道ChatGPT是否可以取代传统的手动3D建…

在?聊聊浏览器事件循环机制

目录 前言 同步/异步编程模型 同步 异步 JS异步模型 调用栈 任务队列 宏任务队列 微任务队列 微任务API 事件循环 队列优先级 混合队列 事件循环实现 总结 参考文章 Event-Loop可视化工具 前言 JS是单线程语言&#xff0c;在某个时间段只能执行一段代码。这…

IP地址定位技术为何如此准确?揭秘背后原理

据最新数据显示&#xff0c;全球互联网用户数量已突破50亿。为确保用户安全和提供个性化服务&#xff0c;IP地址定位技术愈发重要。但你是否好奇&#xff0c;为何IP地址定位如此准确&#xff1f;今天我们将揭秘其背后原理。 IP地址定位技术利用了多种方法来确定用户的地理位置。…

mac苹果电脑,怎么把mkv转换mp4格式

mac苹果电脑&#xff0c;怎么把mkv转换mp4格式&#xff1f;如果你是一名mac苹果电脑的用户&#xff0c;在电脑上下载到mkv格式的视频后会发现它使用起来非常的麻烦&#xff0c;甚至不能直接打开播放。mkv其实也是一种时间比较久远的视频文件格式&#xff0c;但是不知道是什么原…

MAC电脑查看SHA256方式

背景 现在很多网站下载大文件时&#xff0c;以往通过查看文件大小来确定是否下载正确&#xff0c;但是很多情况下&#xff0c;文件下载后大小差不多&#xff0c;但是很多时候却时候出现无法安装的问题&#xff0c;有可能还是下载的文件出现错误&#xff0c;导致文件无法正常使…

研发效能认证学员作品:使用威胁建模进行DevSecOps实践

一、从DevOps到 DevSecOps 作者&#xff1a; 姚圣伟&#xff08;现就职天津引元科技 天津市区块链技术创新中心&#xff09; 研发效能&#xff08;DevOps&#xff09;工程师认证学员 DevOps 最开始最要是强调开发和运维的协作与配合&#xff0c;至今&#xff0c;已不仅仅涉及开…

【运维工程师学习二】OS系统管理

【运维工程师学习二】OS系统管理 1、操作系统管理2、进程管理3、进程的启动4、进程信息的查看4.1、STAT 进程的状态&#xff1a;进程状态使用字符表示的&#xff08;STAT的状态码&#xff09;,其状态码对应的含义&#xff1a;4.2、ps命令常用用法&#xff08;方便查看系统进程&…

stm32(独立看门狗和窗口看门狗)

独立看门狗介绍 什么是看门狗&#xff1f; 在由单片机构成的微型计算机系统中&#xff0c;由于单片机的工作常常会受到来自外界电磁场的干扰&#xff0c;造 成程序的跑飞&#xff0c;而陷入死循环&#xff0c;程序的正常运行被打断&#xff0c;由单片机控制的系统无法继续工作…

Vue3 网络请求——axios 高级用法之 axios 拦截器实战与并发请求

文章目录 &#x1f4cb;前言&#x1f3af;关于拦截器&#x1f3af;项目创建&#x1f3af;代码分析&#x1f3af;补充&#xff1a;并发请求&#x1f9e9;axios.all() 和 Promise.all() 的区别 &#x1f4dd;最后 &#x1f4cb;前言 Axios 是一个流行的基于 Promise 的 HTTP 客户…

spring系列所有漏洞vulhub复现CVE-2022-22978、CVE-2022-22963、CVE-2022-22965、CVE-2018-1273

文章目录 CVE-2022-22978 Spring-security 认证绕过漏洞漏洞描述:复现&#xff1a; CVE-2022-22963漏洞描述:复现&#xff1a; 提提神Spring框架Data Binding与JDK 9导致的远程代码执行漏洞&#xff08;CVE-2022-22965&#xff09;漏洞描述:复现&#xff1a; Spring Data Commo…

机器学习笔记:随机森林

1 集成学习 集成学习通过构建多个学习器采用加权的方式来完成学习任务一般来讲&#xff0c;多个学习器同属于一种模型&#xff0c;比如决策树&#xff0c;线性模型&#xff0c;而不会交叉用多种模型为了保证集成学习的有效性&#xff0c;多个弱分类器之间应该满足两个条件 准确…
最新文章