Merge "init: Support custom shutdown actions" into oc-dr1-dev
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 0af6159..4441ad0 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -22,7 +22,6 @@
     local_include_dirs: ["include/"],
     cppflags: ["-Werror"],
     static_libs: [
-        "liblogwrap",
         "libfec",
         "libfec_rs",
         "libbase",
@@ -33,6 +32,9 @@
         "libselinux",
         "libavb",
     ],
+    whole_static_libs: [
+        "liblogwrap",
+    ],
 }
 
 cc_library_static {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index f3ca724..9249343 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -21,6 +21,7 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_MODULE:= fs_mgr
 LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index a03d92c..75feee7 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -24,25 +24,21 @@
 #include <cutils/partition_utils.h>
 #include <sys/mount.h>
 
-#include <ext4_utils/ext4_utils.h>
 #include <ext4_utils/ext4.h>
-#include <ext4_utils/make_ext4fs.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
+#include <ext4_utils/ext4_utils.h>
+#include <logwrap/logwrap.h>
 #include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
 
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
-extern "C" {
-extern struct fs_info info;     /* magic global from ext4_utils */
-extern void reset_ext4fs_info();
-}
-
 static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
 {
     uint64_t dev_sz;
     int fd, rc = 0;
+    int status;
 
     if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
         PERROR << "Cannot open block device";
@@ -55,30 +51,36 @@
         return -1;
     }
 
-    struct selabel_handle *sehandle = selinux_android_file_context_handle();
-    if (!sehandle) {
-        /* libselinux logs specific error */
-        LERROR << "Cannot initialize android file_contexts";
-        close(fd);
-        return -1;
-    }
-
-    /* Format the partition using the calculated length */
-    reset_ext4fs_info();
-    info.len = (off64_t)dev_sz;
-    if (crypt_footer) {
-        info.len -= CRYPT_FOOTER_OFFSET;
-    }
-
-    /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
-    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL);
-    if (rc) {
-        LERROR << "make_ext4fs returned " << rc;
-    }
     close(fd);
 
-    if (sehandle) {
-        selabel_close(sehandle);
+    /* Format the partition using the calculated length */
+    if (crypt_footer) {
+        dev_sz -= CRYPT_FOOTER_OFFSET;
+    }
+
+    std::string size_str = std::to_string(dev_sz / 4096);
+    const char* const mke2fs_args[] = {
+        "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr};
+
+    rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), &status,
+                                 true, LOG_KLOG, true, nullptr, nullptr, 0);
+    if (rc) {
+        LERROR << "mke2fs returned " << rc;
+        return rc;
+    }
+
+    const char* const e2fsdroid_args[] = {
+        "/system/bin/e2fsdroid",
+        "-e",
+        "-a",
+        fs_mnt_point,
+        fs_blkdev,
+        nullptr};
+
+    rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args),
+                                 &status, true, LOG_KLOG, true, nullptr, nullptr, 0);
+    if (rc) {
+        LERROR << "e2fsdroid returned " << rc;
     }
 
     return rc;
@@ -86,44 +88,11 @@
 
 static int format_f2fs(char *fs_blkdev)
 {
-    char * args[5];
-    int pid;
-    int rc = 0;
+    int status;
+    const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
 
-    args[0] = (char *)"/system/bin/make_f2fs";
-    args[1] = (char *)"-f";
-    args[2] = (char *)"-O encrypt";
-    args[3] = fs_blkdev;
-    args[4] = (char *)0;
-
-    pid = fork();
-    if (pid < 0) {
-       return pid;
-    }
-    if (!pid) {
-        /* This doesn't return */
-        execv(args[0], args);
-        exit(1);
-    }
-    for(;;) {
-        pid_t p = waitpid(pid, &rc, 0);
-        if (p != pid) {
-            LERROR << "Error waiting for child process - " << p;
-            rc = -1;
-            break;
-        }
-        if (WIFEXITED(rc)) {
-            rc = WEXITSTATUS(rc);
-            LINFO << args[0] << " done, status " << rc;
-            if (rc) {
-                rc = -1;
-            }
-            break;
-        }
-        LERROR << "Still waiting for " << args[0] << "...";
-    }
-
-    return rc;
+    return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), &status, true,
+                                   LOG_KLOG, true, nullptr, nullptr, 0);
 }
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
diff --git a/init/Android.bp b/init/Android.bp
index af1e9d3..5d6d979 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -95,6 +95,10 @@
 
     name: "init",
     defaults: ["init_defaults"],
+    required: [
+        "e2fsdroid",
+        "mke2fs",
+    ],
     static_executable: true,
     srcs: [
         "bootchart.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 866ea34..bf75f5a 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -85,6 +85,10 @@
     libavb \
     libkeyutils \
 
+LOCAL_REQUIRED_MODULES := \
+    e2fsdroid \
+    mke2fs \
+
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
diff --git a/init/README.md b/init/README.md
index 72b6c6b..422fdad 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,14 @@
 > Sets the child's /proc/self/oom\_score\_adj to the specified value,
   which must range from -1000 to 1000.
 
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+  the service is killed during shutdown process by using SIGTERM and SIGKILL.
+  The service with shutdown_behavior of "critical" is not killed during shutdown
+  until shutdown times out. When shutdown times out, even services tagged with
+  "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+  is not running when shut down starts, it will be started.
+
 
 Triggers
 --------
diff --git a/init/init.cpp b/init/init.cpp
index 403269f..9652efa 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -923,8 +923,8 @@
     selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
     selinux_android_restorecon("/dev/device-mapper", 0);
 
-    selinux_android_restorecon("/sbin/mke2fs", 0);
-    selinux_android_restorecon("/sbin/e2fsdroid", 0);
+    selinux_android_restorecon("/sbin/mke2fs_static", 0);
+    selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
 }
 
 // Set the UDC controller for the ConfigFS USB Gadgets.
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 3781a22..d72c3ac4 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -168,10 +168,13 @@
         };
         uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
         if (!found) {
+            LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+            Timer t;
             uevent_listener_.Poll(dm_callback, 10s);
+            LOG(INFO) << "Wait for device-mapper returned after " << t;
         }
         if (!found) {
-            LOG(ERROR) << "device-mapper device not found";
+            LOG(ERROR) << "device-mapper device not found after polling timeout";
             return false;
         }
     }
@@ -182,11 +185,16 @@
     // UeventCallback() will remove found partitions from required_devices_partition_names_.
     // So if it isn't empty here, it means some partitions are not found.
     if (!required_devices_partition_names_.empty()) {
+        LOG(INFO) << __PRETTY_FUNCTION__
+                  << ": partition(s) not found in /sys, waiting for their uevent(s): "
+                  << android::base::Join(required_devices_partition_names_, ", ");
+        Timer t;
         uevent_listener_.Poll(uevent_callback, 10s);
+        LOG(INFO) << "Wait for partitions returned after " << t;
     }
 
     if (!required_devices_partition_names_.empty()) {
-        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
+        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
                    << android::base::Join(required_devices_partition_names_, ", ");
         return false;
     }
@@ -238,10 +246,13 @@
 
     uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
     if (!found) {
+        LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+        Timer t;
         uevent_listener_.Poll(verity_callback, 10s);
+        LOG(INFO) << "wait for dm-verity device returned after " << t;
     }
     if (!found) {
-        LOG(ERROR) << "dm-verity device not found";
+        LOG(ERROR) << "dm-verity device not found after polling timeout";
         return false;
     }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 99b4922..e8f6cc5 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -332,13 +332,15 @@
     // keep debugging tools until non critical ones are all gone.
     const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
-    const std::set<std::string> to_starts{"watchdogd", "vold", "ueventd"};
+    const std::set<std::string> to_starts{"watchdogd"};
     ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
         if (kill_after_apps.count(s->name())) {
             s->SetShutdownCritical();
         } else if (to_starts.count(s->name())) {
             s->Start();
             s->SetShutdownCritical();
+        } else if (s->IsShutdownCritical()) {
+            s->Start();  // start shutdown critical service if not started
         }
     });
 
diff --git a/init/service.cpp b/init/service.cpp
index 20ca9fe..09ebc31 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -487,6 +487,14 @@
     return true;
 }
 
+bool Service::ParseShutdown(const std::vector<std::string>& args, std::string* err) {
+    if (args[1] == "critical") {
+        flags_ |= SVC_SHUTDOWN_CRITICAL;
+        return true;
+    }
+    return false;
+}
+
 template <typename T>
 bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
@@ -591,6 +599,7 @@
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
+        {"shutdown",    {1,     1,    &Service::ParseShutdown}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
         {"file",        {2,     2,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
diff --git a/init/service.h b/init/service.h
index 4505131..25d1975 100644
--- a/init/service.h
+++ b/init/service.h
@@ -138,6 +138,7 @@
     bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
     bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
     bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+    bool ParseShutdown(const std::vector<std::string>& args, std::string* err);
     bool ParseSocket(const std::vector<std::string>& args, std::string* err);
     bool ParseFile(const std::vector<std::string>& args, std::string* err);
     bool ParseUser(const std::vector<std::string>& args, std::string* err);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8380c52..8f58a95 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -688,6 +688,7 @@
     class core
     critical
     seclabel u:r:ueventd:s0
+    shutdown critical
 
 service healthd /system/bin/healthd
     class core