init进程处理消息信号事件

116 阅读6分钟

init进程作为系统启动后用户空间的第一个进程,通过解析init.rc文件启动一些系统服务进程,为防止子进程成为僵尸进程,init进程需要监测子进程状态。
本文以Android 13代码为例。
1,在/system/core/init/init.cpp文件中
在第二个启动阶段的SecondStageMain函数中进行信号的处理

int SecondStageMain(int argc, char** argv) {
	Epoll epoll; //初始化epoll实例,用于处理I/O事件
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }
    InstallSignalFdHandler(&epoll); //安装信号处理器
}
static void InstallSignalFdHandler(Epoll* epoll) {
	//新建一个sigaction结构体,sa_handler是信号处理函数,指向内核指定的函数指针SIG_DFL,和Android 9.0及之前的版本不同,这里不再通过socket的读写句柄进行接收信号,改成了内核的信号处理函数SIG_DFL
	//将SA_NOCLDSTOP应用于默认的SIGCHLD处理程序可以防止signalFd在子进程停止或继续时接收SIGCHLD,即SA_NOCLDSTOP使init进程只有在其子进程终止时才会受到SIGCHLD信号。
	const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP }; //新建一个sigaction结构体,sa_handler是信号处理函数,指向内核指定的函数指针SIG_DFL.
    sigaction(SIGCHLD, &act, nullptr); //建立信号绑定关系,也就是说当监听到SIGCHLD信号时,由act这个sigaction结构体处理
  
    sigset_t mask; //初始化信号集,准备将其用于signalfd的创建
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
	
	signal_fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK); //创建一个signalfd,用于接收上面定义的信号集mask中的信号.它允许应用程序通过文件描述符接口接收信号
    if (signal_fd == -1) {
        PLOG(FATAL) << "failed to create signalfd";
	}
	constexpr int flags = EPOLLIN | EPOLLPRI; //EPOLLIN表示对应的文件描述符准备好进行读操作,而EPOLLPRI表示有紧急的数据可读
	//std::bind的第一个参数是要绑定的函数,后续参数是该函数的参数.当事件发生时,handler将作为一个回调,被epoll机制调用,执行HandleSignalFd函数,并传入false作为HandleSignalFd的参数。
	auto handler = std::bind(HandleSignalFd, false); //使用std::bind来创建一个可调用对象handler,它绑定了HandleSignalFd函数和一个参数false
	//将前面定义的事件处理器handler和事件标志flags注册到epoll实例上,以监视signal_fd(一个信号文件描述符)上的事件。
	if (auto result = epoll->RegisterHandler(signal_fd, handler, flags); !result.ok()) {
		LOG(FATAL) << result.error();
	}
}

2,在system/core/init/epoll.cpp文件中

Result<void> Epoll::RegisterHandler(int fd, Handler handler, uint32_t events) { //向epoll事件监听机制中注册一个新的文件描述符(fd)和对应的处理函数(handler),以及该fd感兴趣的事件(events)
    if (!events) {
        return Error() << "Must specify events";
    }

    Info info;
    info.events = events;
    info.handler = std::make_shared<decltype(handler)>(std::move(handler)); //使用std::make_shared来创建一个Handler的智能指针,以便在epoll事件触发时能够安全地调用处理函数。
    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(info)); //使用std::map将fd和Info结构体关联起来。如果fd已经存在于映射中,表示已经为该fd注册了处理函数,因此返回错误。
    if (!inserted) {
        return Error() << "Cannot specify two epoll handlers for a given FD";
    }
    epoll_event ev; //创建一个epoll_event结构体实例ev
    ev.events = events;
    // std::map's iterators do not get invalidated until erased, so we use the
    // pointer to the std::function in the map directly for epoll_ctl.
    ev.data.ptr = reinterpret_cast<void*>(&it->second);
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) { //调用epoll_ctl函数将fd加入到epoll_fd_的监听队列中
        Result<void> result = ErrnoError() << "epoll_ctl failed to add fd";
        epoll_handlers_.erase(fd);
        return result;
    }
    return {};
}

3,在/system/core/init/init.cpp文件中

static void HandleSignalFd(bool one_off) {
	signalfd_siginfo siginfo;
	do {
	    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo))); //从signal_fd中读取信号信息到siginfo结构体中
	    if (bytes_read < 0 && errno == EAGAIN) {
	        auto now = std::chrono::steady_clock::now();
	        std::chrono::duration<double> waited = now - started;
	        if (waited >= kDiagnosticTimeout) {
	            LOG(ERROR) << "epoll() woke us up, but we waited with no SIGCHLD!";
	            started = now;
	        }
	
	        std::this_thread::sleep_for(100ms);
	        continue;
	    }
	    if (bytes_read != sizeof(siginfo)) {
	        PLOG(ERROR) << "Failed to read siginfo from signal_fd";
	        return;
	    }
	    break; //如果read调用成功读取了siginfo结构体大小的字节数,则跳出循环
	} while (!one_off);
	switch (siginfo.ssi_signo) {
		//当init进程启动一个子进程时,它会继续运行并等待来自其子进程的信号或消息。如果子进程结束了,内核会向init进程发送SIGCHLD信号。
	    case SIGCHLD:
	        ReapAnyOutstandingChildren(); //终止出现问题的子进程,会走到sigchld_handler.cpp中的ReapOneProcess函数
	        break;
	    case SIGTERM:
	        HandleSigtermSignal(siginfo);
	        break;
	    default:
	        PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
           break;
    }
}

在Android系统中,子进程并不直接给init进程发送SIGCHLD信号。SIGCHLD信号是当一个进程终止或停止时,由内核发送给其父进程的信号。这个机制是UNIX和类UNIX系统(包括Android)中进程管理的一部分,用于通知父进程其子进程的状态变化。 init进程通过信号处理器(signal handler)HandleSignalFd来响应SIGCHLD信号。当init进程接收到SIGCHLD信号时,它会执行一个特定的函数(即信号处理器)ReapOneProcess来处理这个信号。
4,在system/core/init/sigchld_handler.cpp文件中

void ReapAnyOutstandingChildren() {
    while (ReapOneProcess() != 0) {
    }
}
static pid_t ReapOneProcess() {
	siginfo_t siginfo = {};
    // This returns a zombie pid or informs us that there are no zombies left to be reaped.
    // It does NOT reap the pid; that is done below.
    if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) { //用waitpid函数获取状态发生变化的子进程pid
        PLOG(ERROR) << "waitid failed";
        return 0;
    }
    auto pid = siginfo.si_pid;
    if (pid == 0) return 0;
	std::string name;
    std::string wait_string;
    Service* service = nullptr;
	service = ServiceList::GetInstance().FindService(pid, &Service::pid);//查找死亡进程服务
    if (service) {
        name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
        if (service->flags() & SVC_EXEC) {
            auto exec_duration = boot_clock::now() - service->time_started();
            auto exec_duration_ms =
                std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
            wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
        } else if (service->flags() & SVC_ONESHOT) {
            auto exec_duration = boot_clock::now() - service->time_started();
            auto exec_duration_ms =
                    std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration)
                            .count();
            wait_string = StringPrintf(" oneshot service took %f seconds in background",
                                       exec_duration_ms / 1000.0f);
        }
    } else {
        name = StringPrintf("Untracked pid %d", pid);
    }
	service->Reap(siginfo); //调用system/core/init/service.cpp中的Reap函数清理子进程
}

5,在system/core/init/service.cpp文件中

void Service::Reap(const siginfo_t& siginfo) {
	if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
		KillProcessGroup(SIGKILL, false); //杀死进程
	}
	for (const auto& socket : sockets_) {
	    if (socket.persist) {
	        continue;
	    }
	    auto path = ANDROID_SOCKET_DIR "/" + socket.name;
	    unlink(path.c_str());
	}
	if (name_ == "zygote" || name_ == "zygote64") { //如果是zygote则清除所有服务进程
	    removeAllEmptyProcessGroups();
	}
	flags_ &= (~SVC_RESTART);
	flags_ |= SVC_RESTARTING; //设置重启标志位
	onrestart_.ExecuteAllCommands();//执行rc中该服务的所有onrestart命令
}

6,此时在system/core/init/init.cpp文件中

int SecondStageMain(int argc, char** argv) {
	while (true) { //这是一个无限循环,init进程在这里处理各种事件和任务,如执行命令、处理进程动作、等待epoll事件等
		if (!IsShuttingDown()) {
	        auto next_process_action_time = HandleProcessActions(); //nit进程的死循环中HandleProcessActions会处理服务重启
	        // If there's a process that needs restarting, wake up in time for that.
	        if (next_process_action_time) {
	            epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
	                    *next_process_action_time - boot_clock::now());
	            if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
	        }
	    }
	
	
	
	}
}
static std::optional<boot_clock::time_point> HandleProcessActions() {
	//遍历所有的service
	for (const auto& s : ServiceList::GetInstance()) {
		if (!(s->flags() & SVC_RESTARTING)) 
			continue;
		auto restart_time = s->time_started() + s->restart_period();
		if (boot_clock::now() > restart_time) {
		    if (auto result = s->Start(); !result.ok()) { //调用start重启服务
		        LOG(ERROR) << "Could not restart process '" << s->name() << "': " << result.error();
		    }
		} else {
		    if (!next_process_action_time || restart_time < *next_process_action_time) {
		        next_process_action_time = restart_time;
		    }
		}
	}
}

7,在system/core/init/service.cpp文件中

Result<void> Service::Start() {
	pid_t pid = -1;
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
    
    if (pid == 0) {
        umask(077);
        RunService(override_mount_namespace, descriptors, std::move(pipefd));//在子进程中运行服务
        _exit(127);
    }
}

void Service::RunService(const std::optional<MountNamespace>& override_mount_namespace,
	const std::vector<Descriptor>& descriptors,std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd) {
	if (!ExpandArgsAndExecv(args_, sigstop_)) { //调用ExpandArgsAndExecv执行
	    PLOG(ERROR) << "cannot execv('" << args_[0]
	                << "'). See the 'Debugging init' section of init's README.md for tips";
	}
}

static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
    std::vector<std::string> expanded_args;
    std::vector<char*> c_strings;

    expanded_args.resize(args.size());
    c_strings.push_back(const_cast<char*>(args[0].data()));
    for (std::size_t i = 1; i < args.size(); ++i) {
        auto expanded_arg = ExpandProps(args[i]);
        if (!expanded_arg.ok()) {
            LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
        }
        expanded_args[i] = *expanded_arg;
        c_strings.push_back(expanded_args[i].data());
    }
    c_strings.push_back(nullptr);

    if (sigstop) {
        kill(getpid(), SIGSTOP);
    }

    return execv(c_strings[0], c_strings.data()) == 0; //执行c_string[0]对应的文件,比如启动zygote64
}

调用execv执行可执行文件即可启动相应的服务。