diff --git a/init/README.md b/init/README.md index 423c6d151..29b972d8a 100644 --- a/init/README.md +++ b/init/README.md @@ -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 @@ -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 ` > 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. diff --git a/init/service_parser.cpp b/init/service_parser.cpp index 45d185265..e7808a999 100644 --- a/init/service_parser.cpp +++ b/init/service_parser.cpp @@ -83,6 +83,9 @@ Result ServiceParser::ParseClass(std::vector&& args) { } Result ServiceParser::ParseConsole(std::vector&& 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 {}; @@ -429,6 +432,14 @@ Result ServiceParser::ParseSocket(std::vector&& args) { return {}; } +Result ServiceParser::ParseStdioToKmsg(std::vector&& 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 ServiceParser::ParseFile(std::vector&& args) { if (args[2] != "r" && args[2] != "w" && args[2] != "rw") { @@ -514,6 +525,7 @@ const KeywordMap& 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}}, diff --git a/init/service_parser.h b/init/service_parser.h index f06310299..b1281f5a5 100644 --- a/init/service_parser.h +++ b/init/service_parser.h @@ -75,6 +75,7 @@ class ServiceParser : public SectionParser { Result ParseShutdown(std::vector&& args); Result ParseSigstop(std::vector&& args); Result ParseSocket(std::vector&& args); + Result ParseStdioToKmsg(std::vector&& args); Result ParseTimeoutPeriod(std::vector&& args); Result ParseFile(std::vector&& args); Result ParseUser(std::vector&& args); diff --git a/init/service_utils.cpp b/init/service_utils.cpp index 35f2acf66..93cffd866 100644 --- a/init/service_utils.cpp +++ b/init/service_utils.cpp @@ -16,10 +16,12 @@ #include "service_utils.h" +#include #include #include #include #include +#include #include #include @@ -121,11 +123,15 @@ Result 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) { @@ -238,7 +244,7 @@ Result 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) { diff --git a/init/service_utils.h b/init/service_utils.h index d2e69d918..3f1071e5b 100644 --- a/init/service_utils.h +++ b/init/service_utils.h @@ -77,6 +77,7 @@ struct ProcessAttributes { gid_t gid; std::vector supp_gids; int priority; + bool stdio_to_kmsg; }; Result SetProcessAttributes(const ProcessAttributes& attr);