Android10 Framework—Init进程-17.init进程其它补充

40 阅读2分钟

重启或关机事件

在前面讲的“属性变化控制Service”中,有个特殊项就是sys.powerctl

void property_changed(const std::string& name, const std::string& value) {
    // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
    // This is to ensure that init will always and immediately shutdown/reboot, regardless of
    // if there are other pending events to process or if init is waiting on an exec service or
    // waiting on a property.
    // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
    // commands to be executed.
    if (name == "sys.powerctl") {
        // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
        // because it modifies the contents of the action queue, which can cause the action queue
        // to get into a bad state if this function is called from a command being executed by the
        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
        // command is run in the main init loop.
        // TODO: once property service is removed from init, this will never happen from a builtin,
        // but rather from a callback from the property service socket, in which case this hack can
        // go away.
        shutdown_command = value;
        do_shutdown = true;
    }

    if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);

    if (waiting_for_prop) {
        if (wait_prop_name == name && wait_prop_value == value) {
            LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
                      << "' took " << *waiting_for_prop;
            ResetWaitForProp();
        }
    }
}

从这个注释中可以看出:如果属性事件是sys.powerctl,必须立即进行处理,确保立刻关机或重启;紧接着do_shutdown被设置为true。

int SecondStageMain(int argc, char** argv) {
    ...省略代码
    
    while (true) {
        ...
        
        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }
        
        ...
    }
    
    ...省略代码 
} 

此时do_shutdown为true,就会调用HandlePowerctlMessage,在其中会完成shutdown/reboot操作。

timeout_period处理

`timeout_period <seconds>`
> Provide a timeout after which point the service will be killed. The oneshot keyword is respected
  here, so oneshot services do not automatically restart, however all other services will.
  This is particularly useful for creating a periodic service combined with the restart_period
  option described above.

rc文件中可以通过timeout_period定义服务的超时时间,当服务运行超过这个时间后,就会自动重启

static std::optional<boot_clock::time_point> HandleProcessActions() {
    std::optional<boot_clock::time_point> next_process_action_time;
    for (const auto& s : ServiceList::GetInstance()) {
        if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
            auto timeout_time = s->time_started() + *s->timeout_period();
            if (boot_clock::now() > timeout_time) {
                s->Timeout();
            } else {
                if (!next_process_action_time || timeout_time < *next_process_action_time) {
                    next_process_action_time = timeout_time;
                }
            }
        }

        ...
    }
    return next_process_action_time;
}

timeout_period处理代码在HandleProcessActions中,如果当前时间已经超过了服务启动时间的timeout_period后,会调用服务的Timeout

void Service::Timeout() {
    // All process state flags will be taken care of in Reap(), we really just want to kill the
    // process here when it times out.  Oneshot processes will transition to be disabled, and
    // all other processes will transition to be restarting.
    LOG(INFO) << "Service '" << name_ << "' expired its timeout of " << timeout_period_->count()
              << " seconds and will now be killed";
    if (pid_) {
        KillProcessGroup(SIGKILL);
        NotifyStateChange("stopping");
    }
}
  • 调用KillProcessGroup清理进程组
  • 通知进程状态改变为stopping