OpenHarmony开源社区
直播中

软通动力HOS

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

OpenHarmony恢复启动子系统init进程之启动FD代持服务

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

代持原理:

16631178062575em4bwbj5f

(仅标准系统以上提供)

代持流程:

按需启动进程退出前可将fd发送给init代持,再次启动后再从init获取fd。

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

1663117806848m270mdwnyj

消息格式:

方法

说明

hold

由子服务发送给fdholder 服务,然后交给init进程代持

get

子服务请求fdholder,由fdholder返还fd给子服务

为避免其他进程访问,都需要验证gid,uid,pid。

发布fdholder

正常情况下,fd 是不能在进程间传递的,但是可以通过发布fd来达到目的。

代码:

static void PublishHoldFds(Service *service)

{

INIT_ERROR_CHECK(service != NULL, return, "Publish hold fds with invalid service");

char fdBuffer[MAX_FD_HOLDER_BUFFER] = {};

if (service->fdCount > 0 && service->fds != NULL) {

   size\_t pos = 0;

   for \(size\_t i = 0; i < service\->fdCount; i\+\+\) \{

       /\*\*

        \* 技术要点1:  dup\(fd\) 重定向fd,同时会清除O\_CLOEXEC

        \*            O\_CLOEXEC 标志本来用于防止fd泄露给子进程,这里清除这个标志,就是因为发布就是为了给子进程使用。

        \*/

       int fd = dup\(service\->fds\[i\]\);

       if \(fd < 0\) \{

           INIT\_LOGE\("Duplicate file descriptors of Service \' %s \' failed\. err = %d", service\->name, errno\);

           continue;

       \}

       

       if \(snprintf\_s\(\(char \*\)fdBuffer \+ pos, sizeof\(fdBuffer\) \- pos, sizeof\(fdBuffer\) \- 1, "%d ", fd\) < 0\) \{

           INIT\_LOGE\("snprintf\_s failed err=%d", errno\);

           return;

       \}

       pos = strlen\(fdBuffer\);

   \}

   fdBuffer\[pos \- 1\] = '\0'; // Remove last ' '

   INIT\_LOGI\("fd buffer: \[%s\]", fdBuffer\);

   

   /\*\*

    \* 技术要点2:  发布fds, 实际就是将fd设置到环境变量。在当前进程或子进程通过环境变量访问。

    \*             \#define ENV\_FD\_HOLD\_PREFIX "OHOS\_FD\_HOLD\_"  ,通过getenv\("OHOS\_FD\_HOLD\_fdfdfd"\)就能

    \*           获取所有发布的fd。

    \*/

   char envName\[MAX\_BUFFER\_LEN\] = \{\};

   \(void\)snprintf\_s\(envName, MAX\_BUFFER\_LEN, MAX\_BUFFER\_LEN \- 1, ENV\_FD\_HOLD\_PREFIX"%s", service\->name\);

   if \(setenv\(envName, fdBuffer, 1\) < 0\) \{

       INIT\_LOGE\("Failed to set env %s", envName\);

   \}

   INIT\_LOGI\("File descriptors of Service \' %s \' published", service\->name\);

}

}

就是发布一个环境变量,名称为: OHOS_FD_HOLD_servername, 将fd(可能有多个) 转变成字符串作为环境变量的值。 启动子服务进程之后,先去查找环境变量,获取它的值,分解出fd。

更多回帖

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