OpenHarmony开源社区
直播中

软通动力HOS

3年用户 221经验值
擅长:EMC/MEI设计 EDA/IC设计 处理器/DSP
私信 关注
[经验]

OpenHarmony恢复启动子系统init进程之服务管理与发布

图片1.png

配置文件加载

Jobs 实际上是作为参数使用,作为trigger参数使用。

1663568075045y8el9hoo0y

使用HashMap管理,所有结点按类型存储,通过name获取。

文件

加载类型

说明

/etc/init.cfg

Jobs,Services

/system/etc/*.cfg

Jobs,Services

/system/etc/init/*.cfg

Jobs,Services

系统SA服务

/vendor/etc/init/ *.cfg

Jobs,Services

供应商SA服务

/system/etc/plugin_modules.cfg

插件信息

主要是提供了bootchart 插件,用于统计系统信息。

/vendor/etc/init/init.{hardware}.cfg

Jobs,Services

平台移植时,完成平台相关的初始化设置,如安装ko驱动,设置平台相关的/proc节点信息

/system/etc/device.boot.group.cfg

/system/etc/device.charing.group.cfg

Jobs,Services,Groups

cfg 配置文件:

cfg 文件是一种json格式的配置文件,由import,jobs,services 三部分构成。

import 表示依赖的cfg配置,格式和语法都一样,也需要解析加载。跟硬件设备相关的可以加载在这里。

jobs 是需要执行的命令集合,执行的是一组命令,可以通过start ,stop命令启动服务,也可以通过trigger命令触发其他job

services 定义的是服务的名称、执行path、触发条件,重启条件等,服务也可以通过调用jobs。具体在服务管理里有详细讲解。

"import":[

"/etc/init\.usb\.cfg",

"/etc/init\.usb\.configfs\.cfg",

"/vendor/etc/init\.$\{ohos\.boot\.hardware\}\.cfg"

],

"jobs":[

{

"name":"init",

"cmds":\[

\]

}

],

"services":[

{


"name" : "ueventd",

"path" : \["/system/bin/ueventd"\],

"critical" : \[ 0, 15, 5\],

"ondemand" : true,

"start\-mode" : "condition"

\}

]

插件:

{

"modules" : [

\{

"name": "bootchart",

"start\-mode" : "static",

"lib\-name" : "libbootchart\.z\.so"

\}

]

}

bootchart 插件:

bootchart是一个用于linux启动过程性能分析的开源工具软件,在系统中自动收集CPU占用率、磁盘吞吐率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程

用户态可通过begetctl 启动。

将/data/bootchart/下的log文件导出来。在Ubuntu上通过pybootchartgui.py 工具分析。

服务发布

服务发布是将socket,file 等创建或打开之后,将句柄fd设置到环境变量,并且在当前进程及子进程都可以使用。

#define HOS_SOCKET_DIR "/dev/unix/socket"

#define HOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_"

static int SetSocketEnv(int fd, const char *name)

{

INIT_ERROR_CHECK(name != NULL, return SERVICE_FAILURE, "Invalid name");

char pubName[MAX_SOCKET_ENV_PREFIX_LEN] = { 0 };

char val[MAX_SOCKET_FD_LEN] = { 0 };

INIT_CHECK_RETURN_VALUE(snprintf_s(pubName, sizeof(pubName), sizeof(pubName) - 1, HOS_SOCKET_ENV_PREFIX "%s",

name\) >= 0, \-1\);

INIT_CHECK_RETURN_VALUE(snprintf_s(val, sizeof(val), sizeof(val) - 1, "%d", fd) >= 0, -1);

int ret = setenv(pubName, val, 1);

INIT_ERROR_CHECK(ret >= 0, return -1, "setenv fail %d ", errno);

fcntl(fd, F_SETFD, 0);

return 0;

}

比如fd = 100,name="ueventd" 最终设置了一个环境变量: OHOS_SOCKET_ueventd="100"

执行服务进程之后,在服务进程内部会查找这个环境变量,获取fd的值100,并启动服务循环,收发数据。

如果没找到这个环境变量,服务进程内部按默认参数创建一个socket,并启动循环收发数据。

发布服务的主要目的:

  1. 能较好使用外部配置的参数来创建服务
  2. 避免重复创建同一个socket服务,或重复打开同一个文件服务
  3. 按需启动的情况下,父进程希望控制服务进程的启动和停止
  4. 服务代持能力

技术关键:

fcntl(fd, F_SETFD, 0);

主要是将SOCKET_CLOEXEC标志清除掉,这样才能在子进程访问,否则无法访问。或者在创建socket的时候,去掉SOCKET_CLOEXEC;如果是文件,这个标志是O_CLOEXEC。

FD代持( 仅标准系统以上提供

FD代持是按需启动的一个辅助扩展机制,按需启动进程可以保持退出前的fd状态句柄不丢失。按需启动进程退出前可将fd发送给init代持,再次启动后再从init获取fd。

init提供了相关接口供服务调用,服务进程退出前调用接口将fd通过支持IPC通信的socket发送给init代持,待该服务重新启动时,init将持有的该服务相关的fd句柄通过同样的方式返回给服务。

服务配置
cfg 的services部分:

"services" : [{

"name" : "ueventd",

"path" : \["/system/bin/ueventd"\],

"socket" : \[\{

"name" : "ueventd",

"family" : "AF\_NETLINK",

"type" : "SOCK\_DGRAM",

"protocol" : "NETLINK\_KOBJECT\_UEVENT",

"permissions" : "0660",

"uid" : "system",

"gid" : "system",

"option" : \[

"SOCKET\_OPTION\_PASSCRED",

"SOCKET\_OPTION\_RCVBUFFORCE",

"SOCK\_CLOEXEC",

"SOCK\_NONBLOCK"

\]

\}\],

"critical" : \[ 0, 15, 5\],

"ondemand" : true,

"start\-mode" : "condition"

\}, \{

"name" : "console",

"path" : \["/system/bin/sh"\],

"start\-mode" : "condition",

"disabled" : 1,

"console" : 1,

"uid" : "root",

"gid" : \["shell", "log", "readproc"\],

"jobs" : \{

"on\-start" : "services:console"

\}

\}, \{

"name" : "watchdog\_service",

"start\-mode" : "condition",

"path" : \["/system/bin/watchdog\_service", "10", "2"\],

"disabled" : 1,

"uid" : "root",

"gid" : \["shell", "log", "readproc"\]

\}, \{

"name" : "misc",

"path" : \["/system/bin/misc\_daemon", "\-\-write\_logo", "/vendor/logo\.rgb"\],

"once" : 1

\}

]

附录表——service字段说明

字段名

说明

name:当前服务的名称,须确保非空且长度≤32字节。

path:当前服务的可执行文件全路径和参数,数组形式。须确保第一个数组元素为可执行文件路径、数组元素个数≤20、每个元素为字符串形式以及每个字符串长度≤64字节。

uid:当前服务进程的uid值。

gid:当前服务进程的gid值。

secon:当前服务进程的安全上下文(当前不需要设置该字段)。

once:当前服务进程是否为一次性进程:

1:一次性进程,当该进程退出时,init不会重新启动该服务进程

0 : 常驻进程,当该进程退出时,init收到SIGCHLD信号并重新启动该服务进程;

注意: 对于常驻进程,若在4分钟之内连续退出5次,第5次退出时init将不会再重新拉起该服务进程。

importance: 当前服务进程优先级, 取值范围[19, -20]

caps:当前服务所需的capability值,根据安全子系统已支持的capability,评估所需的capability,遵循最小权限原则配置(当前最多可配置100个值)。

critical: 服务启动失败后, 需要M秒内重新拉起, 拉起失败N次后, 直接重启系统, N默认为4, M默认20。(仅L2以上提供 "critical" : [0, 2, 10])

0:不使能;

1:使能;

cpucores: 服务需要的绑定的cpu核心数, 类型为int型数组

d-caps: 分布式能力 (仅L2以上提供)

apl: 能力特权级别:system_core, normal, system_basic。 默认system_core (仅L2以上提供)

start-mode: 服务的启动模式,具体描述:init服务启动控制(仅L2以上提供)。包括condition,boot,normal

jobs: 当前服务在不同阶段可以执行的job。具体说明可以看:init服务并行控制(仅L2以上提供),类似于:

"jobs" : {

"on-boot" : "services:console"

"on-start" : "services:console"

"on-stop" : "services:console"

}

ondemand

,按需启动的服务需要配置的属性,配置有该属性的服务不会被start命令拉起,如果该服务同时配置有socket,init将会在解析服务时创建该socket并将其监听,当socket有消息上报时,init拉起对应服务

按需启动:

触发服务启动的事件可能是被init监听的相关socket有消息上报、samgr收到客户端的请求需要拉起SA服务等情况;

  • SA进程按需启动

应用请求SA句柄时samgr 需验证sa_profile.xml 是否配置为按需启动

  • socket进程按需启动

init进程在fork阶段为socket发布socket

socket上有报文事件后,init进程拉起socket进程进行报文处理,init进程取消socket数据的监听,由socket进程处理。socket进程无报文处理后,可以自动退出,退出后init进程回收该子进程并重新监听socket网络数据。

  • 热插拔服务进程按需启动

进程可根据系统参数的变化进行热插拔事件按需启动处理。

回帖(2)

余温重顾

2022-9-19 18:25:14
感谢大佬分享
举报

他在笑

2022-9-20 10:25:10
举报

更多回帖

发帖
×
20
完善资料,
赚取积分