2

OpenHarmony恢复启动子系统init进程之启动FD代持服务-开源基础软件社区-51CTO.COM

 2 years ago
source link: https://ost.51cto.com/posts/17030
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

代持原理:

OpenHarmony恢复启动子系统init进程之启动FD代持服务-开源基础软件社区

代持流程:

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

OpenHarmony恢复启动子系统init进程之启动FD代持服务-开源基础软件社区

消息格式:

方法 说明
hold 由子服务发送给fdholder 服务,然后交给init进程代持
get 子服务请求fdholder,由fdholder返还fd给子服务
为避免其他进程访问,都需要验证gid,uid,pid。

发布fdholder

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

{
    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。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK