init: add sigstop option for debugging services from their start

Test: the examples in README.md
Change-Id: Idb528ea4017f8f4ce62911928c040f4bc558d196
diff --git a/init/README.md b/init/README.md
index 59ddd77..b14521c 100644
--- a/init/README.md
+++ b/init/README.md
@@ -282,6 +282,10 @@
   "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
@@ -708,23 +712,39 @@
 
 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).
+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.
 
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
+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.
 
-For quicker turnaround when working on init itself, use:
+This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
 
-    mm -j &&
-    m ramdisk-nodeps &&
-    m bootimage-nodeps &&
-    adb reboot bootloader &&
-    fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+Below is an example of dynamically debugging logd via the above:
 
-Alternatively, use the emulator:
+    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
 
-    emulator -partition-size 1024 \
-        -verbose -show-kernel -no-window
+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
diff --git a/init/init.cpp b/init/init.cpp
index 2f3b28a..0e019b0 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -238,6 +238,10 @@
 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}},
diff --git a/init/service.cpp b/init/service.cpp
index 694e5e7..0227161 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,7 +155,7 @@
     }
 }
 
-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;
 
@@ -169,6 +169,10 @@
     }
     c_strings.push_back(nullptr);
 
+    if (sigstop) {
+        kill(getpid(), SIGSTOP);
+    }
+
     return execv(c_strings[0], c_strings.data()) == 0;
 }
 
@@ -578,6 +582,11 @@
     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();
@@ -700,6 +709,7 @@
         {"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}},
@@ -858,7 +868,7 @@
         // priority. Aborts on failure.
         SetProcessAttributes();
 
-        if (!ExpandArgsAndExecv(args_)) {
+        if (!ExpandArgsAndExecv(args_, sigstop_)) {
             PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
         }
 
diff --git a/init/service.h b/init/service.h
index d46a413..9b916c8 100644
--- a/init/service.h
+++ b/init/service.h
@@ -114,6 +114,7 @@
     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:
@@ -149,6 +150,7 @@
     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);
@@ -209,6 +211,8 @@
 
     std::vector<std::pair<int, rlimit>> rlimits_;
 
+    bool sigstop_ = false;
+
     std::vector<std::string> args_;
 };