理解Binder中Parcel数据结构C++

116 阅读2分钟

​Parcel 是什么?​
你可以把 Parcel 想象成一个"快递包裹",它在 Android 的 Binder 通信机制中负责打包和运输数据。客户端把数据装进这个包裹,服务端收到后拆开包裹读取数据。

​Parcel 能装什么?​

  • 基本类型:数字、布尔值等
  • 字符串
  • 数组
  • 特殊对象:比如 Binder 代理对象、文件描述符
  • 自定义对象(需要实现 Parcelable 接口)

​Parcel 的工作原理(以寄快递为例):​

  1. ​打包数据(写操作)​

    • 比如要寄一个数字 123:

      • 先检查包裹剩余空间是否够用,不够就扩容(类似快递员换个更大的箱子)
      • 把数字按固定格式放进箱子的指定位置
      • 记录当前打包位置,方便后续继续装货
  2. ​运输数据​

    • 通过 Binder 驱动(类似物流系统)把包裹送到目的地
  3. ​拆包数据(读操作)​

    • 服务端按照同样的顺序和格式从包裹里取出数据
    • 每取一件货物,就更新当前位置标记

​关键技术细节:​

  1. ​内存管理​

    • 采用 1.5 倍扩容策略:每次空间不足时,新空间 = 原大小 * 1.5
    • 内存对齐:所有数据按 4 字节对齐存放(类似货架每格固定大小,方便快速存取)
  2. ​对象传输​

    • 传输 Binder 对象时:

      • 本地对象(如服务实体)会被标记为 BINDER_TYPE_BINDER
      • 远程对象(如服务代理)会被标记为 BINDER_TYPE_HANDLE
    • 驱动会自动转换本地/远程标识,实现跨进程对象引用

  3. ​特殊处理​

    • 字符串传输:先写长度再写内容,末尾自动补零对齐
    • 文件描述符传输:会特殊标记并处理跨进程传递

​为什么重要?​

  • 高效的内存管理:通过智能扩容和对齐策略,兼顾内存使用效率和访问速度
  • 安全的跨进程传输:自动处理复杂对象的序列化/反序列化,对开发者透明
  • 统一的接口设计:一套 API 支持各种数据类型,简化开发

​举个例子:​
想象你要通过快递寄送一个装有手机和说明书的包裹:

  1. 手机(对象)需要特殊包装,贴上"易碎品"标签(类似 Binder 对象标记)
  2. 说明书(字符串)要折成固定大小的纸张(内存对齐)
  3. 快递员(Binder 驱动)会检查包裹大小,换合适的箱子(内存扩容)
  4. 收件人必须按相同顺序拆包,才能正确拿到物品(数据读取顺序一致)

这就是 Parcel 在 Binder 通信中扮演的角色,它让复杂的跨进程数据传递变得简单可靠。