1# 使用Parcel作为数据容器
2
3## 概述
4
5Parcel对象是一个数据容器,其提供一个内存空间以供数据写入。Parcel对象不仅支持诸如`int`,`float`,`double`等基本类型的写入,同时也支持扁平化地写入一个继承了`Parcelable`类的子类对象。可用于IPC中以实现数据通信功能。
6
7## 涉及功能
8
9### OHOS::Parcel
10数据/消息的容器类。
11
12#### 具体描述
13
14```cpp
15class OHOS::Parcel;
16```
17
18包含用于写入以及读出多种类型的数据,包括基本类型、Parcelable对象等。
19
20
21`#include <parcel.h>`
22
23#### Public Functions
24
25| 返回类型       | 名称           |
26| -------------- | -------------- |
27| | **Parcel**() |
28| | **Parcel**(Allocator* allocator)<br>构造Parcel对象,并指定内存分配器Allcator。  |
29| virtual | **~Parcel**() |
30| bool | **CheckOffsets**()<br>检查从当前光标读取对象的操作是否可行。  |
31| void | **FlushBuffer**()<br>释放parcel中的数据区域,并重置该parcel状态。  |
32| uintptr_t | **GetData**() const<br>获取指向当前parcel中数据起始位置的指针。  |
33| size_t | **GetDataCapacity**() const<br>获取当前parcel的总体容量(字节),即parcel中数据区域的当前总大小。  |
34| size_t | **GetDataSize**() const<br>获取当前parcel中已存在数据的总大小。  |
35| size_t | **GetMaxCapacity**() const |
36| binder_size_t | **GetObjectOffsets**() const<br>获取写入至当前parcel的每一个oject的具体位置。  |
37| size_t | **GetOffsetsSize**() const<br>获取当前存储的所有object的位置的总大小。  |
38| size_t | **GetReadableBytes**() const<br>获取剩余可从当前parcel读出的总字节数。  |
39| size_t | **GetReadPosition**()<br>获取当前读光标位置。  |
40| size_t | **GetWritableBytes**() const<br>获取剩余可向当前parcel写入的总字节数。  |
41| size_t | **GetWritePosition**()<br>获取当前写光标位置。  |
42| void | **InjectOffsets**(binder_size_t offsets, size_t offsetSize)<br>记录一个数组,该数组内包含多个对象的位置偏移量。  |
43| bool | **ParseFrom**(uintptr_t data, size_t size)<br>使用当前parcel读入输入数据。  |
44| bool | **ReadBool**() |
45| bool | **ReadBool**(bool& value) |
46| bool | **ReadBoolUnaligned**() |
47| bool | **ReadBoolVector**(std::vector< bool >* val) |
48| const uint8_t* | **ReadBuffer**(size_t length)<br>从当前parcel中读出一块数据(一块缓存区的数据)。  |
49| const char* | **ReadCString**()<br>从当前parcel中读出C-风格的字符串。  |
50| double | **ReadDouble**() |
51| bool | **ReadDouble**(double& value) |
52| bool | **ReadDoubleVector**(std::vector< double >* val) |
53| float | **ReadFloat**() |
54| bool | **ReadFloat**(float& value) |
55| bool | **ReadFloatVector**(std::vector< float >* val) |
56| int16_t | **ReadInt16**() |
57| bool | **ReadInt16**(int16_t& value) |
58| bool | **ReadInt16Unaligned**(int16_t& value) |
59| bool | **ReadInt16Vector**(std::vector< int16_t >* val) |
60| int32_t | **ReadInt32**() |
61| bool | **ReadInt32**(int32_t& value) |
62| bool | **ReadInt32Vector**(std::vector< int32_t >* val) |
63| int64_t | **ReadInt64**() |
64| bool | **ReadInt64**(int64_t& value) |
65| bool | **ReadInt64Vector**(std::vector< int64_t >* val) |
66| int8_t | **ReadInt8**() |
67| bool | **ReadInt8**(int8_t& value) |
68| bool | **ReadInt8Unaligned**(int8_t& value) |
69| bool | **ReadInt8Vector**(std::vector< int8_t >* val) |
70| template <typename T \> <br>sptr< T > | **ReadObject**()<br>从当前parcel读出某一具体对象。  |
71| template <typename T \> <br>T* | **ReadParcelable**()<br>从当前parcel读出一个Parcelable(及其子类)对象。  |
72| uintptr_t | **ReadPointer**() |
73| const std::string | **ReadString**()<br>从当前parcel中读出一个C++字符串(`std::string`)对象。  |
74| bool | **ReadString**(std::string& value)<br>从当前parcel读出C++`std::string`字符串对象,并存入输入对象中。  |
75| const std::u16string | **ReadString16**()<br>从当前parcel中读出一个UTF-16编码的C++字符串(`std::u16string`)对象。  |
76| bool | **ReadString16**(std::u16string& value)<br>从当前parcel读出一个UTF-16编码的C++`std::u16string`字符串对象,并存入输入对象中。  |
77| bool | **ReadString16Vector**(std::vector< std::u16string >* val) |
78| const std::u16string | **ReadString16WithLength**(int32_t& len)<br>从当前parcel中读出UTF-16编码的C++字符串(`std::u16string`)对象以及其对应长度。  |
79| const std::string | **ReadString8WithLength**(int32_t& len)<br>从当前parcel中读出C++字符串(`std::string`)对象以及其对应长度。  |
80| bool | **ReadStringVector**(std::vector< std::string >* val) |
81| template <typename T \> <br>sptr< T > | **ReadStrongParcelable**()<br>从当前parcel读出一个Parcelable对象,并使用智能指针管理该对象。  |
82| uint16_t | **ReadUint16**() |
83| bool | **ReadUint16**(uint16_t& value) |
84| bool | **ReadUint16Unaligned**(uint16_t& value) |
85| bool | **ReadUInt16Vector**(std::vector< uint16_t >* val) |
86| uint32_t | **ReadUint32**() |
87| bool | **ReadUint32**(uint32_t& value) |
88| bool | **ReadUInt32Vector**(std::vector< uint32_t >* val) |
89| uint64_t | **ReadUint64**() |
90| bool | **ReadUint64**(uint64_t& value) |
91| bool | **ReadUInt64Vector**(std::vector< uint64_t >* val) |
92| uint8_t | **ReadUint8**() |
93| bool | **ReadUint8**(uint8_t& value) |
94| bool | **ReadUint8Unaligned**(uint8_t& value) |
95| bool | **ReadUInt8Vector**(std::vector< uint8_t >* val) |
96| const uint8_t* | **ReadUnpadBuffer**(size_t length)<br>从当前parcel中读出一块数据(一块缓存区的数据)。  |
97| template <typename T \> <br>bool | **ReadVector**(std::vector< T >* val, bool(Parcel::*)(T&) Read)<br>从当前parcel读出一个`std::vector`对象。  |
98| bool | **RewindRead**(size_t newPosition)<br>将读光标置于指定位置。  |
99| bool | **RewindWrite**(size_t offsets)<br>将写光标置于指定位置。  |
100| bool | **SetAllocator**(Allocator* allocator)<br>设置当前parcel的内存分配器Allocator对象。  |
101| bool | **SetDataCapacity**(size_t newCapacity)<br>设置当前parcel的以字节数为单位的容量大小,即parcel内数据区域的大小。  |
102| bool | **SetDataSize**(size_t dataSize)<br>设置当前parcel的已存在数据大小(字节)。  |
103| bool | **SetMaxCapacity**(size_t maxCapacity)<br>设置当前parcel的以字节为单位的最大容量。  |
104| void | **SkipBytes**(size_t bytes)<br>在读操作中,跳过接下来由`bytes`指定的几个字节。  |
105| bool | **WriteBool**(bool value) |
106| bool | **WriteBoolUnaligned**(bool value) |
107| bool | **WriteBoolVector**(const std::vector< bool >& val) |
108| bool | **WriteBuffer**(const void* data, size_t size) |
109| bool | **WriteBufferAddTerminator**(const void* data, size_t size, size_t typeSize) |
110| bool | **WriteCString**(const char* value)<br>向当前parcel写入一个C风格的字符串。  |
111| bool | **WriteDouble**(double value) |
112| bool | **WriteDoubleVector**(const std::vector< double >& val) |
113| bool | **WriteFloat**(float value) |
114| bool | **WriteFloatVector**(const std::vector< float >& val) |
115| bool | **WriteInt16**(int16_t value) |
116| bool | **WriteInt16Unaligned**(int16_t value) |
117| bool | **WriteInt16Vector**(const std::vector< int16_t >& val) |
118| bool | **WriteInt32**(int32_t value) |
119| bool | **WriteInt32Vector**(const std::vector< int32_t >& val) |
120| bool | **WriteInt64**(int64_t value) |
121| bool | **WriteInt64Vector**(const std::vector< int64_t >& val) |
122| bool | **WriteInt8**(int8_t value) |
123| bool | **WriteInt8Unaligned**(int8_t value) |
124| bool | **WriteInt8Vector**(const std::vector< int8_t >& val) |
125| template <typename T \> <br>bool | **WriteObject**(const sptr< T >& object)<br>向当前parcel写入某一具体对象。  |
126| bool | **WriteParcelable**(const Parcelable* object)<br>向当前parcel写入Parcelable对象。  |
127| bool | **WritePointer**(uintptr_t value) |
128| bool | **WriteRemoteObject**(const Parcelable* object)<br>向当前parcel中写入remote对象。  |
129| bool | **WriteString**(const std::string& value)<br>向当前parcel写入一个C++的std::string字符串。  |
130| bool | **WriteString16**(const std::u16string& value)<br>向当前parcel写入一个C++的std::string字符串。  |
131| bool | **WriteString16Vector**(const std::vector< std::u16string >& val) |
132| bool | **WriteString16WithLength**(const char16_t* value, size_t len)<br>向当前parcel写入一个UTF-16编码的字符串。  |
133| bool | **WriteString8WithLength**(const char* value, size_t len)<br>向当前parcel写入一个UTF-8编码的字符串。  |
134| bool | **WriteStringVector**(const std::vector< std::string >& val) |
135| bool | **WriteStrongParcelable**(const sptr< Parcelable >& object)<br>将Parcelable对象的`HOLD_OBJECT`行为开启后写入当前parcel。  |
136| bool | **WriteUint16**(uint16_t value) |
137| bool | **WriteUint16Unaligned**(uint16_t value) |
138| bool | **WriteUInt16Vector**(const std::vector< uint16_t >& val) |
139| bool | **WriteUint32**(uint32_t value) |
140| bool | **WriteUInt32Vector**(const std::vector< uint32_t >& val) |
141| bool | **WriteUint64**(uint64_t value) |
142| bool | **WriteUInt64Vector**(const std::vector< uint64_t >& val) |
143| bool | **WriteUint8**(uint8_t value) |
144| bool | **WriteUint8Unaligned**(uint8_t value) |
145| bool | **WriteUInt8Vector**(const std::vector< uint8_t >& val) |
146| bool | **WriteUnpadBuffer**(const void* data, size_t size)<br>基于数据区指针及数据长度写入一段数据,功能与WriteBuffer完全相同,`注:`该接口内部会自动计算并写入对齐长度|
147| template <typename T1 ,typename T2 \> <br>bool | **WriteVector**(const std::vector< T1 >& val, bool(Parcel::*)(T2) Write)<br>向当前parcel写入一个`std::vector`对象。  |
148
149#### Protected Functions
150
151| 返回类型       | 名称           |
152| -------------- | -------------- |
153| bool | **EnsureObjectsCapacity**()<br>确保当前写入对象数量小于对象容量。  |
154| bool | **WriteObjectOffset**(binder_size_t offset)<br>记录待写入对象的具体位置,该位置表示为相对于数据区域起始处的偏移量。  |
155
156### OHOS::Parcelable
157
158定义了实例可被写入至某一Parcel的类接口。
159
160#### 具体描述
161
162```cpp
163class OHOS::Parcelable;
164```
165
166**提示**: 如果当前对象为remote,其地址将被用于在内核中进行数据传输。
167
168`#include <parcel.h>`
169
170继承自 OHOS::RefBase
171
172#### Public Types
173
174|                | 名称           |
175| -------------- | -------------- |
176| enum| **BehaviorFlag** { IPC = 0x01, RPC = 0x02, HOLD_OBJECT = 0x10}<br>用于描述Parcelable对象具体行为的枚举类。  |
177
178#### Public Functions
179
180| 返回类型       | 名称           |
181| -------------- | -------------- |
182| | **Parcelable**() |
183| | **Parcelable**(bool asRemote)<br>构造一个Parcelable对象。  |
184| virtual | **~Parcelable**() = default |
185| void | **ClearBehavior**(BehaviorFlag b) const<br>清除指定行为标志位。  |
186| virtual bool | **Marshalling**(Parcel& parcel) const =0<br>向指定Parcel对象中写入当前Parcelable对象。  |
187| void | **SetBehavior**(BehaviorFlag b) const<br>设置指定行为标志位。  |
188| bool | **TestBehavior**(BehaviorFlag b) const<br>检查指定行为是否已开启。  |
189
190#### Public Attributes
191
192|                | 名称           |
193| -------------- | -------------- |
194| bool | **asRemote_** <br>指明对象是否为remote的标志位。  |
195| uint8_t | **behavior_** <br>指定已开启行为的具体值。  |
196
197
198## 使用示例
199
2001. 使用方法(伪代码)
201
202```c++
203// 写入端以某种顺序写入数据
204struct TestData {
205    bool booltest;
206    int8_t int8test;
207    int16_t int16test;
208    int32_t int32test;
209    uint8_t uint8test;
210    uint16_t uint16test;
211    uint32_t uint32test;
212};
213
214...
215
216Parcel parcel(nullptr);
217struct TestData data = { true, -0x34, 0x5634, -0x12345678, 0x34, 0x5634, 0x12345678 };
218bool result = false;
219
220result = parcel.WriteBool(data.booltest);
221if (!result) {
222    // 写失败处理
223}
224
225result = parcel.WriteInt8(data.int8test);
226if (!result) {
227    // 写失败处理
228}
229
230result = parcel.WriteInt16(data.int16test);
231if (!result) {
232    // 写失败处理
233}
234
235result = parcel.WriteInt32(data.int32test);
236if (!result) {
237    // 写失败处理
238}
239
240result = parcel.WriteUint8(data.uint8test);
241if (!result) {
242    // 写失败处理
243}
244
245result = parcel.WriteUint16(data.uint16test);
246if (!result) {
247    // 写失败处理
248}
249
250result = parcel.WriteUint32(data.uint32test);
251if (!result) {
252    // 写失败处理
253}
254```
255
256```c++
257// 接收端根据写入端写入顺序读取数据
258bool readbool = parcel.ReadBool();
259
260int8_t readint8 = parcel.ReadInt8();
261
262int16_t readint16 = parcel.ReadInt16();
263
264int32_t readint32 = parcel.ReadInt32();
265
266uint8_t readuint8 = parcel.ReadUint8();
267
268uint16_t readuint16 = parcel.ReadUint16();
269
270uint32_t readuint32 = parcel.ReadUint32();
271```
272
2732. 常见接口限制及使用误区
274
275- ReadBuffer/ReadUnpadBuffer/WriteBuffer/WriteUnpadBuffer
276
277    不推荐ReadBuffer与WriteBuffer/WriteUnpadBuffer对应配合使用,可能因为对齐问题导致ReadBuffer后的Read操作从错误的偏移位置进行读取,进而导致读取异常;
278    ReadUnpadBuffer与WriteBuffer/WriteUnpadBuffer配合使用为正确的使用方式。
279
280```cpp
281// ReadBuffer: 读取buffer,且内部数据区按参数设置长度偏移,不考虑数据对齐
282// ReadUnpadBuffer: 读取buffer,内部数据区基于读取长度自动计算对齐并偏移,将数据对齐考虑在内
283// WriteBuffer: 写入数据,内部数据区会基于写入长度计算对齐长度并自动偏移
284// WriteUnpadBuffer: 与WriteBuffer完全相同
285
286struct Padded {
287    char title;
288    int32_t handle;
289    uint64_t cookie;
290};
291
292struct Unpadded {
293    char tip;
294};
295
296Parcel parcel(nullptr);
297const struct Padded pad = { 'p', 0x34567890, -0x2345678998765432 };
298const struct Unpadded unpad = { 'u' };
299// CASE 1:写入对齐数据
300// 后续代码为单case下不同情况的使用代码,并非真实连续调用
301parcel.WriteBuffer(static_cast<const void *>(&pad), sizeof(struct Padded));
302parcel.WriteInt32(1);
303
304// 错误使用但结果正常:
305parcel.ReadBuffer(sizeof(struct Padded)); // 可以正常读取buffer内容
306parcel.ReadInt32(); // 后续读取内容正常
307
308// 正确使用:
309parcel.ReadUnpadBuffer(sizeof(struct Padded)); // 可以正常读取buffer内容
310parcel.ReadInt32(); // 后续读取内容正常
311
312// CASE 2:写入非对齐数据
313// 后续代码为单case下不同情况的使用代码,并非真实连续调用
314parcel.WriteBuffer(static_cast<const void *>(&unpad), sizeof(struct Unpadded));
315parcel.WriteInt32(1);
316
317// 错误使用,结果异常:
318parcel.ReadBuffer(sizeof(struct Unpadded)); // 可以正常读取buffer内容
319parcel.ReadInt32(); // 后续读取内容异常
320
321// 正确使用:
322parcel.ReadUnpadBuffer(sizeof(struct Unpadded)); // 可以正常读取buffer内容
323parcel.ReadInt32(); // 后续读取内容正常
324```
325
326- 基础类型的Read接口,如ReadInt32,ReadFloat等读取失败
327
328    当前在基础Read接口内加入了安全校验机制,当发现基础类型的读操作在读取Object对象数据内容时,该行为会被拦截
329
330```cpp
331// 伪代码:
332
333Parcel parcel(nullptr);
334Parcelable object;
335parcel.WriteRemoteObject(object);
336parcel.ReadInt32(); // False
337
338```
339
340- 使用WriteBuffer写入字符串,忽略结束符导致读取字符串长度异常
341
342    WriteBuffer接口并非专门处理字符串写入的接口,因此错误传递写入长度,可能会导致字符串的结束符丢失
343
344```cpp
345// 伪代码:
346
347string str = "abcdefg";
348Parcel parcel(nullptr);
349char *strPtr = str.c_str();
350auto len = str.length();
351parcel.WriteBuffer(strPtr, len);
352
353parcel.ReadBuffer(len); // 读取字符串长度异常
354
355```
356
3573. 测试用例编译运行方法
358
359- 测试用例代码参见 base/test/unittest/common/utils_parcel_test.cpp
360
361- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C)
362
363- 使用以下具体命令以运行`parcel.h`对应测试用例
364
365```bash
366run -t UT -tp utils -ts UtilsParcelTest
367```