Android 13(T) - binder阅读(3)- binder相关的类

news2025/1/16 21:32:10

原先准备在binder阅读(3)中记录ServiceManager的使用,但是写着写着发现,如果不了解和binder相关的类,那么阅读起来将会由很多困惑,所以就先来记录binder相关的类了。记录完发现特别凌乱…先就这样吧。

1 UML类图

从 binder阅读(1)一开始的图中可以看到,getService获得的是一个handle,要怎样才能用这个handle完成RPC呢?Android为我们提供了一套框架,以下是框架相关类的UML类图。

我们设计的service需要遵循这套框架才能注册到binder驱动中,client也要遵循这套框架才能实现对service的调用。

请添加图片描述
接下来我们将会一起了解下面这张图中的内容。

binder框架代码位置: frameworks/native/libs/binder/
我将以MediaServer为例,代码位置:frameworks/av/media/libmedia/


2 IBinder

IBinder声明于IBinder.h,实现于Binder.cpp。

想要让一个类对象能够通过binder驱动进行跨进程传输,那么这个class必须要继承自IBinder接口。

IBinder服务本体远程代理提供了基本接口,并提供了一些基础实现,本体和代理均需要实现这些接口。


2 BBinder

BBinder声明于Binder.h,实现于Binder.cpp。

BBinder服务本体IBinder的实现。BBinder覆写了localBinder方法,使其可以返回服务本体,调用BBinder对象的remoteBinder方法将会返回null。

BBinder* BBinder::localBinder()
{
    return this;
}

transact方法用于执行远程代理的调用,根据不同的code执行不同的方法,transact已经实现了一些基本的调用,服务自定义的调用需要在onTransact做实现,该工作由子类完成。

virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) final;

virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);

3 BpBinder

BpBinder声明于BpBinder.h,实现于BpBinder.cpp。

BpBinder远程代理IBinder的实现。BpBinder覆写了remoteBinder方法,使其可以返回远程代理,调用BpBinder对象的localBinder方法将会返回null。

BpBinder中封装有从ServiceManager那里获取到的HandleBpBinder提供有私有的create方法,可以很方便的帮助我们用Handle创建一个BpBinder对象。

BpBinder同样有transact方法,该方法用于和binder驱动通信,利用handle调用服务提供的方法,而BBindertransact用于执行我们的远程调用。

有这样一种情况,我们在使用远程代理进行RPC调用,但是这时候service挂了,如果我们不及时处理程序就很容易出错了。为了解决这个问题,BpBinder提供了一个linkToDeath方法,当远程服务死亡时可以通知到使用者。这个不是我们的重点,所以这里只要会用就行。

virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0);

4 IInterface

IInterface声明于IInterface.h,实现于IInterface.cpp。

我们定义的binder服务接口需要继承自IInterfaceIInterface可以理解是服务本体远程代理的一层封装,封装的是IBinder对象,提供更高层的接口,方便我们使用。

IInterface为我们提供了asBinder方法,这个方法的实现需要依赖子类对onAsBinder的实现,从名字上可以猜到它用来获取IInterface中封装的IBinder对象。

我们以 IMediaPlayerService为例看看binder服务接口要如何声明。IMediaPlayerService继承自IInterface,除了声明虚函数接口外,还调用了一个宏 DECLARE_META_INTERFACE,这个宏为我们提供了多个方法和类成员。

class IMediaPlayerService: public IInterface
{
public:
	 DECLARE_META_INTERFACE(MediaPlayerService);
}

DECLARE_META_INTERFACE 定义在 IInterface.h,将宏参数做替换后的代码如下:

public:                                                                                          
    static const ::android::String16 descriptor;                                                 
    static ::android::sp<IMediaPlayerService> asInterface(const ::android::sp<::android::IBinder>& obj); 
    virtual const ::android::String16& getInterfaceDescriptor() const; 
    IMediaPlayerService();                                                                               
    virtual ~IMediaPlayerService();                                                                      
    static bool setDefaultImpl(::android::sp<IMediaPlayerService> impl); 
    static const ::android::sp<IMediaPlayerService>& getDefaultImpl(); 
private:                                                                                          
    static ::android::sp<IMediaPlayerService> default_impl;    

实现同样也在 IInterface.h,这里我们不做展开,后面用到了我们再看。


5 BnInterface

BnInterface声明于IInterface.h,实现于IInterface.cpp。

BnInterface服务本体IInterface接口的实现:

template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
        const String16& _descriptor)
{
    if (_descriptor == INTERFACE::descriptor) return sp<IInterface>::fromExisting(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;
}

覆写了IBinder接口queryLocalInterface用于返回服务本体(BnInterface)
覆写了IInterface接口onAsBinder,用于返回服务本体(IBinder)

我们在这里看下上面的宏定义实现展开:

const ::android::String16& IMediaPlayerService::getInterfaceDescriptor() const { return IMediaPlayerService::descriptor;} 

::android::sp<IMediaPlayerService> IMediaPlayerService::asInterface(const ::android::sp<::android::IBinder>& obj) {        
    ::android::sp<IMediaPlayerService> intr;                                                                 
    if (obj != nullptr) {
    	// 尝试将IBinder对象转换为BnMediaPlayerService对象                                                                
        intr = ::android::sp<IMediaPlayerService>::cast(obj->queryLocalInterface(IMediaPlayerService::descriptor));        
        if (intr == nullptr) { 
        	// 如果为null,则将IBinder对象转换为BpMediaPlayerService对象                                                                
            intr = ::android::sp<BpMediaPlayerService>::make(obj);                                           
        }                                                                                      
    }                                                                                          
    return intr;                                                                               
}  

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

我们从ServiceManager获取到的服务其实是一个IBinder对象,有了它我们还不能执行RPC,需要将它转换为BpInterface对象或者是说代理实现,该对象内完成了参数的封装以及对Handle的调用。那我们应该如何转换呢?用这里的两个方法asInterfaceinterface_cast 就可以了。


6 BpInterface

BpInterface声明于IInterface.h,实现于IInterface.cpp。

BpInterface指的是远程代理,除了实现了IInterface接口外,还继承了BpRefBase

BpRefBase声明于Binder.h,实现于Binder.cpp。BpRefBase用于管理远程代理的生命周期,用handle创建的BpBinder对象就存储于BpRefBaseBpRefBase的remote方法返回的就是BpBinder

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

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

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

说到生命周期,BpRefBase 的用法我没太看懂什么意思。

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(nullptr), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}

不过我猜是将BpRefBaseIBinder 的生命周期绑定,因为BpRefBaseIBinder需要相互依赖,IBinder释放了BpRefBase也就无法工作了,BpRefBase释放了IBinder同样也没有意义了。


7 Parcel

RPC调用时少不了要传输数据,server端如何才能够识别client端写过去的数据呢?这就需要他们做一个约定,按照既定的数据格式传输数据。

Parcel就是用于帮我们做数据格式化的工作的,包括输入数据的封装与输出数据的解压。我们按什么顺序写入数据,就要按照什么顺序读取数据。

Parcel声明于Parcel.h,实现于Parcel.cpp。

现在我们可以使用aidl生成binder接口,但是aidl文件中我们只能使用Parcel中已经定义的基础数据类型,而不能使用任意类型,这是因为Parcel并不知道要按照什么规则写入我们想要使用的数据。


8 IPCThreadState / ProcessState

我们的老朋友了,ProcessState用于打开关闭binder驱动程序,IPCThreadState用于与操作binder驱动,与之沟通。


写在最后:这一篇笔记记录了一些零零碎碎的内容,主要了解了一些类的接口含义与使用。写到这我有点凌乱了,因为这篇仅仅是流水账式的记录,并没有什么章法可言,我应该也没有理解为什么binder框架这么设计。

现在回过头又想了一些,不知是对是错,就先记录在这里:

  1. binder驱动中传输的对象之所以要继承自IBinder,是因为传输的对象有可能是代理,也有可能是服务实体,我们得区分他们,IBinder为我们提供了区分他们的方法;
  2. 远端代理 和 本地服务 实际的执行者不同,所以又区分了BBinderBpBinderBBinder中是一个实例化的提供服务的对象,而BpBinder存储的是服务的引用handle;
  3. 为了保证远端代理 和 本地服务的接口保持一致,所以他们都继承了IInterface
  4. 远端的接口和本地的服务接口实际完成的工作不一样,所以区分出了BnInterfaceBpInterfaceBpInterface需要组织数据并且向handle发送数据,BnInterface需要根据发来的数据做真正的函数调用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【致敬未来的攻城狮计划】打卡3:点亮LED

点亮LED 本文主要参考文章&#xff1a;【致敬未来的攻城狮计划】— 连续打卡第十一天&#xff1a;FSP固件库开发点亮第一个灯。_嵌入式up的博客-CSDN博客 在32阶段我们已经接触过类似做法了。初始化引脚模式&#xff08;可以手动库函数&#xff0c;或者在工具包图形化界面里配…

实训四:索引与视图 - MySQL开发技巧 - 视图

MySQL开发技巧 - 视图 任务描述相关知识视图的定义创建视图操作视图删除视图 编程要求测试说明参考代码 任务描述 本关任务&#xff1a;通过学习视图&#xff0c;创建一个单表视图和一个多表视图。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 视图的定义…

工地扬尘智能监测系统 yolov7

工地扬尘智能监测系统通过yolov7网络算法模型技术&#xff0c;实时监测工地施工中的扬尘情况。工地扬尘智能监测系统利用AI视频智能分析技术&#xff0c;并将数据传输到数据中心进行分析。YOLOv7 的发展方向与当前主流的实时目标检测器不同&#xff0c;研究团队希望它能够同时支…

数据库管理-第八十四期 X10M来了(20230624)

数据库管理 2023-06-24 第八十四期 X10M来了1 Intel -> AMD2 PMEM -> XRMEM3 DDR4 -> DDR54 Flash cards总结 第八十四期 X10M来了 在第四十三期的时候&#xff0c;我曾经憧憬过Exadata X10M的到来&#xff0c;Oracle于6月22日正式公布Exadata X10M系列。其实5月已经…

chatgpt赋能python:Python在电气行业中的应用——从数据分析到自动化控制

Python在电气行业中的应用——从数据分析到自动化控制 介绍 Python语言作为一种高级编程语言&#xff0c;越来越受到电气行业的关注。随着互联网、物联网以及大数据时代的到来&#xff0c;电气行业需要将传统的工业控制与现代化的数据分析、智能决策等技术相结合&#xff0c;…

Java——《面试题——Dobbo篇》

前文 java——《面试题——基础篇》 Java——《面试题——JVM篇》 Java——《面试题——多线程&并发篇》 Java——《面试题——Spring篇》 Java——《面试题——SpringBoot篇》 Java——《面试题——MySQL篇》​​​​​​ Java——《面试题——SpringCloud》 目录…

springboot+mybatis笔记学习

1.环境搭建 1.引入pom依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version> </dependency> <dependency><groupId>org…

人工智能(2):机器学习算法分类

根据数据集组成不同&#xff0c;可以把机器学习算法分为&#xff1a; 监督学习无监督学习半监督学习强化学习 1 监督学习 定义&#xff1a; 输入数据是由输入特征值和目标值所组成。 函数的输出可以是一个连续的值(称为回归&#xff09;&#xff0c;或是输出是有限个离散值&…

07- c语言字符串 (C语言)

一 字符串的定义及基本使用 1、什么是字符串 被双引号引用的字符集合&#xff01;例如&#xff1a;”hello” 、”world”&#xff0c;或者是以 \0 结尾的字符数组&#xff01;&#xff01;&#xff01; 比如&#xff1a;char ch[] {h, e, \0} 注意&#xff1a;”hello” 中…

Win10同时安装MYSQL5.7和MYSQL8.0版本

一、准备好两个MySQL版本的压缩包 官网下载网址&#xff1a;https://dev.mysql.com/downloads/ 二、安装 MYSQL5.7 2.1、解压文件夹&#xff0c;然后新建一个 my.ini文件 my.ini文件内容: [mysql] # 设置mysql客户端默认字符集 default-character-setutf8 port 3305 [mysq…

leetcode1.两数之和

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【LeetCode】 &#x1f353;希望我们一起努力、成长&#xff0c;共同进步。 题目链接 给定一个整数数组 nums 和一个整数目标值 target&am…

FPGA-DFPGL22学习1-上手开发板

文章目录 前言一、FPGA是什么&#xff1f;二、FPGA内部结构1) 可编程输入/输出单元2) 基本可编程逻辑单元3) 嵌入式块 RAM4) 丰富的布线资源5) 底层嵌入功能单元 Logos 系列芯片 前言 和原子哥一起学习FPGA 开发环境&#xff1a;正点原子 ATK-DFPGL22G 开发板 参考书籍&…

mysql没有data和my.ini文件怎么办?

目录 一、前言 二、其他知识 一、前言 data是存储mysql数据的地方&#xff0c;ini是mysql配置文件的地方&#xff0c;要配置文件就可以在ini里面配置就好了。在mysql的安装位置没有发现这两个文件&#xff0c;不是没有&#xff0c;而是在其他地方。&#x1f447; 其实这两个…

【CSS】`top: 50%;` 和 `transform: translateY(-50%);`的区别和联系

top: 50%; 和 transform: translateY(-50%);的区别 在某些情况下&#xff0c;top: 50%; 和 transform: translateY(-50%); 可以达到类似的效果&#xff0c;但它们实际上具有不同的工作原理和应用场景。 top: 50%;&#xff1a;这是一个相对定位属性&#xff0c;用于设置元素相对…

P6739 [BalticOI 2014 Day1] Three Friends

[BalticOI 2014 Day1] Three Friends 题目描述 有一个字符串 S S S&#xff0c;对他进行操作&#xff1a; 将 S S S 复制为两份&#xff0c;存在字符串 T T T 中在 T T T 的某一位置上插入一个字符&#xff0c;得到字符串 U U U 现在给定 U U U&#xff0c;求 S S S…

【吴恩达老师《机器学习》】课后习题4之【神经网络反向传播】(代码注释详细)

前情回顾 上一周是已经给定了神经网络的最优权重参数&#xff0c;接着直接代到前向传播里面去&#xff0c;算得最终的预测值就可以了。 这周呢&#xff0c;需要搭建整个完整的神经网络&#xff0c;并且需要自己去进行训练&#xff0c;找到最终的这个优化的权重参数。 可能需要…

WVP PRO配置实战

WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网络视频平台&#xff0c;负责实现核心信令与设备管理后台部分&#xff0c;支持NAT穿透&#xff0c;支持海康、大华、宇视等品牌的IPC、NVR接入。支持国标级联&#xff0c;支持将不带国标功能的摄像机/直播流/直播…

FPGA-DFPGL22学习2-开发平台学习

文章目录 前言一、Pango Design Suite软件的使用流程二、使用步骤1.新建一个工程2.设计输入3.配置工程4.分析与综合&#xff08;编译检查&#xff09;5.约束输入6.编译工程7.下载程序 总结 前言 和原子哥一起学习FPGA 开发环境&#xff1a;正点原子 ATK-DFPGL22G 开发板 参考…

5.2.2如何改变文件属性与权限

常用于群组、拥有者、各种身份的权限之修改的指令&#xff0c;如下所示&#xff1a; 改变一个文件的群组很简单&#xff0c;直接chgrp来改变&#xff0c;指令就是change group。要被改变的群组名称必须要在/etc/group文件内存在才行&#xff0c;否则就会显示错误。 假设你已经…

构造中序线索二叉树和先序线索二叉树,中序线索二叉树找寻前驱结点和后继结点,包含完整代码

一.线索二叉树的结点结构&#xff1a; lchildltagdatartagrchild ltag 0, lchild域指示结点的左孩子 ltag 1, lchild域指示结点的前驱 rtag 0, rchild域指示结点的右孩子 rtag 1, rchild域指示结点的后继 这里用char型作为树的数据域类型 //定义线索二叉树的结…