1# 系统参数
2## 概述
3### 功能简介
4
5OHOS系统参数为各系统服务提供简单易用的键值对访问接口,使得各个系统服务可以通过各自的系统参数来进行业务功能的配置。
6
7### 系统参数定义
8
9每个子系统定义各自模块的系统参数,包括系统参数名称、默认值以及系统参数的权限访问信息。
10#### 系统参数定义文件
11
12- 系统参数定义文件后缀名为".para" ,其格式示例如下:
13
14	```
15	const.product.name=OHOS-PRODUCT
16	const.os.version.api=26
17	const.telephony.enable=false|true
18	```
19#### 系统参数名(key)定义
20
21- 系统参数命名格式
22
23  系统参数名称采用点分格式,由多段组成,每一段可以由字母、数字、下划线组成,总长度不超过96字节;系统参数名称分为两类:
24
25  系统参数名称
26
27  | 类别 | 名称 | 示例 | 说明 |
28  | -------- | -------- | -------- | -------- |
29  | 参数名称 | Parameter Name | const.product.**name** | 完整的系统参数名称,末尾不是"."。 |
30  | 参数目录 | Parameter Directory | const.**. | 以"."结尾,标识相同前缀的所有系统参数集合。 |
31
32- 系统参数类型
33
34  系统参数一共分为三大类:
35
36  系统参数分类
37
38  | 类别 | 前缀 | 说明 |
39  | -------- | -------- | -------- |
40  | 常量 | const. | 常量参数,一旦赋值后续不会再变更;值最大长度为4096字节(包括结束符)。 |
41  | 可写 | 其它 | 可写参数,重启后丢失,值最大长度96字节(包括结束符)。|
42  | 可持久化 | persist. | 可写并可持久化保存参数,重启后不会丢失,值最大长度96字节(包括结束符)。|
43
44  每个系统参数名称总体格式如下:
45
46  ```java
47  [ const | persist ].$sub_system.$desc
48  ```
49  $sub_system为子系统或模块的名称。
50
51  $desc为子系统或模块下参数的描述字符,可以为点分格式进行分级描述。
52
53#### 系统参数值(value)定义
54
55- 系统参数的赋值分为三大类:
56
57系统参数赋值方式
58
59| 类别 | 示例 | 说明 |
60| -------- | -------- | -------- |
61| 字符串   | const.product.name=OHOS-PRODUCT | 多行字符串需要通过引号扩起来。 |
62| 数字     | const.os.version.api=26         | 数字不需要。|
63| 布尔     | const.telephony.enable=false    | 布尔型的可以为0,1,false,true。|
64
65### 系统参数权限设置
66
67系统参数支持DAC和MAC访问控制。
68#### 默认权限
69
70系统参数没有定义任何DAC,MAC权限时,其默认权限为:
71
72| [DAC] User | [DAC] Group | [DAC] UGO | [MAC] SELinux Label |
73| ---------- | ----------- | --------- | ------------------- |
74| root       | root        | 775       | default_param       |
75
76Other进程对默认权限参数的访问行为列举如下:
77
78| 操作  | 系统Native进程 | 系统应用进程 | 三方应用进程 |
79| ----- | -------------- | ------------ | ------------ |
80| get   | 允许           | 允许         | 允许         |
81| watch | 允许           | 允许         | 允许         |
82| set   | 不允许         | 不允许       | 不允许       |
83
84#### DAC访问控制权限设置
85
86- 系统参数DAC访问控制定义文件
87
88  当前系统参数的访问权限控制通过自主访问控制(Discretionary Access Control)方式管理,访问权限定义文件后缀名为".para.dac" ,init下的文件路径为/base/startup/init/services/etc/param/ohos.para.dac,具体定义内容示例如下:
89
90  ```
91  const.product.              = root:root:0775
92  persist.init.               = root:root:0775
93  startup.appspawn.           = root:root:0750
94  startup.uevent.             = ueventd:ueventd:0775
95  ```
96
97  如上所示,可以为相同前缀的所有系统参数定义一类访问权限信息,DAC信息通过":"分三段来描述,分别为参数的user,group以及UGO规则信息。
98
99  UGO规则信息每一位的定义如下:
100
101  **图1** UGO规则信息
102
103  ![UGO规则信息](figures/系统参数DAC.png)
104
105#### MAC访问控制权限设置
106
107 - 添加selinux标签
108
109    为系统参数添加selinux标签,首先需要在文件/base/security/selinux_adapter/sepolicy/base/public/parameter.te中定义标签,例如:
110
111    ```java
112    type servicectrl_param, parameter_attr
113    ```
114
115    标签定义完成后,在文件/base/security/selinux_adapter/sepolicy/base/public/parameter_contexts中添加和标签关联的系统参数前缀,这里以前缀ohos.servicectrl.为例:
116
117    ```java
118    ohos.servicectrl.           u:object_r:servicectrl_param:s0
119    ```
120
121  - 给init授权,允许map等操作,在文件/base/security/selinux/sepolicy/ohos_policy/startup/init/public/init.te中补充下面内容:
122
123    ```java
124    allow servicectrl_param tmpfs:filesystem associate;
125    allow init servicectrl_param:file { map open read relabelto relabelfrom };
126    ```
127
128  - 设置写权限,这里允许init samgr hdf_devmgr 进行系统参数写:
129
130    ```java
131    allow { init samgr hdf_devmgr } servicectrl_param:parameter_service { set };
132    ```
133
134  - 设置读权限,如果只允许部分进程访问可单独对该进程授权:
135
136    ```java
137    allow { xxx } servicectrl_param:file { map open read };
138    ```
139
140  - 如果全部允许,则设置为:
141
142    ```java
143    allow { domain -limit_domain } servicectrl_param:file { map open read };
144    ```
145
146#### 系统参数权限基本要求
147
148    每个selinux标签对应的系统参数有独立的共享内存区,同类型的系统参数建议共用selinux标签,减少系统共享内存的开销。
149
150    以sample部件为例,建议增加以下几类标签进行访问控制:
151
152    a)公开只读的系统参数,不需要定义新的标签,使用default_param
153
154    b)可写系统参数:增加标签{component}_writable_param
155
156    c)仅部件内部可读的系统参数(隐私数据):增加标签【可选】 {component}_private_param
157
158### 系统参数标签配置
159
160#### 系统参数标签文件大小配置
161
162每个标签默认分配1K内存,能存放5个左右的系统参数。如果标签下支持的系统参数较多,需在ohso.para.size文件中按照标签扩大内存大小。
163
164支持/system/etc/param/ohos.para.size/sys_prod/etc/param/ohos.para.size进行扩展。
165
166配置规则:
167
168系统参数标签=大小
169
170例如:
171
172```
173devinfo_public_param=30720
174hilog_param=40960
175```
176
177默认系统参数的共享内存大小:80KB
178
179#### 系统参数标签说明
180
181  init 会根据系统参数标签在/dev/__parameters__/目录下创建对应的共享内存映射文件,该共享内存用来存储与该标签绑定的系统参数。
182
183  共享内存文件示例:
184
185  ```
186  -rwxr-xr-- 1 root root 30720 2017-08-10 16:22 u:object_r:default_param:s0
187  -rwxr-xr-- 1 root root  1024 2017-08-10 16:22 u:object_r:devinfo_private_param:s0
188  -rwxr-xr-- 1 root root 30720 2017-08-10 16:22 u:object_r:devinfo_public_param:s0
189  -rwxr-xr-- 1 root root 40960 2017-08-10 16:22 u:object_r:hilog_param:s0
190  ```
191
192  系统参数标签会在/base/security/selinux_adapter/sepolicy/base/public/parameter.te文件中定义:
193
194  系统参数标签定义:
195
196  ```
197  type default_param, parameter_attr;
198  type devinfo_private_param, parameter_attr;
199  type devinfo_public_param, parameter_attr;
200  type hilog_param, parameter_attr;
201  ```
202
203  系统参数标签与系统参数的关联在/base/security/selinux_adapter/sepolicy/base/public/parameter_contexts定义:
204
205  以hilog_param标签为例:
206
207  ```
208  hilog.                   u:object_r:hilog_param:s0  #以hilog.为前缀的系统参数存储在hilog_param标签对应的共享内存中
209  persist.sys.hilog.       u:object_r:hilog_param:s0  #以persist.sys.hilog.为前缀的系统参数也存储在hilog_param标签对应的共享内存中
210  ```
211### 查看系统参数共享内存占用情况
212
213    系统参数共享内存占用情况的查询,提供了查询命令:param dump [verbose]
214
215    查询结果的介绍说明如下:
216
217    ```
218      Dump all parameters begin ...
219      Local security information
220      pid: 1612 uid: 0 gid: 0
221      map file: u:object_r:default_param:s0            // 系统参数标签名称(共享内存映射文件名)
222      total size: 10485720                             // 系统参数标签文件大小(标签映射的共享内存大小)
223      first offset: 0                                  // 第一个参数节点的偏移量
224      current offset: 15948                            // 当前的参数节点的偏移量
225      total node: 242                                  // 该标签内节点总数
226      total param node: 219                            // 参数节点总数
227      total security node: 0                           // selinux节点数
228      commitId        : 26                             //
229      commitPersistId : 0                              //
230      node info:                                       // 该标签下所有节点的信息
231      ... ...
232    ```
233### 系统参数的加载顺序
234
235    系统参数加载顺序
236
237    | 类别 | 路径 | 说明 |
238    | -------- | -------- | -------- |
239    | 内核参数    | /proc/cmdline | 将内核参数中的部分值转化成系统参数,并保存。内核参数中.xxx=valXXX类型的参数都转换成ohos.boot.xxx=valXXX系统参数。 |
240    | OS系统参数 | /system/etc/param/ohos_const/*.para | OS固定系统参数值参数优先加载。                               |
241    | vendor参数 | /vendor/etc/param/*.para | 厂商定义的系统参数次优先级加载。                             |
242    | system参数 | /system/etc/param/*.para | 加载各子系统定义的参数参数。如果系统参数已经存在,则忽略掉。 |
243    | persist参数 | /data/parameters/ | 如果持久化参数存在,则最后加载持久化系统参数。持久化系统参数会覆盖加载的默认系统参数。 |
244
245### 参数和标签的展示
246
247   目前按照子系统,部件把参数和标签统计的信息已经录入数据库,可以搭建[OpenHarmony实时架构信息收集与分析系统](https://gitee.com/handyohos/ohos_archinfo/tree/master)进行查看
248
249   搭建服务可参考:[OpenHarmony实时架构信息analyser模块说明](https://gitee.com/handyohos/ohos_archinfo/blob/master/analyser/README.md)
250
251   自行收集数据库信息可参考:[OpenHarmony实时架构信息收集与分析系统](https://gitee.com/handyohos/ohos_archinfo/tree/master#/handyohos/ohos_archinfo/blob/master/collector/README.md)
252
253   数据库也可以取每日构建的dayu200-db
254### 系统参数的基本操作
255
256系统参数操作原语
257
258![系统参数操作原语](figures/系统参数操作原语.png)
259
260系统参数操作原语说明
261| 功能 | 说明 |
262| -------- | -------- |
263| get      | 获取系统参数的值        |
264| set      | 设置系统参数的值        |
265| wait     | 同步等待系统参数的值变更 |
266| watch    | 异步观察系统参数的值变更 |
267
268### 约束与限制
269
270仅限小型系统、标准系统下使用。
271
272## 开发指导
273
274### 场景介绍
275设定特定的系统参数
276
277### 接口说明
278
279  - Shell命令接口
280
281    通过shell命令中可直接操作系统参数(只在标准系统提供)。系统参数shell命令如下表所示:
282
283    **表6** 系统参数shell命令说明
284
285    | 功能 | 说明 |
286    | -------- | -------- |
287    | param get [**key**] | 获取指定key名称的系统参数值;如果不指定任何name,则返回所有系统参数值。 |
288    | param set **key value** | 设置指定key名称的参数值为value。 |
289    | param wait **key** **value** | 同步等待指定key名称的系统参数值与value匹配。value可支持模糊匹配,如"*"表示任何值,"val\*"表示只匹配前三个val字符。 |
290
291  - syspara系统接口
292
293    在Coding中可以调用下列函数接口,获取对应的系统参数值(系统参数接口返回的为const字符串,不支持free操作)。
294
295    **表7** 系统属性接口说明
296    | 接口名 | 描述 |
297    | -------- | -------- |
298    | int GetParameter(const char\* key, const char\* def, char\* value, unsigned int len) | 获取系统参数。 |
299    | int SetParameter(const char\* key, const char\* value) | 设置/更新系统参数。 |
300    | const char\* GetDeviceType(void) | 返回当前设备类型。 |
301    | const char\* GetManufacture(void) | 返回当前设备生产厂家信息。 |
302    | const char\* GetBrand(void) | 返回当前设备品牌信息。 |
303    | const char\* GetMarketName(void) | 返回当前设备传播名。 |
304    | const char\* GetProductSeries(void) | 返回当前设备产品系列名。 |
305    | const char\* GetProductModel(void) | 返回当前设备认证型号。 |
306    | const char\* GetSoftwareModel(void) | 返回当前设备内部软件子型号。 |
307    | const char\* GetHardwareModel(void) | 返回当前设备硬件版本号。 |
308    | const char\* GetHardwareProfile(void) | 返回当前设备硬件profile。 |
309    | const char\* GetSerial(void) | 返回当前设备序列号(SN号)。 |
310    | const char\* GetOSFullName(void) | 返回操作系统名。 |
311    | const char\* GetDisplayVersion(void) | 返回当前设备用户可见的软件版本号。 |
312    | const char\* GetBootloaderVersion(void) | 返回当前设备Bootloader版本号。 |
313    | const char\* GetSecurityPatchTag(void) | 返回安全补丁标签。 |
314    | const char\* GetAbiList(void) | 返回当前设备支持的指令集(Abi)列表。 |
315    | int GetSdkApiVersion(void) | 返回与当前系统软件匹配的SDK API 版本号。 |
316    | int GetFirstApiVersion(void) | 返回系统软件首版本SDK API 版本号。 |
317    | const char\* GetIncrementalVersion(void) | 返回差异版本号。 |
318    | const char\* GetVersionId(void) | 返回版本id。 |
319    | const char\* GetBuildType(void) | 返回构建类型。 |
320    | const char\* GetBuildUser(void) | 返回构建账户用户名。 |
321    | const char\* GetBuildHost(void) | 返回构建主机名。 |
322    | const char\* GetBuildTime(void) | 返回构建时间。 |
323    | const char\* GetBuildRootHash(void) | 返回当前版本hash。 |
324    | const char\* GetOsReleaseType(void) | 返回系统发布类型。 |
325    | int GetDevUdid(char \*udid, int size) | 获取设备udid。 |
326    | const char *AclGetSerial(void); | 返回当前设备序列号(SN号)(带访问权限检查)。 |
327    | int AclGetDevUdid(char *udid, int size); | 获取设备udid(带访问权限检查)。 |
328
329### 开发步骤
330
3311. 系统参数定义
332
333    通过定义子系统或者产品的.para和.para.dac文件,实现默认系统参数的定义和权限控制。
334
335    ​    	在标准系统上通过ohos_prebuilt_para模版安装配置文件到到/etc/param/目录下,GN脚本示例如下:
336
337    ```go
338    import("//base/startup/init/services/etc/param/param_fixer.gni")
339
340    ohos_prebuilt_para("ohos.para") {
341        source = "//base/startup/init/services/etc/ohos.para"
342        part_name = "init"
343        module_install_dir = "etc/param"
344    }
345
346    ohos_prebuilt_para("ohos.para.dac") {
347        source = "//base/startup/init/services/etc/ohos.para.dac"
348        part_name = "init"
349        module_install_dir = "etc/param"
350    }
351    ```
352
353    在小系统上,通过copy命令,把对应的系统参数定义文件拷贝到system/etc/param目录下
354    ```go
355    copy("ohos.para") {
356      sources = [ "//base/startup/init/services/etc/param/ohos.para" ]
357      outputs = [ "$root_out_dir/system/etc/param/ohos.para" ]
358    }
359    copy("ohos.para.dac") {
360      sources = [ "//base/startup/init/services/etc/param/ohos.para.dac" ]
361      outputs = [ "$root_out_dir/system/etc/param/ohos.para.dac" ]
362    }
363    ```
364    在mini系统上,通过action把所有定义的默认系统参数转化成头文件,并编译到系统中
365    ```go
366    action("lite_const_param_to") {
367      script = "//base/startup/init/scripts/param_cfg_to_code.py"
368      args = [
369        "--source",
370        rebase_path(
371            "//base/startup/init/services/etc_lite/param/ohos_const/ohospara"),
372        "--dest_dir",
373        rebase_path("$root_out_dir/gen/init/"),
374        "--priority",
375        "0",
376      ]
377      outputs = [ "$target_gen_dir/${target_name}_param_cfg_to_code.log" ]
378    }
379    ```
3802. 系统参数使用实例
381    ```
382    // set && get
383    char key1[] = "rw.sys.version";
384    char value1[] = "10.1.0";
385    int ret = SetParameter(key1, value1);
386    char valueGet1[128] = {0};
387    ret = GetParameter(key1, "version=10.1.0", valueGet1, 128);
388
389    // get sysparm
390    char* value1 = GetDeviceType();
391    printf("Product type =%s\n", value1);
392
393    char* value2 = GetManufacture();
394    printf("Manufacture =%s\n", value2);
395
396    char* value3 = GetBrand();
397    printf("GetBrand =%s\n", value3);
398
399    char* value4 = GetMarketName();
400    printf("MarketName =%s\n", value4);
401
402    char* value5 = GetProductSeries();
403    printf("ProductSeries =%s\n", value5);
404
405    char* value6 = GetProductModel();
406    printf("ProductModel =%s\n", value6);
407
408    char* value7 = GetSoftwareModel();
409    printf("SoftwareModel =%s\n", value7);
410
411    char* value8 = GetHardwareModel();
412    printf("HardwareModel =%s\n", value8);
413
414    char* value9 = GetHardwareProfile();
415    printf("Software profile =%s\n", value9);
416
417    char* value10 = GetSerial();
418    printf("Serial =%s\n", value10);
419
420    char* value11 = GetOSFullName();
421    printf("OS name =%s\n", value11);
422
423    char* value12 = GetDisplayVersion();
424    printf("Display version =%s\n", value12);
425
426    char* value13 = GetBootloaderVersion();
427    printf("bootloader version =%s\n", value13);
428
429    char* value14 = GetSecurityPatchTag();
430    printf("secure patch level =%s\n", value14);
431
432    char* value15 = GetAbiList();
433    printf("abi list =%s\n", value15);
434
435    int value16 = GetFirstApiVersion();
436    printf("first api level =%d\n", value16);
437
438    char* value17 = GetIncrementalVersion();
439    printf("Incremental version = %s\n", value17);
440
441    char* value18 = GetVersionId();
442    printf("formal id =%s\n", value18);
443
444    char* value19 = GetBuildType();
445    printf("build type =%s\n", value19);
446
447    char* value20 = GetBuildUser();
448    printf("build user =%s\n", value20);
449
450    char* value21 = GetBuildHost();
451    printf("Build host = %s\n", value21);
452
453    char* value22 = GetBuildTime();
454    printf("build time =%s\n", value22);
455
456    char* value23 = GetBuildRootHash();
457    printf("build root later..., %s\n", value23);
458
459    char* value24 = GetOsReleaseType();
460    printf("OS release type =%s\n", value24);
461
462    char* value25 = GetOsReleaseType();
463    printf("OS release type =%s\n", value25);
464
465    char value26[65] = {0};
466    GetDevUdid(value26, 65);
467    printf("device udid =%s\n", value26);
468    ```
469### 系统参数错误码说明
470
471**错误码说明**
472
473| 枚举                             | 枚举值 | 说明                                      |
474| -------------------------------- | ------ | ----------------------------------------- |
475| PARAM_CODE_ERROR                 | -1     | 系统错误                                  |
476| PARAM_CODE_SUCCESS               | 0      | 成功                                      |
477| PARAM_CODE_INVALID_PARAM         | 100    | 系统参数接口的入参为空                     |
478| PARAM_CODE_INVALID_NAME          | 101    | 系统参数key不符合规范,长度或非法字符      |
479| PARAM_CODE_INVALID_VALUE         | 102    | 系统参数value值不符合规范,长度或非法字符  |
480| PARAM_CODE_REACHED_MAX           | 103    | 树节点已达最大值                          |
481| PARAM_CODE_NOT_SUPPORT           | 104    | 不支持此接口                              |
482| PARAM_CODE_TIMEOUT               | 105    | 访问服务端超时                            |
483| PARAM_CODE_NOT_FOUND             | 106    | 没有找到该参数                            |
484| PARAM_CODE_READ_ONLY             | 107    | 系统参数为只读参数                        |
485| PARAM_CODE_IPC_ERROR             | 108    | IPC通信异常                               |
486| PARAM_CODE_NODE_EXIST            | 109    | 系统参数的节点存在                        |
487| PARAM_WATCHER_CALLBACK_EXIST     | 110    | watcher的callback重复添加                 |
488| PARAM_WATCHER_GET_SERVICE_FAILED | 111    | watcher获取服务失败                       |
489| PARAM_CODE_MEMORY_MAP_FAILED     | 112    | 建立文件共享内存映射失败                  |
490| PARAM_WORKSPACE_NOT_INIT         | 113    | workspace 没有初始化                      |
491| PARAM_CODE_FAIL_CONNECT          | 114    | 连接paramServer 失败                      |
492| PARAM_CODE_MEMORY_NOT_ENOUGH     | 115    | 系统参数空间不足                          |
493| DAC_RESULT_INVALID_PARAM         | 1000   | 无用,定义权限错误的起始值                |
494| DAC_RESULT_FORBIDED              | 1001   | DAC权限被禁止                             |
495| SELINUX_RESULT_FORBIDED          | 1002   | selinux权限被禁止                         |
496| PARAM_CODE_MAX                   | 1003   | 枚举最大值                                |
497
498**错误定位关键日志**
499
500- system parameter set:
501
502    SetParameter failed! the errNum is: xx!
503
504    SystemSetParameter failed! name is : xxx, errNum is: xx!
505
506- system parameter get:
507
508    GetParameter_ failed! the errNum is: xx!
509
510    SystemReadParam failed! name is: xxxx, errNum is: xx!
511
512- system parameter wait:
513
514    WaitParameter failed! the errNum is: xx!
515
516    SystemWaitParameter failed! name is: xxx, errNum is: xx!
517
518- system parameter Watcher:
519
520    WatchParameter failed! the errNum is xx!
521
522    SystemWatchParameter is failed! keyPrefix is:xxx, errNum is:xx!
523## 系统参数常见问题
524
525### 如何设置一个系统参数
526
527  1、hdc shell进入终端,执行param set param.key.xxx(系统参数名) param.value.xxx(系统参数名值), 确认参数是否可以设置成功,成功则无需其他设置
528
529  2、代码侧设置系统参数,调用SetParameter接口,具体参照[接口说明](#接口说明)
530
531  3、执行param set 失败,则根据失败的日志确定对应的排查操作:
532
533  若dac 权限不足,参照DAC访问控制权限设置进行设置
534
535  若selinux 权限不足,根据" avc:  denied" 告警信息设置对应规则
536
537  若内存不够,参照[系统参数标签配置](#系统参数标签配置)进行扩展
538
539### 如何读取一个系统参数
540
541  1、hdc shell进入终端,执行param get param.key.xxx(系统参数名), 查看参数是否可以读取成功,读取成功则无需其他操作
542
543  2、代码侧获取系统参数,调用GetParameter接口,具体参照[接口说明](#接口说明)
544
545  3、执行param get 失败,则根据失败的日志确定对应的排查操作:
546
547  首先需要确认该参数是否被设置,若没有被设置,则需要先设置该参数;若已设置,则进行下一步排查
548
549  若dac 权限不足,参照DAC访问控制权限设置进行设置
550
551  若selinux 权限不足,根据" avc:  denied" 告警信息设置对应规则
552
553### 如何订阅一个系统参数的变化
554
555  1、hdc shell进入终端,执行param shell,进入Parameter shell后执行 watcher parameter param.key.xxx(系统参数名),当系统参数值发生变化时,会收到类似"Receive parameter commit 691 change aaa.aaa 11111"的消息
556
557  2、代码侧监控系统参数变化,调用WatchParameter接口
558
559  3、执行watcher parameter 失败,则根据失败的日志确定对应的排查操作:
560
561  若dac 权限不足,参照DAC访问控制权限设置进行设置
562
563  若selinux 权限不足,根据" avc:  denied" 告警信息设置对应规则
564
565### 三方应用为何无法访问系统参数
566
567默认DAC规则只允许三方应用对参数具有get, watch 的权限,因此三方应用若需要set权限需要重新设置DAC规则。 此外, 三方应用的selinux权限默认是未设置的,因此需要参照mac访问控制权限设置进行设置
568