Loading init/README.md +9 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ runs the service. be changed by setting the "androidboot.console" kernel parameter. In all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be specified as just "console tty0". This option connects stdin, stdout, and stderr to the console. It is mutually exclusive with the stdio_to_kmsg option, which only connects stdout and stderr to kmsg. `critical` > This is a device-critical service. If it exits more than four times in Loading Loading @@ -313,6 +315,13 @@ runs the service. seclabel or computed based on the service executable file security context. For native executables see libcutils android\_get\_control\_socket(). `stdio_to_kmsg` > Redirect stdout and stderr to /dev/kmsg_debug. This is useful for services that do not use native Android logging during early boot and whose logs messages we want to capture. This is only enabled when /dev/kmsg_debug is enabled, which is only enabled on userdebug and eng builds. This is mutually exclusive with the console option, which additionally connects stdin to the given console. `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. Loading init/service_parser.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,9 @@ Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) { } Result<void> ServiceParser::ParseConsole(std::vector<std::string>&& args) { if (service_->proc_attr_.stdio_to_kmsg) { return Error() << "'console' and 'stdio_to_kmsg' are mutually exclusive"; } service_->flags_ |= SVC_CONSOLE; service_->proc_attr_.console = args.size() > 1 ? "/dev/" + args[1] : ""; return {}; Loading Loading @@ -429,6 +432,14 @@ Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) { return {}; } Result<void> ServiceParser::ParseStdioToKmsg(std::vector<std::string>&& args) { if (service_->flags_ & SVC_CONSOLE) { return Error() << "'stdio_to_kmsg' and 'console' are mutually exclusive"; } service_->proc_attr_.stdio_to_kmsg = true; return {}; } // name type Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) { if (args[2] != "r" && args[2] != "w" && args[2] != "rw") { Loading Loading @@ -514,6 +525,7 @@ const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() con {"shutdown", {1, 1, &ServiceParser::ParseShutdown}}, {"sigstop", {0, 0, &ServiceParser::ParseSigstop}}, {"socket", {3, 6, &ServiceParser::ParseSocket}}, {"stdio_to_kmsg", {0, 0, &ServiceParser::ParseStdioToKmsg}}, {"timeout_period", {1, 1, &ServiceParser::ParseTimeoutPeriod}}, {"updatable", {0, 0, &ServiceParser::ParseUpdatable}}, {"user", {1, 1, &ServiceParser::ParseUser}}, Loading init/service_parser.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ class ServiceParser : public SectionParser { Result<void> ParseShutdown(std::vector<std::string>&& args); Result<void> ParseSigstop(std::vector<std::string>&& args); Result<void> ParseSocket(std::vector<std::string>&& args); Result<void> ParseStdioToKmsg(std::vector<std::string>&& args); Result<void> ParseTimeoutPeriod(std::vector<std::string>&& args); Result<void> ParseFile(std::vector<std::string>&& args); Result<void> ParseUser(std::vector<std::string>&& args); Loading init/service_utils.cpp +11 −5 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ #include "service_utils.h" #include <fcntl.h> #include <grp.h> #include <sys/mount.h> #include <sys/prctl.h> #include <sys/wait.h> #include <unistd.h> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -121,11 +123,15 @@ Result<void> SetUpPidNamespace(const char* name) { return {}; } void ZapStdio() { void SetupStdio(bool stdio_to_kmsg) { auto fd = unique_fd{open("/dev/null", O_RDWR | O_CLOEXEC)}; dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); dup2(fd, STDIN_FILENO); if (stdio_to_kmsg) { fd.reset(open("/dev/kmsg_debug", O_WRONLY | O_CLOEXEC)); if (fd == -1) fd.reset(open("/dev/null", O_WRONLY | O_CLOEXEC)); } dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); } void OpenConsole(const std::string& console) { Loading Loading @@ -238,7 +244,7 @@ Result<void> SetProcessAttributes(const ProcessAttributes& attr) { if (setpgid(0, getpid()) == -1) { return ErrnoError() << "setpgid failed"; } ZapStdio(); SetupStdio(attr.stdio_to_kmsg); } for (const auto& rlimit : attr.rlimits) { Loading init/service_utils.h +1 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ struct ProcessAttributes { gid_t gid; std::vector<gid_t> supp_gids; int priority; bool stdio_to_kmsg; }; Result<void> SetProcessAttributes(const ProcessAttributes& attr); Loading Loading
init/README.md +9 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ runs the service. be changed by setting the "androidboot.console" kernel parameter. In all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be specified as just "console tty0". This option connects stdin, stdout, and stderr to the console. It is mutually exclusive with the stdio_to_kmsg option, which only connects stdout and stderr to kmsg. `critical` > This is a device-critical service. If it exits more than four times in Loading Loading @@ -313,6 +315,13 @@ runs the service. seclabel or computed based on the service executable file security context. For native executables see libcutils android\_get\_control\_socket(). `stdio_to_kmsg` > Redirect stdout and stderr to /dev/kmsg_debug. This is useful for services that do not use native Android logging during early boot and whose logs messages we want to capture. This is only enabled when /dev/kmsg_debug is enabled, which is only enabled on userdebug and eng builds. This is mutually exclusive with the console option, which additionally connects stdin to the given console. `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. Loading
init/service_parser.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,9 @@ Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) { } Result<void> ServiceParser::ParseConsole(std::vector<std::string>&& args) { if (service_->proc_attr_.stdio_to_kmsg) { return Error() << "'console' and 'stdio_to_kmsg' are mutually exclusive"; } service_->flags_ |= SVC_CONSOLE; service_->proc_attr_.console = args.size() > 1 ? "/dev/" + args[1] : ""; return {}; Loading Loading @@ -429,6 +432,14 @@ Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) { return {}; } Result<void> ServiceParser::ParseStdioToKmsg(std::vector<std::string>&& args) { if (service_->flags_ & SVC_CONSOLE) { return Error() << "'stdio_to_kmsg' and 'console' are mutually exclusive"; } service_->proc_attr_.stdio_to_kmsg = true; return {}; } // name type Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) { if (args[2] != "r" && args[2] != "w" && args[2] != "rw") { Loading Loading @@ -514,6 +525,7 @@ const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() con {"shutdown", {1, 1, &ServiceParser::ParseShutdown}}, {"sigstop", {0, 0, &ServiceParser::ParseSigstop}}, {"socket", {3, 6, &ServiceParser::ParseSocket}}, {"stdio_to_kmsg", {0, 0, &ServiceParser::ParseStdioToKmsg}}, {"timeout_period", {1, 1, &ServiceParser::ParseTimeoutPeriod}}, {"updatable", {0, 0, &ServiceParser::ParseUpdatable}}, {"user", {1, 1, &ServiceParser::ParseUser}}, Loading
init/service_parser.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ class ServiceParser : public SectionParser { Result<void> ParseShutdown(std::vector<std::string>&& args); Result<void> ParseSigstop(std::vector<std::string>&& args); Result<void> ParseSocket(std::vector<std::string>&& args); Result<void> ParseStdioToKmsg(std::vector<std::string>&& args); Result<void> ParseTimeoutPeriod(std::vector<std::string>&& args); Result<void> ParseFile(std::vector<std::string>&& args); Result<void> ParseUser(std::vector<std::string>&& args); Loading
init/service_utils.cpp +11 −5 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ #include "service_utils.h" #include <fcntl.h> #include <grp.h> #include <sys/mount.h> #include <sys/prctl.h> #include <sys/wait.h> #include <unistd.h> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -121,11 +123,15 @@ Result<void> SetUpPidNamespace(const char* name) { return {}; } void ZapStdio() { void SetupStdio(bool stdio_to_kmsg) { auto fd = unique_fd{open("/dev/null", O_RDWR | O_CLOEXEC)}; dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); dup2(fd, STDIN_FILENO); if (stdio_to_kmsg) { fd.reset(open("/dev/kmsg_debug", O_WRONLY | O_CLOEXEC)); if (fd == -1) fd.reset(open("/dev/null", O_WRONLY | O_CLOEXEC)); } dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); } void OpenConsole(const std::string& console) { Loading Loading @@ -238,7 +244,7 @@ Result<void> SetProcessAttributes(const ProcessAttributes& attr) { if (setpgid(0, getpid()) == -1) { return ErrnoError() << "setpgid failed"; } ZapStdio(); SetupStdio(attr.stdio_to_kmsg); } for (const auto& rlimit : attr.rlimits) { Loading
init/service_utils.h +1 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ struct ProcessAttributes { gid_t gid; std::vector<gid_t> supp_gids; int priority; bool stdio_to_kmsg; }; Result<void> SetProcessAttributes(const ProcessAttributes& attr); Loading