mirror of
https://gitee.com/openharmony/napi_generator
synced 2024-11-23 08:20:01 +00:00
修改guide和usage
Signed-off-by: huruitao <huruitao@kaihong.com>
This commit is contained in:
parent
4dbdc0948d
commit
0c475a9149
@ -4,7 +4,7 @@
|
||||
|
||||
当开发人员为OpenHarmony系统框架开发某些功能时,有时需要将这个功能包装成一个独立的服务进程运行在系统中,为了其它应用进程能够调用此服务,开发人员需要基于系统IPC通信框架编写一套远程接口调用实现。 Service代码生成工具能够帮助用户生成框架代码,提升开发效率。用户只需提供一个定义远程方法的.h头文件,工具会自动生成整个Service框架的代码,包含Ability注册、proxy/stub类实现、MessageParcel数据包构造、Service子系统编译及开机自启动相关配置文件。用户可基于框架代码专注于业务功能的编写。
|
||||
|
||||
![image-20240723101920662](C:\Users\kaihong\AppData\Roaming\Typora\typora-user-images\image-20240723101920662.png)
|
||||
![image](./docs/figures/service_frame_structure.png)
|
||||
|
||||
---
|
||||
|
||||
@ -39,137 +39,7 @@ h2sa
|
||||
|
||||
运行逻辑
|
||||
|
||||
![image-20240723144207759](C:\Users\kaihong\AppData\Roaming\Typora\typora-user-images\image-20240723144207759.png)
|
||||
|
||||
js文件中的部分重要函数和参数:
|
||||
|
||||
~~~
|
||||
//main.js
|
||||
|
||||
let ops = stdio.getopt({
|
||||
//命令行参数
|
||||
'filename': { key: 'f', args: 1, description: '.h file', default: '' },
|
||||
'out': { key: 'o', args: 1, description: 'output directory', default: '.' },
|
||||
'loglevel': { key: 'l', args: 1, description: 'Log Level: 0~3', default: '1' },
|
||||
'serviceId': { key: 's', args: 1, description: 'service register id: 9000~16777214', default: '9000' },
|
||||
'versionTag': { key: 'v', args: 1, description: 'version tag: 4.1 / 3.2', default: '3.2' }
|
||||
});
|
||||
|
||||
function genServiceFile(fileName) {
|
||||
// 1. h文件解析保存为结构体
|
||||
let rootInfo = analyze.doAnalyze(fileName, ops);
|
||||
|
||||
// 2. 根据结构体生成代码
|
||||
let fileContent = gen.doGenerate(rootInfo);
|
||||
|
||||
// 3. 创建service工程目录
|
||||
let servicePath = re.pathJoin(ops.out, rootInfo.serviceName.toLowerCase() + 'service');
|
||||
let etcPath = re.pathJoin(servicePath, 'etc');
|
||||
let includePath = re.pathJoin(servicePath, 'include');
|
||||
let interfacePath = re.pathJoin(servicePath, 'interface');
|
||||
let profilePath = re.pathJoin(servicePath, 'sa_profile');
|
||||
let srcPath = re.pathJoin(servicePath, 'src');
|
||||
createFolder(servicePath);
|
||||
createFolder(etcPath);
|
||||
createFolder(includePath);
|
||||
createFolder(interfacePath);
|
||||
createFolder(profilePath);
|
||||
createFolder(srcPath);
|
||||
|
||||
// 4. 生成代码保存为文件
|
||||
wirte2Disk(fileContent.serviceCfgGnFile, etcPath);
|
||||
wirte2Disk(fileContent.proxyHFile, includePath);
|
||||
wirte2Disk(fileContent.stubHFile, includePath);
|
||||
...
|
||||
}
|
||||
|
||||
~~~
|
||||
|
||||
~~~
|
||||
// analyze.js
|
||||
|
||||
function doAnalyze(hFilePath, cmdParam) {
|
||||
let parseResult = parseFileAll(hFilePath);
|
||||
parseResult.isInclude = false;
|
||||
AllParseFileList.push(parseResult);
|
||||
let rootInfo = {
|
||||
'serviceName': '',
|
||||
'nameSpace': [],
|
||||
'class': [],
|
||||
'includes': [],
|
||||
'using': [],
|
||||
'serviceId': (cmdParam.serviceId === null || cmdParam.serviceId === undefined) ?
|
||||
'9002' : cmdParam.serviceId,
|
||||
'versionTag': (cmdParam.versionTag === null || cmdParam.versionTag === undefined) ?
|
||||
'3.2' : cmdParam.versionTag,
|
||||
'rawContent': parseResult.rawContent
|
||||
};
|
||||
|
||||
analyzeNameSpace(rootInfo, parseResult);
|
||||
analyzeClasses(rootInfo, parseResult.classes);
|
||||
rootInfo.includes = parseResult.includes;
|
||||
rootInfo.using = parseResult.using;
|
||||
return rootInfo; //经过解析后返回的结构体;作为参数,传值调用使用
|
||||
}
|
||||
|
||||
~~~
|
||||
|
||||
~~~
|
||||
//generate.js
|
||||
let fileContent = {
|
||||
'iServiceHFile': {},
|
||||
'proxyHFile': {},
|
||||
'stubHFile': {},
|
||||
'serviceHFile': {},
|
||||
'proxyCppFile': {},
|
||||
'stubCppFile': {},
|
||||
'serviceCppFile': {},
|
||||
'clientCppFile': {},
|
||||
'buildGnFile': {},
|
||||
'bundleJsonFile': {},
|
||||
'profileGnFile': {},
|
||||
'profileXmlFile': {},
|
||||
'profileJsonFile': {},
|
||||
'serviceCfgFile': {},
|
||||
'serviceCfgGnFile': {},
|
||||
'iServiceCppFile': {},
|
||||
};
|
||||
|
||||
function doGenerate(rootInfo) {
|
||||
rootHFileSrc = rootInfo.rawContent;
|
||||
let lowServiceName = rootInfo.serviceName.toLowerCase();
|
||||
let upperServiceName = rootInfo.serviceName.toUpperCase();
|
||||
|
||||
// 生成文件名
|
||||
genFileNames(lowServiceName, rootInfo);
|
||||
|
||||
// 按模板生成.h和.cpp文件内容框架
|
||||
let files = genFilesByTemplate(upperServiceName, lowServiceName, rootInfo);
|
||||
|
||||
// 替换文件includes
|
||||
replaceIncludes(files, rootInfo);
|
||||
...
|
||||
|
||||
// 替换namespace
|
||||
replaceServiceName(files, rootInfo);
|
||||
|
||||
// 替换类名
|
||||
let classInfo = rootInfo.class[0];
|
||||
replaceClassName(files, classInfo);
|
||||
...
|
||||
|
||||
// 文件内容汇总
|
||||
fileContent.iServiceHFile.content = files.iServiceH;
|
||||
fileContent.proxyHFile.content = files.proxyH;
|
||||
fileContent.stubHFile.content = files.stubH;
|
||||
fileContent.serviceHFile.content = files.serviceH;
|
||||
fileContent.proxyCppFile.content = files.proxyCpp;
|
||||
fileContent.stubCppFile.content = files.stubCpp;
|
||||
fileContent.serviceCppFile.content = files.serviceCpp;
|
||||
fileContent.clientCppFile.content = files.clientCpp;
|
||||
...
|
||||
return fileContent;
|
||||
}
|
||||
![image](./docs/figures/service_runLogic.png)
|
||||
|
||||
~~~
|
||||
|
||||
@ -228,6 +98,3 @@ function doGenerate(rootInfo) {
|
||||
├── test_service_proxy.cpp
|
||||
└── test_service_stub.cpp
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,18 @@
|
||||
### 工具使用方法说明
|
||||
### h2sa工具
|
||||
|
||||
## 简介
|
||||
|
||||
h2sa工具,即SERVICE框架生成工具,当开发者为OpenHarmony系统框架开发某些功能时,有时需要将这个功能包装成一个独立的服务进程运行在系统中,为了其它应用进程能够调用此服务,开发人员需要基于系统IPC通信框架编写一套远程接口调用实现。实现Service远程调用接口需要开发人员熟悉IPC通信框架,了解proxy/stub的继承与实现方式,掌握C++类型转为MessageParcel数据包的各种API方法,有一定的学习成本。而Service代码生成工具能够帮助使用者生成框架代码,提升开发效率。用户只需提供一个定义远程方法的.h头文件,工具会自动生成整个Service框架的代码,包含Ability注册、proxy/stub类实现、MessageParcel数据包构造、Service子系统编译及开机自启动相关配置文件。
|
||||
|
||||
## 约束
|
||||
|
||||
系统:建议Ubuntu 20.04或者Windows 10
|
||||
|
||||
依赖版本:VS Code 1.62.0
|
||||
|
||||
## 使用方法
|
||||
|
||||
#### 命令行
|
||||
|
||||
1. 安装python库 CppHeaderParser
|
||||
|
||||
@ -20,6 +34,35 @@
|
||||
|
||||
4. 将待转换的文件test.h文件拷贝到napi_generator/src/cli/h2sa/src/src/gen目录下
|
||||
|
||||
~~~cpp
|
||||
napi_generator/src/cli/h2sa/examples/test.h
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
namespace OHOS {
|
||||
namespace Example {
|
||||
/**
|
||||
* @brief service服务,提供IPC调用接口
|
||||
* @ServiceClass
|
||||
*/
|
||||
class test {
|
||||
public:
|
||||
int testFunc(int v1, int v2, bool v3);
|
||||
};
|
||||
} // namespace Example
|
||||
} // namespace OHOS
|
||||
#endif // TEST_H
|
||||
~~~
|
||||
|
||||
注意:.h文件中待生成的主class必须加注释:@brief service服务,提供IPC调用接口 ,如下所示:
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* @brief service服务,提供IPC调用接口
|
||||
* @ServiceClass
|
||||
*/
|
||||
```
|
||||
|
||||
5. 在napi_generator/src/cli/h2sa/src/src/gen目录下执行命令生成service框架代码:
|
||||
|
||||
~~~
|
||||
@ -28,27 +71,139 @@
|
||||
|
||||
其中,参数详情如下: -f,定义远程服务的.h文件; -l, 日志级别(0-3),默认为1; -o,生成框架代码输入到指定路径下; -s,指定serviceID。 -v,指定版本(3.2和4.1,默认版本为3.2)
|
||||
|
||||
6. 输出testservice文件夹
|
||||
#### 生成物
|
||||
|
||||
7. 编译步骤:生成的testservice文件夹放在源码根目录下
|
||||
1. 输出testservice文件夹,其中的文件如下所示:
|
||||
|
||||
8. 配置vendor serviceID
|
||||
![](./docs/figures/h2sa_outRes.png)
|
||||
|
||||
9. 编配置完成后,执行镜像编译命令 ./build.sh --product-name 产品名若编译rk3568开发板,则执行 ./build.sh --product-name rk3568
|
||||
#### 生成物的应用和验证
|
||||
|
||||
10. 烧录镜像
|
||||
1. 编译步骤:生成的testservice文件夹放在对应版本的源码根目录下
|
||||
|
||||
11. 验证
|
||||
2. 修改系统公共文件
|
||||
|
||||
> 验证一: shell登录开发板。 查看服务端进程是否已正常启动
|
||||
>
|
||||
> ~~~
|
||||
> ps -ef | grep testservice
|
||||
> ~~~
|
||||
>
|
||||
> 验证二:运行客户端
|
||||
>
|
||||
> ~~~
|
||||
> /system/bin/testclient
|
||||
> ~~~
|
||||
##### 基础配置
|
||||
|
||||
1. 服务配置
|
||||
|
||||
在foundation/systemabilitymgr/samgr/interfaces/innerkits/samgr_proxy/include/
|
||||
|
||||
system_ability_definition.h增加以下一行:
|
||||
|
||||
```
|
||||
TEST_SERVICE_ID = 9016,
|
||||
```
|
||||
|
||||
其中,TEST_SERVICE_ID宏值与用户定义的serviceID一致。
|
||||
|
||||
2. 子系统配置
|
||||
|
||||
在build/subsystem_config.json中增加以下内容。
|
||||
|
||||
```
|
||||
"testservice": {
|
||||
"path":"testservice",
|
||||
"name": "testservice"
|
||||
}
|
||||
```
|
||||
|
||||
3. 产品配置,如rk3568
|
||||
|
||||
在vendor/kaihong/rk3568/config.json中增加以下内容:
|
||||
|
||||
```
|
||||
{
|
||||
"subsystem": "testservice",
|
||||
"components": [
|
||||
{
|
||||
"component": "testservice_part",
|
||||
"features": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
4. 权限配置
|
||||
|
||||
在相应的产品目录的vendor/kaihong/rk3568/security_config/high_privilege_process_list.json中增加以下内容:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "testservice",
|
||||
"uid": "system",
|
||||
"gid": ["root", "system"]
|
||||
}
|
||||
```
|
||||
|
||||
##### selinux权限配置
|
||||
|
||||
上述基础配置时关闭了selinux 权限配置,用户新增服务时需根据自身需求配置selinux 权限 。
|
||||
|
||||
若要配置selinux权限,首先应将vendor/hihope/rk3568/config.json中"build_selinux"属性改为true,然后修改以下文件:
|
||||
|
||||
1. testservice/etc/sample_service.cfg
|
||||
|
||||
```
|
||||
"secon" : "u:r:testservice:s0"
|
||||
```
|
||||
|
||||
2. base/security/selinux_adapter/sepolicy/base/public/service_contexts
|
||||
|
||||
```
|
||||
9016 u:object_r:sa_testservice:s0
|
||||
```
|
||||
|
||||
3. base/security/selinux_adapter/sepolicy/base/public/service.te
|
||||
|
||||
```
|
||||
type sa_testservice, sa_service_attr;
|
||||
```
|
||||
|
||||
4. base/security/selinux_adapter/sepolicy/ohos_policy/startup/init/system/init.te
|
||||
|
||||
```
|
||||
allow init testservice:process { getattr rlimitinh siginh transition };
|
||||
```
|
||||
|
||||
5. base/security/selinux/sepolicy/base/public/type.te
|
||||
|
||||
```
|
||||
type testservice, sadomain, domain;
|
||||
```
|
||||
|
||||
6. /base/security/selinux/sepolicy/base/te目录下增加新service的te文件,新增文件名即为服务名,例如:testservice.te
|
||||
|
||||
```
|
||||
allow testservice init_param:file { map open read };
|
||||
allow testservice sa_testservice:samgr_class { add get };
|
||||
```
|
||||
|
||||
3. 编码完成后,执行镜像编译命令
|
||||
|
||||
~~~
|
||||
./build.sh --product-name 产品名
|
||||
|
||||
如:若编译Hi3516DV300开发板,则执行
|
||||
./build.sh --product-name Hi3516DV300
|
||||
|
||||
若编译rk3568开发板,则执行
|
||||
./build.sh --product-name rk3568
|
||||
~~~
|
||||
|
||||
4. 烧录镜像
|
||||
|
||||
5. 运行验证
|
||||
|
||||
> 验证一: shell登录开发板。 查看服务端进程是否已正常启动
|
||||
>
|
||||
> ~~~
|
||||
> ps -ef | grep testservice
|
||||
> system 288 1 0 00:02:13 ? 00:00:00 testservice_sa --- 服务进程已正常运行
|
||||
> ~~~
|
||||
>
|
||||
> 验证二:运行客户端
|
||||
>
|
||||
> ~~~
|
||||
> /system/bin/testclient
|
||||
> ~~~
|
BIN
src/cli/h2sa/docs/figures/service_frame_structure.png
Normal file
BIN
src/cli/h2sa/docs/figures/service_frame_structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
BIN
src/cli/h2sa/docs/figures/service_runLogic.png
Normal file
BIN
src/cli/h2sa/docs/figures/service_runLogic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
Loading…
Reference in New Issue
Block a user