Loading init/README.md +40 −20 Original line number Diff line number Diff line Loading @@ -282,6 +282,10 @@ runs the service. "shutdown critical" will be killed. When the service tagged with "shutdown critical" is not running when shut down starts, it will be started. `sigstop` > Send SIGSTOP to the service immediately before exec is called. This is intended for debugging. See the below section on debugging for how this can be used. `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]` > Create a unix domain socket named /dev/socket/_name_ and pass its fd to the launched process. _type_ must be "dgram", "stream" or "seqpacket". User and Loading Loading @@ -708,23 +712,39 @@ affected. Debugging init -------------- By default, programs executed by init will drop stdout and stderr into /dev/null. To help with debugging, you can execute your program via the Android program logwrapper. This will redirect stdout/stderr into the Android logging system (accessed via logcat). For example service akmd /system/bin/logwrapper /sbin/akmd For quicker turnaround when working on init itself, use: mm -j && m ramdisk-nodeps && m bootimage-nodeps && adb reboot bootloader && fastboot boot $ANDROID_PRODUCT_OUT/boot.img Alternatively, use the emulator: emulator -partition-size 1024 \ -verbose -show-kernel -no-window Launching init services without init is not recommended as init sets up a significant amount of environment (user, groups, security label, capabilities, etc) that is hard to replicate manually. If it is required to debug a service from its very start, the `sigstop` service option is added. This option will send SIGSTOP to a service immediately before calling exec. This gives a window where developers can attach a debugger, strace, etc before continuing the service with SIGCONT. This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties. Below is an example of dynamically debugging logd via the above: stop logd setprop ctl.sigstop_on logd start logd ps -e | grep logd > logd 4343 1 18156 1684 do_signal_stop 538280 T init gdbclient.py -p 4343 b main c c c > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427 Below is an example of doing the same but with strace stop logd setprop ctl.sigstop_on logd start logd ps -e | grep logd > logd 4343 1 18156 1684 do_signal_stop 538280 T init strace -p 4343 (From a different shell) kill -SIGCONT 4343 > strace runs init/init.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,10 @@ struct ControlMessageFunction { static const std::map<std::string, ControlMessageFunction>& get_control_message_map() { // clang-format off static const std::map<std::string, ControlMessageFunction> control_message_functions = { {"sigstop_on", {ControlTarget::SERVICE, [](auto* service) { service->set_sigstop(true); return Success(); }}}, {"sigstop_off", {ControlTarget::SERVICE, [](auto* service) { service->set_sigstop(false); return Success(); }}}, {"start", {ControlTarget::SERVICE, DoControlStart}}, {"stop", {ControlTarget::SERVICE, DoControlStop}}, {"restart", {ControlTarget::SERVICE, DoControlRestart}}, Loading init/service.cpp +12 −2 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ static void SetUpPidNamespace(const std::string& service_name) { } } static bool ExpandArgsAndExecv(const std::vector<std::string>& args) { static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) { std::vector<std::string> expanded_args; std::vector<char*> c_strings; Loading @@ -169,6 +169,10 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args) { } c_strings.push_back(nullptr); if (sigstop) { kill(getpid(), SIGSTOP); } return execv(c_strings[0], c_strings.data()) == 0; } Loading Loading @@ -582,6 +586,11 @@ Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) { return Success(); } Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) { sigstop_ = true; return Success(); } Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) { environment_vars_.emplace_back(args[1], args[2]); return Success(); Loading Loading @@ -704,6 +713,7 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const { {"seclabel", {1, 1, &Service::ParseSeclabel}}, {"setenv", {2, 2, &Service::ParseSetenv}}, {"shutdown", {1, 1, &Service::ParseShutdown}}, {"sigstop", {0, 0, &Service::ParseSigstop}}, {"socket", {3, 6, &Service::ParseSocket}}, {"user", {1, 1, &Service::ParseUser}}, {"writepid", {1, kMax, &Service::ParseWritepid}}, Loading Loading @@ -862,7 +872,7 @@ Result<Success> Service::Start() { // priority. Aborts on failure. SetProcessAttributes(); if (!ExpandArgsAndExecv(args_)) { if (!ExpandArgsAndExecv(args_, sigstop_)) { PLOG(ERROR) << "cannot execve('" << args_[0] << "')"; } Loading init/service.h +4 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ class Service { bool is_override() const { return override_; } bool process_cgroup_empty() const { return process_cgroup_empty_; } unsigned long start_order() const { return start_order_; } void set_sigstop(bool value) { sigstop_ = value; } const std::vector<std::string>& args() const { return args_; } private: Loading Loading @@ -153,6 +154,7 @@ class Service { Result<Success> ParseSeclabel(const std::vector<std::string>& args); Result<Success> ParseSetenv(const std::vector<std::string>& args); Result<Success> ParseShutdown(const std::vector<std::string>& args); Result<Success> ParseSigstop(const std::vector<std::string>& args); Result<Success> ParseSocket(const std::vector<std::string>& args); Result<Success> ParseFile(const std::vector<std::string>& args); Result<Success> ParseUser(const std::vector<std::string>& args); Loading Loading @@ -213,6 +215,8 @@ class Service { std::vector<std::pair<int, rlimit>> rlimits_; bool sigstop_ = false; std::vector<std::string> args_; std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_; Loading Loading
init/README.md +40 −20 Original line number Diff line number Diff line Loading @@ -282,6 +282,10 @@ runs the service. "shutdown critical" will be killed. When the service tagged with "shutdown critical" is not running when shut down starts, it will be started. `sigstop` > Send SIGSTOP to the service immediately before exec is called. This is intended for debugging. See the below section on debugging for how this can be used. `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]` > Create a unix domain socket named /dev/socket/_name_ and pass its fd to the launched process. _type_ must be "dgram", "stream" or "seqpacket". User and Loading Loading @@ -708,23 +712,39 @@ affected. Debugging init -------------- By default, programs executed by init will drop stdout and stderr into /dev/null. To help with debugging, you can execute your program via the Android program logwrapper. This will redirect stdout/stderr into the Android logging system (accessed via logcat). For example service akmd /system/bin/logwrapper /sbin/akmd For quicker turnaround when working on init itself, use: mm -j && m ramdisk-nodeps && m bootimage-nodeps && adb reboot bootloader && fastboot boot $ANDROID_PRODUCT_OUT/boot.img Alternatively, use the emulator: emulator -partition-size 1024 \ -verbose -show-kernel -no-window Launching init services without init is not recommended as init sets up a significant amount of environment (user, groups, security label, capabilities, etc) that is hard to replicate manually. If it is required to debug a service from its very start, the `sigstop` service option is added. This option will send SIGSTOP to a service immediately before calling exec. This gives a window where developers can attach a debugger, strace, etc before continuing the service with SIGCONT. This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties. Below is an example of dynamically debugging logd via the above: stop logd setprop ctl.sigstop_on logd start logd ps -e | grep logd > logd 4343 1 18156 1684 do_signal_stop 538280 T init gdbclient.py -p 4343 b main c c c > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427 Below is an example of doing the same but with strace stop logd setprop ctl.sigstop_on logd start logd ps -e | grep logd > logd 4343 1 18156 1684 do_signal_stop 538280 T init strace -p 4343 (From a different shell) kill -SIGCONT 4343 > strace runs
init/init.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,10 @@ struct ControlMessageFunction { static const std::map<std::string, ControlMessageFunction>& get_control_message_map() { // clang-format off static const std::map<std::string, ControlMessageFunction> control_message_functions = { {"sigstop_on", {ControlTarget::SERVICE, [](auto* service) { service->set_sigstop(true); return Success(); }}}, {"sigstop_off", {ControlTarget::SERVICE, [](auto* service) { service->set_sigstop(false); return Success(); }}}, {"start", {ControlTarget::SERVICE, DoControlStart}}, {"stop", {ControlTarget::SERVICE, DoControlStop}}, {"restart", {ControlTarget::SERVICE, DoControlRestart}}, Loading
init/service.cpp +12 −2 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ static void SetUpPidNamespace(const std::string& service_name) { } } static bool ExpandArgsAndExecv(const std::vector<std::string>& args) { static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) { std::vector<std::string> expanded_args; std::vector<char*> c_strings; Loading @@ -169,6 +169,10 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args) { } c_strings.push_back(nullptr); if (sigstop) { kill(getpid(), SIGSTOP); } return execv(c_strings[0], c_strings.data()) == 0; } Loading Loading @@ -582,6 +586,11 @@ Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) { return Success(); } Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) { sigstop_ = true; return Success(); } Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) { environment_vars_.emplace_back(args[1], args[2]); return Success(); Loading Loading @@ -704,6 +713,7 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const { {"seclabel", {1, 1, &Service::ParseSeclabel}}, {"setenv", {2, 2, &Service::ParseSetenv}}, {"shutdown", {1, 1, &Service::ParseShutdown}}, {"sigstop", {0, 0, &Service::ParseSigstop}}, {"socket", {3, 6, &Service::ParseSocket}}, {"user", {1, 1, &Service::ParseUser}}, {"writepid", {1, kMax, &Service::ParseWritepid}}, Loading Loading @@ -862,7 +872,7 @@ Result<Success> Service::Start() { // priority. Aborts on failure. SetProcessAttributes(); if (!ExpandArgsAndExecv(args_)) { if (!ExpandArgsAndExecv(args_, sigstop_)) { PLOG(ERROR) << "cannot execve('" << args_[0] << "')"; } Loading
init/service.h +4 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ class Service { bool is_override() const { return override_; } bool process_cgroup_empty() const { return process_cgroup_empty_; } unsigned long start_order() const { return start_order_; } void set_sigstop(bool value) { sigstop_ = value; } const std::vector<std::string>& args() const { return args_; } private: Loading Loading @@ -153,6 +154,7 @@ class Service { Result<Success> ParseSeclabel(const std::vector<std::string>& args); Result<Success> ParseSetenv(const std::vector<std::string>& args); Result<Success> ParseShutdown(const std::vector<std::string>& args); Result<Success> ParseSigstop(const std::vector<std::string>& args); Result<Success> ParseSocket(const std::vector<std::string>& args); Result<Success> ParseFile(const std::vector<std::string>& args); Result<Success> ParseUser(const std::vector<std::string>& args); Loading Loading @@ -213,6 +215,8 @@ class Service { std::vector<std::pair<int, rlimit>> rlimits_; bool sigstop_ = false; std::vector<std::string> args_; std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_; Loading