RK3399Pro ueventd.rockchip.rc

1. 该文件位于 rk3399pro\device\rockchip\common\ueventd.rockchip.rc, rc只是一个资源文件,类似于xml,

以gps为例:

/dev/ttyS1   0660   gps   gps


分别对应设备节点,设备权限,设备所有者,设备所有者所在组。

 

2. 在它被解析使用前,还有一个init.rc文件会用到,位于rk3399pro\system\core\rootdir\init.rc(在recovery内也有一个一样的文件init.rc,而正常启动时只会使用rootdir中的init.rc,这里的是在刷机时用到)。

## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical

service为Android初始化语言的四种类型声明之一(其他三种分别为action-行为, command-命令, option-选项)

service表示服务程序,在init进程中启动,一般在另外一个由init 进程fork出的子进程中运行,在启动前会检测对应的可执行文件是否存在。

它的语法格式如下:

service   [  ]*
    

因此,有上面ueventd服务程序可知,

a.该服务的名称为 ueventd (在代码中直接使用这个名字)

b.该服务的对应的程序位置为 /sbin/ueventd

c.该服务无可选参数

d.该服务设置的选项有四个:

class core
critical
seclabel u:r:ueventd:s0
shutdown critical

① 选项class core,表示指定一个服务类为core, 所有同一个类的服务可以同时启动和停止,若不通过class选项指定一个类,则默认为“default”类服务,它的语法格式为:

class

② 选项critical,表示这是一个非常重要的服务,若该服务四分钟内退出大于四次,系统将会重启并进入Recovery模式。

③选项seclabel u:r:ueventd:s0, 表示ueventd的SELinux安全上下文名

④选项shutdown critical,表示关机时,通过什么行为来杀死服务进程。若未指定,则表示关机时通过信号SIGTERM或SIGKILL来杀死服务进程。而指定为critical,则表示关机超时才去杀死服务进程,而在关机开始时不杀进程。

所有服务所支持的选项详细解释在rk3399pro\system\core\init\README.md中有。

 

3. 节点会在init进程中被解析使用,init进程位于 rk3399pro\system\core\init\init.cpp:

int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }

    if (argc > 1 && !strcmp(argv[1], "subcontext")) {
        InitKernelLogging(argv);
        const BuiltinFunctionMap function_map;
        return SubcontextMain(argc, argv, &function_map);
    }

    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }

    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
...
}

其中的   !strcmp(basename(argv[0]), "ueventd")  就表示找到ueventd服务并执行ueventd_main()。这里主要工作是根据接收到的uevent来创建或删除设备(比如/dev/ttyS1),它最终也是调用到mknod。

 

4. 函数ueventd_main() 在rk3399pro\system\core\init\ueventd.cpp中定义:

int ueventd_main(int argc, char** argv) {
    /*
     * init sets the umask to 077 for forked processes. We need to
     * create files with exact permissions, without modification by
     * the umask.
     */
    umask(000);

    InitKernelLogging(argv);

    LOG(INFO) << "ueventd started!";

    SelinuxSetupKernelLogging();
    SelabelInitialize();

    DeviceHandler device_handler = CreateDeviceHandler();
    UeventListener uevent_listener;

    if (access(COLDBOOT_DONE, F_OK) != 0) {
        ColdBoot cold_boot(uevent_listener, device_handler);
        cold_boot.Run();
    }

    // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
    signal(SIGCHLD, SIG_IGN);
    // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
    // for SIGCHLD above.
    while (waitpid(-1, nullptr, WNOHANG) > 0) {
    }

    uevent_listener.Poll([&device_handler](const Uevent& uevent) {
        HandleFirmwareEvent(uevent);
        device_handler.HandleDeviceEvent(uevent);
        return ListenerAction::kContinue;
    });

    return 0;
}

 

5. 通过Poll监听uevent,调用HandleDeviceEvent()来解析对应的设备信息, 它在文件rk3399pro\system\core\init\devices.cpp中:
 

void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
    if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
        FixupSysPermissions(uevent.path, uevent.subsystem);
    }

    // if it's not a /dev device, nothing to do
    if (uevent.major < 0 || uevent.minor < 0) return;

    std::string devpath;
    std::vector links;
    bool block = false;

    if (uevent.subsystem == "block") {
        block = true;
        devpath = "/dev/block/" + Basename(uevent.path);

        if (StartsWith(uevent.path, "/devices")) {
            links = GetBlockDeviceSymlinks(uevent);
        }
    } else if (const auto subsystem =
                   std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
               subsystem != subsystems_.cend()) {
        devpath = subsystem->ParseDevPath(uevent);
    } else if (uevent.subsystem == "usb") {
        if (!uevent.device_name.empty()) {
            devpath = "/dev/" + uevent.device_name;
        } else {
            // This imitates the file system that would be created
            // if we were using devfs instead.
            // Minors are broken up into groups of 128, starting at "001"
            int bus_id = uevent.minor / 128 + 1;
            int device_id = uevent.minor % 128 + 1;
            devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
        }
    } else if (StartsWith(uevent.subsystem, "usb")) {
        // ignore other USB events
        return;
    } else {
        devpath = "/dev/" + Basename(uevent.path);
    }

    mkdir_recursive(Dirname(devpath), 0755);

    HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
}

 

6.  再通过HandleDevice传入解析完的uevent信息来MakeDevice,最终是用到了mknod。

add行为触发设备创建动作,remove行为触发设备删除动作。
HandleDevice:

void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
                                 int major, int minor, const std::vector& links) const {
    if (action == "add") {
        MakeDevice(devpath, block, major, minor, links);
        for (const auto& link : links) {
            if (!mkdir_recursive(Dirname(link), 0755)) {
                PLOG(ERROR) << "Failed to create directory " << Dirname(link);
            }

            if (symlink(devpath.c_str(), link.c_str())) {
                if (errno != EEXIST) {
                    PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
                } else if (std::string link_path;
                           Readlink(link, &link_path) && link_path != devpath) {
                    PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link
                                << ", which already links to: " << link_path;
                }
            }
        }
    }

    if (action == "remove") {
        for (const auto& link : links) {
            std::string link_path;
            if (Readlink(link, &link_path) && link_path == devpath) {
                unlink(link.c_str());
            }
        }
        unlink(devpath.c_str());
    }
}

MakeDevice --> mknod:

void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
                               const std::vector& links) const {
    auto[mode, uid, gid] = GetDevicePermissions(path, links);
    mode |= (block ? S_IFBLK : S_IFCHR);

    std::string secontext;
    if (!SelabelLookupFileContextBestMatch(path, links, mode, &secontext)) {
        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
        return;
    }
    if (!secontext.empty()) {
        setfscreatecon(secontext.c_str());
    }

    dev_t dev = makedev(major, minor);
    /* Temporarily change egid to avoid race condition setting the gid of the
     * device node. Unforunately changing the euid would prevent creation of
     * some device nodes, so the uid has to be set with chown() and is still
     * racy. Fixing the gid race at least fixed the issue with system_server
     * opening dynamic input devices under the AID_INPUT gid. */
    if (setegid(gid)) {
        PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
        goto out;
    }
    /* If the node already exists update its SELinux label to handle cases when
     * it was created with the wrong context during coldboot procedure. */
    if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && !secontext.empty()) {
        char* fcon = nullptr;
        int rc = lgetfilecon(path.c_str(), &fcon);
        if (rc < 0) {
            PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
            goto out;
        }

        bool different = fcon != secontext;
        freecon(fcon);

        if (different && lsetfilecon(path.c_str(), secontext.c_str())) {
            PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
                        << "' device";
        }
    }

out:
    chown(path.c_str(), uid, -1);
    if (setegid(AID_ROOT)) {
        PLOG(FATAL) << "setegid(AID_ROOT) failed";
    }

    if (!secontext.empty()) {
        setfscreatecon(nullptr);
    }
}

 


 

你可能感兴趣的:(平台硬件驱动)