idl-guidelines.md 19.3 KB
Newer Older
Y
yuyaozhi 已提交
1 2
# OpenHarmony IDL工具规格及使用说明书

W
wusongqing 已提交
3
## IDL接口描述语言简介
Y
yuyaozhi 已提交
4 5
在OpenHarmony中,当客户端和服务器进行IPC通信时,需要定义双方都认可的接口,以保障双方可以成功通信,OpenHarmony IDL(OpenHarmony Interface Definition Language)则是一种定义此类接口的工具。OpenHarmony IDL先把需要传递的对象分解成操作系统能够理解的基本类型,并根据开发者的需要封装跨边界的对象。

Y
yuyaozhi 已提交
6 7
  **图1** IDL接口描述

Y
yuyaozhi 已提交
8 9
![IDL-interface-description](./figures/IDL-interface-description.png)

10
 **OpenHarmony IDL接口描述语言主要用于:** 
Y
yuyaozhi 已提交
11 12 13 14 15

- 声明系统服务对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。

- 声明Ability对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。

Y
yuyaozhi 已提交
16
**图2** IPC/RPC通信模型
Y
yuyaozhi 已提交
17 18 19

![IPC-RPC-communication-model](./figures/IPC-RPC-communication-model.png)

20
 **使用OpenHarmony IDL接口描述语言声明接口具有以下优点:** 
Y
yuyaozhi 已提交
21 22 23 24 25

- OpenHarmony IDL中是以接口的形式定义服务,可以专注于定义而隐藏实现细节。

- OpenHarmony IDL中定义的接口可以支持跨进程调用或跨设备调用。根据OpenHarmony IDL中的定义生成的信息或代码可以简化跨进程或跨设备调用接口的实现。

W
wusongqing 已提交
26
## IDL接口描述语言构成
Y
yuyaozhi 已提交
27

W
wusongqing 已提交
28
### 数据类型
Y
yuyaozhi 已提交
29

W
wusongqing 已提交
30
#### 基础数据类型
Y
yuyaozhi 已提交
31
| IDL基本数据类型 | C++基本数据类型 | TS基本数据类型 |
32 33 34 35 36 37 38 39 40 41
|   --------    |  --------     | --------     |
|void           | void          | void         |
|boolean        | bool          | boolean      |
|byte           | int8_t        | number       |
|short          | int16_t       | number       |
|int            | int32_t       | number       |
|long           | int64_t       | number       |
|float          | float         | number       |
|double         | double        | number       |
|String         | std::string   | string       |
Y
yuyaozhi 已提交
42

Y
yuyaozhi 已提交
43
IDL支持的基本数据类型及其映射到C++、TS上的数据类型的对应关系如上表所示。
Y
yuyaozhi 已提交
44

W
wusongqing 已提交
45
#### sequenceable数据类型
Y
yuyaozhi 已提交
46 47 48 49
sequenceable数据类型是指使用“sequenceable”关键字声明的数据,表面该数据类型可以被序列化进行跨进程或跨设备传递。sequenceable在C++与TS中声明方式存在一定差异。

在C++中sequenceable数据类型的声明放在文件的头部,以“sequenceable includedir..namespace.typename”的形式声明。具体而言。声明可以有如下三个形式:

50
```cpp
Y
yuyaozhi 已提交
51 52 53 54
sequenceable includedir..namespace.typename
sequenceable includedir...typename
sequenceable namespace.typename
```
55

Y
yuyaozhi 已提交
56
其中,includedir表示该数据类型头文件所在目录,includedir中以“.”作为分隔符。namespace表示该数据类型所在命名空间,namespace中同样以“.”作为分隔符。typename表示数据类型,数据类型中不能包含非英文字符类型的其他符号。includedir与namespace之间通过“..”分割,如果类型声明的表达式中不包含“..”,除去最后一个typename之外的字符都会被解析为命名空间。例如:
57 58

```cpp
Y
yuyaozhi 已提交
59 60
sequenceable a.b..C.D
```
61

62
 上述声明在生成的的C++头文件中将被解析为如下代码:
63 64

```cpp
Y
yuyaozhi 已提交
65 66 67
#include  “a/b/d.h”
using C::D;
```
68

Y
yuyaozhi 已提交
69 70
TS声明放在文件的头部,以 “sequenceable namespace.typename;”的形式声明。具体而言,声明可以有如下形式:

71
```ts
Y
yuyaozhi 已提交
72 73 74
sequenceable idl.MySequenceable
```

Y
yuyaozhi 已提交
75
其中,namespace是该类型所属的命名空间,typename是类型名。MySequenceable类型表示可以通过Parcel进行跨进程传递。sequenceable数据类型并不在OpenHarmony IDL文件中定义,而是定义在.ts文件中。因此,OpenHarmony IDL工具将根据声明在生成的.ts代码文件中加入如下语句:
Y
yuyaozhi 已提交
76

77
```ts
Y
yuyaozhi 已提交
78
import MySequenceable from "./my_sequenceable"
Y
yuyaozhi 已提交
79 80 81 82
```

需要注意的是,IDL并不负责该类型的代码实现,仅仅按照指定的形式引入该头文件或import指定模块,并使用该类型,因此开发者需要自行保证引入目录、命名空间及类型的正确性。

W
wusongqing 已提交
83
#### 接口类型
84
 接口类型是指OpenHarmony IDL文件中定义的接口。对于当前IDL文件中定义的接口,可以直接使用它作为方法参数类型或返回值类型。而在其它OpenHarmony IDL文件中定义的接口,则需要在文件的头部进行前置声明。 
Y
yuyaozhi 已提交
85

86
 C++中声明的形式与sequenceable类型相似,具体而言可以有如下形式: 
Y
yuyaozhi 已提交
87

88
```cpp
Y
yuyaozhi 已提交
89 90 91
interface includedir..namespace.typename
```

92
 TS中声明的形式,具体而言可以有如下形式: 
Y
yuyaozhi 已提交
93

94
```ts
Y
yuyaozhi 已提交
95 96 97 98 99
interface namespace.interfacename
```

其中,namespace是该接口所属的命名空间,interfacename是接口名。例如:“interface OHOS.IIdlTestObserver;”声明了在其他OpenHarmony IDL文件定义的IIdlTestObserver接口,该接口可以作为当前定义中方法的参数类型或返回值类型使用。OpenHarmony IDL工具将根据该声明在生成的TS代码文件中加入如下语句:

100
```ts
Y
yuyaozhi 已提交
101 102 103
import IIdlTestObserver from "./i_idl_test_observer"
```

W
wusongqing 已提交
104
#### 数组类型
105
数组类型使用“T[]”表示,其中T可以是基本数据类型、sequenceable数据类型、interface类型和数组类型。该类型在C++生成代码中将被生成为std::vector<T>类型。
Y
yuyaozhi 已提交
106 107
OpenHarmony IDL数组数据类型与TS数据类型、C++数据类型的对应关系如下表所示:

108 109 110
|OpenHarmony IDL数据类型  | C++数据类型           | TS数据类型     |
|   -------              |  --------            |  --------    |
|T[]                     | std::vector<T> | T[]          |
Y
yuyaozhi 已提交
111

W
wusongqing 已提交
112
#### 容器类型
Y
yuyaozhi 已提交
113 114 115 116 117 118 119 120 121
IDL支持两种容器类型,即List和Map。其中List类型容器的用法为List&lt;T&gt;;Map容器的用法为Map<KT,VT>,其中T、KT、VT为基本数据类型、sequenceable类型、interface类型、数组类型或容器类型。

List类型在C++代码中被映射为std::list,Map容器被映射为std::map。

List类型在TS代码中不支持,Map容器被映射为Map。

OpenHarmony IDL容器数据类型与Ts数据类型、C++数据类型的对应关系如下表所示:

|OpenHarmony IDL数据类型  | C++数据类型       | TS数据类型     |
122 123 124
|   --------             |  --------        |  -------     |
|List&lt;T&gt;           | std::list        | 不支持        |
|Map<KT,VT>              | std::map         | Map          |
Y
yuyaozhi 已提交
125 126


W
wusongqing 已提交
127
### IDL文件编写规范
Y
yuyaozhi 已提交
128
一个idl文件只能定义一个interface类型,且该interface名称必须和文件名相同。idl文件的接口定义使用BNF范式描述,其基本定义的形式如下:
129

Y
yuyaozhi 已提交
130 131 132
```
[<*interface_attr_declaration*>]interface<*interface_name_with_namespace*>{<*method_declaration*>}
```
133

Y
yuyaozhi 已提交
134
其中,<*interface_attr_declaration*>表示接口属性声明。当前仅支持“oneway”属性,表示该接口中的接口都是单向方法,即调用方法后不用等待该方法执行即可返回。这个属性为可选项,如果未声明该属性,则默认为同步调用方法。接口名需要包含完整的接口头文件目录及命名空间,且必须包含方法声明,不允许出现空接口。
Y
yuyaozhi 已提交
135
接口内的方法声明形式为:
136

Y
yuyaozhi 已提交
137
```
Y
yuyaozhi 已提交
138
[<*method_attr_declaration*>]<*result_type*><*method_declaration*>
Y
yuyaozhi 已提交
139
```
140

Y
yuyaozhi 已提交
141
其中,<*method_attr_declaration*>表示接口属性说明。当前仅支持“oneway”属性,表示该方法为单向方法,即调用方法后不用等待该方法执行即可返回。这个属性为可选项,如果未声明该属性,则默认为同步调用方法。<*result_type*>为返回值类型,<*method_declaration*>是方法名和各个参数声明。
Y
yuyaozhi 已提交
142
参数声明的形式为:
143

Y
yuyaozhi 已提交
144
```
Y
yuyaozhi 已提交
145
[<*formal_param_attr*>]<*type*><*identifier*>
Y
yuyaozhi 已提交
146
```
147

Y
yuyaozhi 已提交
148 149
其中<*formal_param_attr*>的值为“in”,“out”,“inout”,分别表示该参数是输入参数,输出参数或输入输出参数。需要注意的是,如果一个方法被声明为oneway,则该方法不允许有输出类型的参数(及输入输出类型)和返回值。

W
wusongqing 已提交
150
## 开发步骤
Y
yuyaozhi 已提交
151

C
chenyuyan 已提交
152
### IDL工具的获取
C
chenyuyan 已提交
153
首先,打开DevEco Studio—>Tools—>SDK Manager,查看OpenHarmony SDK的本地安装路径,此处以DevEco Studio 3.0.0.993版本为例,查看方式如下图所示。
C
chenyuyan 已提交
154 155 156
![SDKpath](./figures/SDKpath.png)
![SDKpath](./figures/SDKpath2.png)

C
chenyuyan 已提交
157
进入对应路径后,查看toolchains->3.x.x.x(对应版本号命名文件夹)下是否存在idl工具的可执行文件。
Y
yuyaozhi 已提交
158

C
chenyuyan 已提交
159
> **注意**:请保证使用最新版的SDK,版本老旧可能导致部分语句报错。
Y
yuyaozhi 已提交
160

161
若不存在,可对应版本前往[docs仓版本目录](../../release-notes)下载SDK包,以[3.2Beta3版本](../../release-notes/OpenHarmony-v3.2-beta3.md)为例,可通过镜像站点获取。
C
chenyuyan 已提交
162

163
关于如何替换DevEco Studio的SDK包具体操作,参考[full-SDK替换指南](../quick-start/full-sdk-compile-guide.md)中的替换方法。
C
chenyuyan 已提交
164 165 166

得到idl工具的可执行文件后,根据具体场景进行后续开发步骤。

C
chenyuyan 已提交
167
### TS开发步骤
Y
yuyaozhi 已提交
168

W
wusongqing 已提交
169
#### 创建.idl文件
Y
yuyaozhi 已提交
170

C
chenyuyan 已提交
171 172 173
 开发者可以使用TS编程语言构建.idl文件。

 例如,此处构建一个名为IIdlTestService.idl的文件,文件内具体内容如下:  
Y
yuyaozhi 已提交
174

175
```cpp
Y
yuyaozhi 已提交
176 177 178
  interface OHOS.IIdlTestService {
      int TestIntTransaction([in] int data);
      void TestStringTransaction([in] String data);
179 180
      void TestMapTransaction([in] Map<int, int> data);
      int TestArrayTransaction([in] String[] data);
Y
yuyaozhi 已提交
181 182 183
  }
```

C
chenyuyan 已提交
184
在idl的可执行文件所在文件夹下执行命令 `idl -gen-ts -d dir -c dir/IIdlTestService.idl`
Y
yuyaozhi 已提交
185

C
chenyuyan 已提交
186
-d后的dir为目标输出目录,以输出文件夹名为IIdlTestServiceTs为例,在idl可执行文件所在目录下执行`idl -gen-ts -d IIdlTestServiceTs -c IIdlTestServiceTs/IIdlTestService.idl`,将会在执行环境的dir目录(即IIdlTestServiceTs目录)中生成接口文件、Stub文件、Proxy文件。
Y
yuyaozhi 已提交
187

C
chenyuyan 已提交
188
> **注意**:生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。
Y
yuyaozhi 已提交
189

C
chenyuyan 已提交
190
以名为`IIdlTestService.idl`的.idl文件、目标输出文件夹为IIdlTestServiceTs为例,其目录结构应类似于:
Y
yuyaozhi 已提交
191 192

```
C
chenyuyan 已提交
193 194 195 196 197 198
├── IIdlTestServiceTs  # idl代码输出文件夹
│   ├── i_idl_test_service.ts  # 生成文件
│   ├── idl_test_service_proxy.ts  # 生成文件
│   ├── idl_test_service_stub.ts  # 生成文件
│   └── IIdlTestService.idl  # 构造的.idl文件
└── idl.exe  # idl的可执行文件
Y
yuyaozhi 已提交
199 200
```

W
wusongqing 已提交
201
#### 服务端公开接口
Y
yuyaozhi 已提交
202

203
OpenHarmony IDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法。 
Y
yuyaozhi 已提交
204

205
```ts
Y
yuyaozhi 已提交
206 207
import {testIntTransactionCallback} from "./i_idl_test_service";
import {testStringTransactionCallback} from "./i_idl_test_service";
208 209
import {testMapTransactionCallback} from "./i_idl_test_service";
import {testArrayTransactionCallback} from "./i_idl_test_service";
Y
yuyaozhi 已提交
210 211 212 213 214 215 216 217
import IIdlTestService from "./i_idl_test_service";
import rpc from "@ohos.rpc";

export default class IdlTestServiceStub extends rpc.RemoteObject implements IIdlTestService {
    constructor(des: string) {
        super(des);
    }
    
218 219
    async onRemoteMessageRequest(code: number, data, reply, option): Promise<boolean> {
        console.log("onRemoteMessageRequest called, code = " + code);
Y
yuyaozhi 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        switch(code) {
            case IdlTestServiceStub.COMMAND_TEST_INT_TRANSACTION: {
                let _data = data.readInt();
                this.testIntTransaction(_data, (errCode, returnValue) => {
                    reply.writeInt(errCode);
                    if (errCode == 0) {
                        reply.writeInt(returnValue);
                    }
                });
                return true;
            }
            case IdlTestServiceStub.COMMAND_TEST_STRING_TRANSACTION: {
                let _data = data.readString();
                this.testStringTransaction(_data, (errCode) => {
                    reply.writeInt(errCode);
                });
                return true;
            }
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
            case IdlTestServiceStub.COMMAND_TEST_MAP_TRANSACTION: {
                let _data = new Map();
                let _dataSize = data.readInt();
                for (let i = 0; i < _dataSize; ++i) {
                    let key = data.readInt();
                    let value = data.readInt();
                    _data.set(key, value);
                }
                this.testMapTransaction(_data, (errCode) => {
                    reply.writeInt(errCode);
                });
                return true;
            }
            case IdlTestServiceStub.COMMAND_TEST_ARRAY_TRANSACTION: {
                let _data = data.readStringArray();
                this.testArrayTransaction(_data, (errCode, returnValue) => {
                    reply.writeInt(errCode);
                    if (errCode == 0) {
                        reply.writeInt(returnValue);
                    }
                });
                return true;
            }
Y
yuyaozhi 已提交
261 262 263 264 265 266 267 268 269 270
            default: {
                console.log("invalid request code" + code);
                break;
            }
        }
        return false;
    }
    
    testIntTransaction(data: number, callback: testIntTransactionCallback): void{}
    testStringTransaction(data: string, callback: testStringTransactionCallback): void{}
271 272
    testMapTransaction(data: Map<number, number>, callback: testMapTransactionCallback): void{}
    testArrayTransaction(data: string[], callback: testArrayTransactionCallback): void{}
Y
yuyaozhi 已提交
273 274 275

    static readonly COMMAND_TEST_INT_TRANSACTION = 1;
    static readonly COMMAND_TEST_STRING_TRANSACTION = 2;
276 277
    static readonly COMMAND_TEST_MAP_TRANSACTION = 3;
    static readonly COMMAND_TEST_ARRAY_TRANSACTION = 4;
Y
yuyaozhi 已提交
278 279 280
}
```

281
开发者需要继承.idl文件中定义的接口类并实现其中的方法。在本示例中,我们继承了IdlTestServiceStub接口类并实现了其中的testIntTransaction、testStringTransaction、testMapTransaction和testArrayTransaction方法。具体的示例代码如下:
Y
yuyaozhi 已提交
282

283
```ts
Y
yuyaozhi 已提交
284 285
import {testIntTransactionCallback} from "./i_idl_test_service"
import {testStringTransactionCallback} from "./i_idl_test_service"
286 287
import {testMapTransactionCallback} from "./i_idl_test_service";
import {testArrayTransactionCallback} from "./i_idl_test_service";
Y
yuyaozhi 已提交
288 289 290 291 292 293 294 295 296 297 298 299 300
import IdlTestServiceStub from "./idl_test_service_stub"


class IdlTestImp extends IdlTestServiceStub {

    testIntTransaction(data: number, callback: testIntTransactionCallback): void
    {
        callback(0, data + 1);
    }
    testStringTransaction(data: string, callback: testStringTransactionCallback): void
    {
        callback(0);
    }
301 302 303 304 305 306 307 308
    testMapTransaction(data: Map<number, number>, callback: testMapTransactionCallback): void
    {
        callback(0);
    }
    testArrayTransaction(data: string[], callback: testArrayTransactionCallback): void
    {
        callback(0, 1);
    }
Y
yuyaozhi 已提交
309 310 311 312 313
}
```

在服务实现接口后,需要向客户端公开该接口,以便客户端进程绑定。如果开发者的服务要公开该接口,请扩展Ability并实现onConnect()从而返回IRemoteObject,以便客户端能与服务进程交互。服务端向客户端公开IRemoteAbility接口的代码示例如下:

314
```ts
Y
yuyaozhi 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
export default {
    onStart() {
        console.info('ServiceAbility onStart');
    },
    onStop() {
        console.info('ServiceAbility onStop');
    },
    onCommand(want, startId) {
        console.info('ServiceAbility onCommand');
    },
    onConnect(want) {
        console.info('ServiceAbility onConnect');
        try {
            console.log('ServiceAbility want:' + typeof(want));
            console.log('ServiceAbility want:' + JSON.stringify(want));
            console.log('ServiceAbility want name:' + want.bundleName)
        } catch(err) {
F
fangJinliang1 已提交
332
            console.log('ServiceAbility error:' + err)
Y
yuyaozhi 已提交
333 334 335 336 337 338 339 340 341 342 343
        }
        console.info('ServiceAbility onConnect end');
        return new IdlTestImp('connect');
    },
    onDisconnect(want) {
        console.info('ServiceAbility onDisconnect');
        console.info('ServiceAbility want:' + JSON.stringify(want));
    }
};
```

W
wusongqing 已提交
344
#### 客户端调用IPC方法
Y
yuyaozhi 已提交
345

Y
yuyaozhi 已提交
346
客户端调用connectAbility()以连接服务时,客户端的onAbilityConnectDone中的onConnect回调会接收服务的onConnect()方法返回的IRemoteObject实例。由于客户端和服务在不同应用内,所以客户端应用的目录内必须包含.idl文件(SDK工具会自动生成Proxy代理类)的副本。客户端的onAbilityConnectDone中的onConnect回调会接收服务的onConnect()方法返回的IRemoteObject实例,使用IRemoteObject创建IdlTestServiceProxy类的实例对象testProxy,然后调用相关IPC方法。示例代码如下:
Y
yuyaozhi 已提交
347

348
```ts
Y
yuyaozhi 已提交
349 350 351 352 353
import IdlTestServiceProxy from './idl_test_service_proxy'
import featureAbility from '@ohos.ability.featureAbility';

function callbackTestIntTransaction(result: number, ret: number): void {
  if (result == 0 && ret == 124) {
F
fangJinliang1 已提交
354
    console.log('case 1 success');
Y
yuyaozhi 已提交
355 356 357 358 359
  }
}

function callbackTestStringTransaction(result: number): void {
  if (result == 0) {
F
fangJinliang1 已提交
360
    console.log('case 2 success');
Y
yuyaozhi 已提交
361 362 363
  }
}

364 365 366 367 368 369 370 371 372 373 374 375
function callbackTestMapTransaction(result: number): void {
  if (result == 0) {
    console.log('case 3 success');
  }
}

function callbackTestArrayTransaction(result: number, ret: number): void {
  if (result == 0 && ret == 124) {
    console.log('case 4 success');
  }
}

Y
yuyaozhi 已提交
376 377 378
var onAbilityConnectDone = {
  onConnect:function (elementName, proxy) {
    let testProxy = new IdlTestServiceProxy(proxy);
379 380 381
    let testMap = new Map();
    testMap.set(1, 1);
    testMap.set(1, 2);
Y
yuyaozhi 已提交
382 383
    testProxy.testIntTransaction(123, callbackTestIntTransaction);
    testProxy.testStringTransaction('hello', callbackTestStringTransaction);
384 385
    testProxy.testMapTransaction(testMap, callbackTestMapTransaction);
    testProxy.testArrayTransaction(['1','2'], callbackTestMapTransaction);
Y
yuyaozhi 已提交
386 387
  },
  onDisconnect:function (elementName) {
F
fangJinliang1 已提交
388
    console.log('onDisconnectService onDisconnect');
Y
yuyaozhi 已提交
389 390
  },
  onFailed:function (code) {
F
fangJinliang1 已提交
391
    console.log('onDisconnectService onFailed');
Y
yuyaozhi 已提交
392 393 394 395 396
  }
};

function connectAbility: void {
    let want = {
F
fangJinliang1 已提交
397 398
        bundleName: 'com.example.myapplicationidl',
        abilityName: 'com.example.myapplicationidl.ServiceAbility'
Y
yuyaozhi 已提交
399 400 401 402 403 404 405 406
    };
    let connectionId = -1;
    connectionId = featureAbility.connectAbility(want, onAbilityConnectDone);
}


```

W
wusongqing 已提交
407
#### IPC传递sequenceable对象
Y
yuyaozhi 已提交
408 409 410

开发者可以通过 IPC 接口,将某个类从一个进程发送至另一个进程。但是,必须确保 IPC 通道的另一端可使用该类的代码,并且该类必须支持marshalling和unmarshalling方法。OpenHarmony 需要通过该marshalling和unmarshalling方法将对象序列化和反序列化成各进程能识别的对象。

411
 **如需创建支持sequenceable 类型数据,开发者必须执行以下操作:** 
Y
yuyaozhi 已提交
412 413 414 415 416 417

1. 实现marshalling方法,它会获取对象的当前状态并将其序列化后写入Parcel。
2. 实现unmarshalling方法,它会从Parcel中反序列化出对象。

MySequenceable类的代码示例如下:

418
```ts
Y
yuyaozhi 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
import rpc from '@ohos.rpc';
export default class MySequenceable {
    constructor(num: number, str: string) {
        this.num = num;
        this.str = str;
    }
    getNum() : number {
        return this.num;
    }
    getString() : string {
        return this.str;
    }
    marshalling(messageParcel) {
        messageParcel.writeInt(this.num);
        messageParcel.writeString(this.str);
        return true;
    }
    unmarshalling(messageParcel) {
        this.num = messageParcel.readInt();
        this.str = messageParcel.readString();
        return true;
    }
    private num;
    private str;
}
```