Binder学习笔记(五)—— Parcel是怎么打包数据的?
前文中曾经遇到过Parcel,从命名上知道他负责数据打包。在checkService的请求/响应体系中,Parcel只打包了基本数据类型,如Int32、String16……后面还要用于打包抽象数据类型flat_binder_object,这会稍微复杂一些,因此有必要拿出来单独研究。我们从Parcel::writeInterfaceToken(…)追起,它的层层调用关系如下,这些函数都在frameworks/native/libs/binder/Parcel.cpp文件中,行数和函数名为:
writeInterfaceToken(…)
Parcel::writeInt32(int32_t val)
Parcel::writeAligned(val)
所有的基本数据类型的打包最后都由writeAligned(…)实现的,其内部逻辑也非常简单,
frameworks/native/libs/binder/Parcel.cpp:1149
template<class T>
status_t Parcel::writeAligned(T val) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
*reinterpret_cast<T*>(mData+mDataPos) = val; // 将val追加到mData
return finishWrite(sizeof(val));
} status_t err = growData(sizeof(val)); // 如果mData空间不够,则先扩容
if (err == NO_ERROR) goto restart_write;
return err;
}
mData是一块内存栈,writeXXX则把数据写入栈,如果mData空间不够,先给mData扩容,并把原先的数据搬到新的空间,再把新数据写入栈。
Parcel::writeStrongBinder(…)的逻辑更复杂一些,它的调用关系如下:
frameworks/native/libs/binder/Parcel.cpp
Parcel::writeStrongBinder(const sp<IBinder>& val)
Parcel::flatten_binder(const sp<ProcessState>& /*proc*/, const sp<IBinder>& binder =val, Parcel* out=this)
来看flatten_binder(…),frameworks/native/libs/binder/Parcel.cpp:205
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) { // remote类型的binder封装逻辑
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : ;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = ; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = ;
} else { // local类型的binder封装逻辑
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = ;
obj.cookie = ;
} return finish_flatten_binder(binder, obj, out);
}
它根据传入binder的类型做不同的数据封装,在frameworks/native/include/binder/IBinder.h:139,可以看到IBinder声明了两个虚函数:
class IBinder : public virtual RefBase
{
public:
……
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
……
};
并在frameworks/native/libs/binder/Binder.cpp:47定义了默认实现:
BBinder* IBinder::localBinder()
{
return NULL;
} BpBinder* IBinder::remoteBinder()
{
return NULL;
}
flat_binder_object这个数据结构在《Binder学习笔记(四)—— ServiceManager如何响应checkService请求》研究ServiceManager如何组织reply数据时遇到过,它定义在external/kernel-headers/original/uapi/linux/binder.h:57。对于不同的binder封装成的数据示意图如下:

然后flatten_binder(…)调用finish_flatten_binder(…),frameworks/native/libs/binder/Parcel.cpp:199
inline static status_t finish_flatten_binder(
const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
return out->writeObject(flat, false);
}
继续调用writeObject(…),frameworks/native/libs/binder/Parcel.cpp:1035
status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
const bool enoughObjects = mObjectsSize < mObjectsCapacity;
if (enoughData && enoughObjects) {
restart_write:
// 如果空间足够,他把前面组装的flat_binder_object实体追加到mData里
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
……
if (nullMetaData || val.binder != ) {
// mObjects记录每次向mData追加的flat_binder_object的偏移位置
mObjects[mObjectsSize] = mDataPos;
acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
mObjectsSize++;
} return finishWrite(sizeof(flat_binder_object));
}
……
}
总结一下:Parcel的数据区域分两个部分:mData和mObjects,所有的数据不管是基础数据类型还是对象实体,全都追加到mData里,mObjects是一个偏移量数组,记录所有存放在mData中的flat_binder_object实体的偏移量。Parcel的数据模型如下:

Binder学习笔记(五)—— Parcel是怎么打包数据的?的更多相关文章
- Binder学习笔记(九)—— 服务端如何响应Test()请求 ?
从服务端代码出发,TestServer.cpp int main() { sp < ProcessState > proc(ProcessState::self()); sp < I ...
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- golang学习笔记8 beego参数配置 打包linux命令
golang学习笔记8 beego参数配置 打包linux命令 参数配置 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/mvc/contro ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
随机推荐
- mezzanine安装配置
ubuntu 14.04 cd /var/wwwmkdir testingcd testingvirtualenv venv --python=python3. venv/bin/activate p ...
- 容器中跨主机的网络方案-flannel
容器中的网络是建立docker集群的重要内容. 本文将介绍如何用flannel实现容器的多节点互通. 下图是flannel的实现原理,摘自: http://docker-k8s-lab.readthe ...
- Azure上通过haproxy实现APP Gateway或WAF的http跳转https
Azure上的APP Gateway是七层负载均衡服务,WAF是APP Gateway服务的扩展.在实现七层负载均衡的同时,增加了WAF的功能,可以对后台的HTTP服务进行保护. Azure WAF采 ...
- openTSDB+HBase+ZK遇到的坑汇总
1.zookeeper返回的hbase地址是hostname,外网如何访问? 如果需要直接访问zk获取hbase地址进而访问,目前需要本机配置host ip hostname 如果是要长期解决方法, ...
- 使用Spring Boot 和Spring Data JPA访问mysql数据库
在Spring中使用JdbcTemplate是一种基本的数据访问方式,但是仍然需要较多的代码,为了解决这些大量枯燥的数据操作语句,我们可以使用ORM框架,比如:Hibernate,通过整合Hibern ...
- SQL Server获取TEXT字段的内容长度
DATALENGTH 返回任何表达式所占用的字节数. 语法 DATALENGTH ( expression ) 参数 expression 任何类型的表达式. 返回类型 int 注释 DATALENG ...
- 机器学习:调整kNN的超参数
一.评测标准 模型的测评标准:分类的准确度(accuracy): 预测准确度 = 预测成功的样本个数/预测数据集样本总数: 二.超参数 超参数:运行机器学习算法前需要指定的参数: kNN算法中的超参数 ...
- Oracle 高可用作业测试
1.RAC 是一种: A 分布式数据库B 内存共享多节点数据库C 能够保护数据安全的架构 2.RAC 和CRS 的区别是: A 前者表示一种架构,后者是一套软件B 前者表示一套软件,后者是一种架构 C ...
- MySQL中varchar类型排序
-- +0后就转换INT类型排序 SELECT * FROM T_TEST ORDER BY (SORT + 0) DESC ;
- C++的继承与接口
1.继承方式 三种继承方式,public,private,protected.注意,继承方式是相对于某一层类的方法而言,并不是相对于子类的对象而言.对于外部世界()对象来说,protected和pri ...