Merge "update shutdown sequence and use shutdown_timeout to cover all wait"
am: 59cebb6e6f

Change-Id: I4a09594aba83bc489c9e1735b27e4dbdf5256385
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 1559b6f..261a437 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -263,6 +263,8 @@
     return umountDone;
 }
 
+static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
+
 /* Try umounting all emulated file systems R/W block device cfile systems.
  * This will just try umount and give it up if it fails.
  * For fs like ext4, this is ok as file system will be marked as unclean shutdown
@@ -272,7 +274,8 @@
  *
  * return true when umount was successful. false when timed out.
  */
-static UmountStat TryUmountAndFsck(bool runFsck) {
+static UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
+    Timer t;
     std::vector<MountEntry> emulatedPartitions;
     std::vector<MountEntry> blockDevRwPartitions;
 
@@ -297,12 +300,20 @@
      * still happen while waiting for /data. If the current waiting is not good enough, give
      * up and leave it to e2fsck after reboot to fix it.
      */
-    /* TODO update max waiting time based on usage data */
-    if (!UmountPartitions(&blockDevRwPartitions, 100, 0)) {
-        /* Last resort, detach and hope it finish before shutdown. */
-        UmountPartitions(&blockDevRwPartitions, 1, MNT_DETACH);
-        stat = UMOUNT_STAT_TIMEOUT;
+    int remainingTimeMs = timeoutMs - t.duration_ms();
+    // each retry takes 100ms, and run at least once.
+    int retry = std::max(remainingTimeMs / 100, 1);
+    if (!UmountPartitions(&blockDevRwPartitions, retry, 0)) {
+        /* Last resort, kill all and try again */
+        LOG(WARNING) << "umount still failing, trying kill all";
+        KillAllProcesses();
+        DoSync();
+        if (!UmountPartitions(&blockDevRwPartitions, 1, 0)) {
+            stat = UMOUNT_STAT_TIMEOUT;
+        }
     }
+    // fsck part is excluded from timeout check. It only runs for user initiated shutdown
+    // and should not affect reboot time.
     if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
         for (auto& entry : blockDevRwPartitions) {
             DoFsck(entry);
@@ -312,8 +323,6 @@
     return stat;
 }
 
-static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
-
 static void __attribute__((noreturn)) DoThermalOff() {
     LOG(WARNING) << "Thermal system shutdown";
     DoSync();
@@ -334,11 +343,10 @@
     }
 
     std::string timeout = property_get("ro.build.shutdown_timeout");
-    unsigned int delay = 0;
-    if (!android::base::ParseUint(timeout, &delay)) {
-        delay = 3;  // force service termination by default
-    } else {
-        LOG(INFO) << "ro.build.shutdown_timeout set:" << delay;
+    /* TODO update default waiting time based on usage data */
+    unsigned int shutdownTimeout = 10;  // default value
+    if (android::base::ParseUint(timeout, &shutdownTimeout)) {
+        LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout;
     }
 
     static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
@@ -353,7 +361,7 @@
     }
     // optional shutdown step
     // 1. terminate all services except shutdown critical ones. wait for delay to finish
-    if (delay > 0) {
+    if (shutdownTimeout > 0) {
         LOG(INFO) << "terminating init services";
         // tombstoned can write to data when other services are killed. so finish it first.
         static const constexpr char* first_to_kill[] = {"tombstoned"};
@@ -368,7 +376,9 @@
         });
 
         int service_count = 0;
-        while (t.duration_s() < delay) {
+        // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
+        unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
+        while (t.duration_s() < terminationWaitTimeout) {
             ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
             service_count = 0;
@@ -409,12 +419,9 @@
     } else {
         LOG(INFO) << "vold not running, skipping vold shutdown";
     }
-    if (delay == 0) {  // no processes terminated. kill all instead.
-        KillAllProcesses();
-    }
     // 4. sync, try umount, and optionally run fsck for user shutdown
     DoSync();
-    UmountStat stat = TryUmountAndFsck(runFsck);
+    UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
     LogShutdownTime(stat, &t);
     // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
     RebootSystem(cmd, rebootTarget);