Merge "Recognize IPv6 addresses for "adb connect"."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 4251f88..1727225 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -175,7 +175,7 @@
     for (const auto& elem : elements) {
         const auto& flag = trace_flags.find(elem);
         if (flag == trace_flags.end()) {
-            D("Unknown trace flag: %s", flag->first.c_str());
+            D("Unknown trace flag: %s\n", flag->first.c_str());
             continue;
         }
 
diff --git a/adb/adb.h b/adb/adb.h
index 1be83d7..31fe3a5 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -365,7 +365,9 @@
 
 extern const char *adb_device_banner;
 extern int HOST;
+#if !ADB_HOST
 extern int SHELL_EXIT_NOTIFY_FD;
+#endif // !ADB_HOST
 
 #define CHUNK_SIZE (64*1024)
 
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 8e7d38b..884d5be 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -212,7 +212,7 @@
 
     ret = snprintf(msg, sizeof(msg), "PK%s", key);
     if (ret >= (signed)sizeof(msg)) {
-        D("Key too long. ret=%d", ret);
+        D("Key too long. ret=%d\n", ret);
         return;
     }
     D("Sending '%s'\n", msg);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index e878f8b..8085c1a 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -183,7 +183,7 @@
 
 #if defined(OPENSSL_IS_BORINGSSL)
     if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
-        D("Public key too large to base64 encode");
+        D("Public key too large to base64 encode\n");
         goto out;
     }
 #else
@@ -194,7 +194,7 @@
 
     encoded = new uint8_t[encoded_length];
     if (encoded == nullptr) {
-        D("Allocation failure");
+        D("Allocation failure\n");
         goto out;
     }
 
@@ -203,7 +203,7 @@
 
     if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
         fwrite(info, strlen(info), 1, outfile) != 1) {
-        D("Write error while writing public key");
+        D("Write error while writing public key\n");
         goto out;
     }
 
@@ -323,7 +323,7 @@
 
     if (stat(android_dir, &buf)) {
         if (adb_mkdir(android_dir, 0750) < 0) {
-            D("Cannot mkdir '%s'", android_dir);
+            D("Cannot mkdir '%s'\n", android_dir);
             return -1;
         }
     }
@@ -339,7 +339,7 @@
 
     ret = get_user_keyfilepath(path, sizeof(path));
     if (ret < 0 || ret >= (signed)sizeof(path)) {
-        D("Error getting user key filename");
+        D("Error getting user key filename\n");
         return 0;
     }
 
@@ -414,7 +414,7 @@
     char path[PATH_MAX];
     int ret = get_user_keyfilepath(path, sizeof(path) - 4);
     if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
-        D("Error getting user key filename");
+        D("Error getting user key filename\n");
         return 0;
     }
     strcat(path, ".pub");
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 9a1b761..75e888d 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -243,7 +243,7 @@
 
     fd = _adb_connect(service, error);
     if (fd == -1) {
-        D("_adb_connect error: %s", error->c_str());
+        D("_adb_connect error: %s\n", error->c_str());
     } else if(fd == -2) {
         fprintf(stderr,"** daemon still not running\n");
     }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 0c43c5e..5cd4988 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -42,7 +42,9 @@
 // This socket is used when a subproc shell service exists.
 // It wakes up the fdevent_loop() and cause the correct handling
 // of the shell's pseudo-tty master. I.e. force close it.
+#if !ADB_HOST
 int SHELL_EXIT_NOTIFY_FD = -1;
+#endif // !ADB_HOST
 
 static void fatal(const char *fn, const char *fmt, ...)
 {
@@ -81,7 +83,6 @@
 static void fdevent_plist_enqueue(fdevent *node);
 static void fdevent_plist_remove(fdevent *node);
 static fdevent *fdevent_plist_dequeue(void);
-static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
 
 static fdevent list_pending = {
     .next = &list_pending,
@@ -510,6 +511,7 @@
     fde->func(fde->fd, events, fde->arg);
 }
 
+#if !ADB_HOST
 static void fdevent_subproc_event_func(int fd, unsigned ev,
                                        void* /* userdata */)
 {
@@ -569,6 +571,24 @@
     }
 }
 
+void fdevent_subproc_setup()
+{
+    int s[2];
+
+    if(adb_socketpair(s)) {
+        FATAL("cannot create shell-exit socket-pair\n");
+    }
+    D("socketpair: (%d,%d)\n", s[0], s[1]);
+
+    SHELL_EXIT_NOTIFY_FD = s[0];
+    fdevent *fde;
+    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
+    if(!fde)
+      FATAL("cannot create fdevent for shell-exit handler\n");
+    fdevent_add(fde, FDE_READ);
+}
+#endif // !ADB_HOST
+
 fdevent *fdevent_create(int fd, fd_func func, void *arg)
 {
     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
@@ -661,27 +681,12 @@
         fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
 }
 
-void fdevent_subproc_setup()
-{
-    int s[2];
-
-    if(adb_socketpair(s)) {
-        FATAL("cannot create shell-exit socket-pair\n");
-    }
-    D("socketpair: (%d,%d)", s[0], s[1]);
-
-    SHELL_EXIT_NOTIFY_FD = s[0];
-    fdevent *fde;
-    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
-    if(!fde)
-      FATAL("cannot create fdevent for shell-exit handler\n");
-    fdevent_add(fde, FDE_READ);
-}
-
 void fdevent_loop()
 {
     fdevent *fde;
+#if !ADB_HOST
     fdevent_subproc_setup();
+#endif // !ADB_HOST
 
     for(;;) {
         D("--- ---- waiting for events\n");
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index c0f7ec2..23af6c9 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -435,7 +435,7 @@
               __FUNCTION__, strerror(errno));
             return -1;
         }
-        D("socketpair: (%d,%d)", fds[0], fds[1]);
+        D("socketpair: (%d,%d)\n", fds[0], fds[1]);
 
         proc->out_fds[ proc->out_count ] = fds[1];
         if (++proc->out_count == 1)
diff --git a/adb/services.cpp b/adb/services.cpp
index 678d57b..b9c532a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -206,7 +206,7 @@
         printf("cannot create service socket pair\n");
         return -1;
     }
-    D("socketpair: (%d,%d)", s[0], s[1]);
+    D("socketpair: (%d,%d)\n", s[0], s[1]);
 
     stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
     if (sti == nullptr) {
@@ -318,7 +318,7 @@
         printf("[ cannot create socket pair - %s ]\n", strerror(errno));
         return -1;
     }
-    D("socketpair: (%d,%d)", sv[0], sv[1]);
+    D("socketpair: (%d,%d)\n", sv[0], sv[1]);
 
     *pid = fork();
     if (*pid < 0) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index b7c16d9..5efdab5 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -276,6 +276,7 @@
 #include "fdevent.h"
 #include <cutils/sockets.h>
 #include <cutils/misc.h>
+#include <cutils/threads.h>
 #include <signal.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
@@ -544,7 +545,7 @@
 
 static __inline__ unsigned long adb_thread_id()
 {
-    return (unsigned long)pthread_self();
+    return (unsigned long)gettid();
 }
 
 #endif /* !_WIN32 */
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 50c99f1..bdc6027 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -361,9 +361,10 @@
                                0, NULL );
 
     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        const DWORD err = GetLastError();
         _fh_close(f);
-        D( "adb_open: could not open '%s':", path );
-        switch (GetLastError()) {
+        D( "adb_open: could not open '%s': ", path );
+        switch (err) {
             case ERROR_FILE_NOT_FOUND:
                 D( "file not found\n" );
                 errno = ENOENT;
@@ -375,7 +376,7 @@
                 return -1;
 
             default:
-                D( "unknown error\n" );
+                D( "unknown error: %ld\n", err );
                 errno = ENOENT;
                 return -1;
         }
@@ -402,9 +403,10 @@
                                NULL );
 
     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        const DWORD err = GetLastError();
         _fh_close(f);
-        D( "adb_creat: could not open '%s':", path );
-        switch (GetLastError()) {
+        D( "adb_creat: could not open '%s': ", path );
+        switch (err) {
             case ERROR_FILE_NOT_FOUND:
                 D( "file not found\n" );
                 errno = ENOENT;
@@ -416,7 +418,7 @@
                 return -1;
 
             default:
-                D( "unknown error\n" );
+                D( "unknown error: %ld\n", err );
                 errno = ENOENT;
                 return -1;
         }
@@ -781,8 +783,9 @@
 
     fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
     if (fh->fh_socket == INVALID_SOCKET) {
+        const DWORD err = WSAGetLastError();
         _fh_close( fh );
-        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
+        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err );
         return -1;
     }
 
@@ -1546,7 +1549,7 @@
     threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
                                         sizeof(WaitForAllParam));
     if (threads == NULL) {
-        D("Unable to allocate thread array for %d handles.", handles_count);
+        D("Unable to allocate thread array for %d handles.\n", handles_count);
         return (int)WAIT_FAILED;
     }
 
@@ -1554,7 +1557,7 @@
      * reset" event that will remain set once it was set. */
     main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (main_event == NULL) {
-        D("Unable to create main event. Error: %d", (int)GetLastError());
+        D("Unable to create main event. Error: %ld\n", GetLastError());
         free(threads);
         return (int)WAIT_FAILED;
     }
@@ -1587,7 +1590,7 @@
                                                        &threads[chunk], 0, NULL);
         if (threads[chunk].thread == NULL) {
             /* Unable to create a waiter thread. Collapse. */
-            D("Unable to create a waiting thread %d of %d. errno=%d",
+            D("Unable to create a waiting thread %d of %d. errno=%d\n",
               chunk, chunks, errno);
             chunks = chunk;
             SetEvent(main_event);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 274449b..87ca5ac 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -283,7 +283,7 @@
     p->msg.magic = A_SYNC ^ 0xffffffff;
     if(write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
-        D("%s: failed to write SYNC apacket to transport", t->serial);
+        D("%s: failed to write SYNC apacket to transport\n", t->serial);
     }
 
 oops:
@@ -579,7 +579,7 @@
             fatal_errno("cannot open transport socketpair");
         }
 
-        D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
+        D("transport: %s socketpair: (%d,%d) starting\n", t->serial, s[0], s[1]);
 
         t->transport_socket = s[0];
         t->fd = s[1];
@@ -617,7 +617,7 @@
     if(adb_socketpair(s)){
         fatal_errno("cannot open transport registration socketpair");
     }
-    D("socketpair: (%d,%d)", s[0], s[1]);
+    D("socketpair: (%d,%d)\n", s[0], s[1]);
 
     transport_registration_send = s[0];
     transport_registration_recv = s[1];
@@ -789,9 +789,10 @@
         if (result->connection_state == kCsUnauthorized) {
             *error_out = "device unauthorized.\n";
             char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
-            *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+            *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
             *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
-            *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+            *error_out += "\n";
+            *error_out += "Try 'adb kill-server' if that seems wrong.\n";
             *error_out += "Otherwise check for a confirmation dialog on your device.";
             result = NULL;
         }
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index d34c454..cfd95dd 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -444,11 +444,11 @@
 
     err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
     if (err < 0)
-        D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in, errno);
+        D("[ kick: source (fd=%d) clear halt failed (%d) ]\n", h->bulk_in, errno);
 
     err = ioctl(h->bulk_out, FUNCTIONFS_CLEAR_HALT);
     if (err < 0)
-        D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
+        D("[ kick: sink (fd=%d) clear halt failed (%d) ]\n", h->bulk_out, errno);
 
     adb_mutex_lock(&h->lock);
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 42f25c7..f467f81 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -162,10 +162,10 @@
     } else if (!strcmp(fs_type, "f2fs")) {
             char *f2fs_fsck_argv[] = {
                     F2FS_FSCK_BIN,
-                    "-f",
+                    "-a",
                     blk_device
             };
-        INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device);
+        INFO("Running %s -a %s\n", F2FS_FSCK_BIN, blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
                                       &status, true, LOG_KLOG | LOG_FILE,
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
index 85e1b7e..a3861a0 100644
--- a/include/cutils/android_reboot.h
+++ b/include/cutils/android_reboot.h
@@ -17,6 +17,8 @@
 #ifndef __CUTILS_ANDROID_REBOOT_H__
 #define __CUTILS_ANDROID_REBOOT_H__
 
+#include <mntent.h>
+
 __BEGIN_DECLS
 
 /* Commands */
@@ -28,6 +30,9 @@
 #define ANDROID_RB_PROPERTY "sys.powerctl"
 
 int android_reboot(int cmd, int flags, const char *arg);
+int android_reboot_with_callback(
+    int cmd, int flags, const char *arg,
+    void (*cb_on_remount)(const struct mntent*));
 
 __END_DECLS
 
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 02fe2b5..0c071ca 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -77,6 +77,7 @@
 #define AID_SDCARD_ALL    1035  /* access all users external storage */
 #define AID_LOGD          1036  /* log daemon */
 #define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
+#define AID_DBUS          1038  /* dbus-daemon IPC broker process */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -168,6 +169,7 @@
     { "sdcard_all",    AID_SDCARD_ALL, },
     { "logd",          AID_LOGD, },
     { "shared_relro",  AID_SHARED_RELRO, },
+    { "dbus",          AID_DBUS, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/init/builtins.cpp b/init/builtins.cpp
index ca31c50..d5d3faf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -16,7 +16,9 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <mntent.h>
 #include <net/if.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +40,7 @@
 #include <base/stringprintf.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
+#include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
 
 #include "init.h"
@@ -49,6 +52,8 @@
 #include "log.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
+#define UNMOUNT_CHECK_MS 5000
+#define UNMOUNT_CHECK_TIMES 10
 
 int add_environment(const char *name, const char *value);
 
@@ -109,6 +114,67 @@
     }
 }
 
+static void unmount_and_fsck(const struct mntent *entry)
+{
+    if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
+        return;
+
+    /* First, lazily unmount the directory. This unmount request finishes when
+     * all processes that open a file or directory in |entry->mnt_dir| exit.
+     */
+    TEMP_FAILURE_RETRY(umount2(entry->mnt_dir, MNT_DETACH));
+
+    /* Next, kill all processes except init, kthreadd, and kthreadd's
+     * children to finish the lazy unmount. Killing all processes here is okay
+     * because this callback function is only called right before reboot().
+     * It might be cleaner to selectively kill processes that actually use
+     * |entry->mnt_dir| rather than killing all, probably by reusing a function
+     * like killProcessesWithOpenFiles() in vold/, but the selinux policy does
+     * not allow init to scan /proc/<pid> files which the utility function
+     * heavily relies on. The policy does not allow the process to execute
+     * killall/pkill binaries either. Note that some processes might
+     * automatically restart after kill(), but that is not really a problem
+     * because |entry->mnt_dir| is no longer visible to such new processes.
+     */
+    service_for_each(service_stop);
+    TEMP_FAILURE_RETRY(kill(-1, SIGKILL));
+
+    int count = 0;
+    while (count++ < UNMOUNT_CHECK_TIMES) {
+        int fd = TEMP_FAILURE_RETRY(open(entry->mnt_fsname, O_RDONLY | O_EXCL));
+        if (fd >= 0) {
+            /* |entry->mnt_dir| has sucessfully been unmounted. */
+            close(fd);
+            break;
+        } else if (errno == EBUSY) {
+            /* Some processes using |entry->mnt_dir| are still alive. Wait for a
+             * while then retry.
+             */
+            TEMP_FAILURE_RETRY(
+                usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES));
+            continue;
+        } else {
+            /* Cannot open the device. Give up. */
+            return;
+        }
+    }
+
+    int st;
+    if (!strcmp(entry->mnt_type, "f2fs")) {
+        const char *f2fs_argv[] = {
+            "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
+        };
+        android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
+                                &st, true, LOG_KLOG, true, NULL);
+    } else if (!strcmp(entry->mnt_type, "ext4")) {
+        const char *ext4_argv[] = {
+            "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
+        };
+        android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
+                                &st, true, LOG_KLOG, true, NULL);
+    }
+}
+
 int do_class_start(int nargs, char **args)
 {
         /* Starting a class does not start services
@@ -559,6 +625,7 @@
     int len = 0;
     int cmd = 0;
     const char *reboot_target;
+    void (*callback_on_ro_remount)(const struct mntent*) = NULL;
 
     res = expand_props(command, args[1], sizeof(command));
     if (res) {
@@ -569,6 +636,7 @@
     if (strncmp(command, "shutdown", 8) == 0) {
         cmd = ANDROID_RB_POWEROFF;
         len = 8;
+        callback_on_ro_remount = unmount_and_fsck;
     } else if (strncmp(command, "reboot", 6) == 0) {
         cmd = ANDROID_RB_RESTART2;
         len = 6;
@@ -586,7 +654,8 @@
         return -EINVAL;
     }
 
-    return android_reboot(cmd, 0, reboot_target);
+    return android_reboot_with_callback(cmd, 0, reboot_target,
+                                        callback_on_ro_remount);
 }
 
 int do_trigger(int nargs, char **args)
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 6ae23c1..af7e189 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -14,43 +14,108 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
-#include <sys/reboot.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <mntent.h>
+#include <stdbool.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <sys/cdefs.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/list.h>
 
-#define UNUSED __attribute__((unused))
+#define TAG "android_reboot"
+#define READONLY_CHECK_MS 5000
+#define READONLY_CHECK_TIMES 50
 
-/* Check to see if /proc/mounts contains any writeable filesystems
- * backed by a block device.
- * Return true if none found, else return false.
+typedef struct {
+    struct listnode list;
+    struct mntent entry;
+} mntent_list;
+
+static bool has_mount_option(const char* opts, const char* opt_to_find)
+{
+  bool ret = false;
+  char* copy = NULL;
+  char* opt;
+  char* rem;
+
+  while ((opt = strtok_r(copy ? NULL : (copy = strdup(opts)), ",", &rem))) {
+      if (!strcmp(opt, opt_to_find)) {
+          ret = true;
+          break;
+      }
+  }
+
+  free(copy);
+  return ret;
+}
+
+static bool is_block_device(const char* fsname)
+{
+    return !strncmp(fsname, "/dev/block", 10);
+}
+
+/* Find all read+write block devices in /proc/mounts and add them to
+ * |rw_entries|.
  */
-static int remount_ro_done(void)
+static void find_rw(struct listnode* rw_entries)
 {
     FILE* fp;
     struct mntent* mentry;
-    int found_rw_fs = 0;
 
     if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
-        /* If we can't read /proc/mounts, just give up. */
-        return 1;
+        KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+        return;
     }
     while ((mentry = getmntent(fp)) != NULL) {
-        if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) {
-            found_rw_fs = 1;
-            break;
+        if (is_block_device(mentry->mnt_fsname) &&
+            has_mount_option(mentry->mnt_opts, "rw")) {
+            mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
+            item->entry = *mentry;
+            item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
+            item->entry.mnt_dir = strdup(mentry->mnt_dir);
+            item->entry.mnt_type = strdup(mentry->mnt_type);
+            item->entry.mnt_opts = strdup(mentry->mnt_opts);
+            list_add_tail(rw_entries, &item->list);
         }
     }
     endmntent(fp);
+}
 
-    return !found_rw_fs;
+static void free_entries(struct listnode* entries)
+{
+    struct listnode* node;
+    struct listnode* n;
+    list_for_each_safe(node, n, entries) {
+        mntent_list* item = node_to_item(node, mntent_list, list);
+        free(item->entry.mnt_fsname);
+        free(item->entry.mnt_dir);
+        free(item->entry.mnt_type);
+        free(item->entry.mnt_opts);
+        free(item);
+    }
+}
+
+static mntent_list* find_item(struct listnode* rw_entries, const char* fsname_to_find)
+{
+    struct listnode* node;
+    list_for_each(node, rw_entries) {
+        mntent_list* item = node_to_item(node, mntent_list, list);
+        if (!strcmp(item->entry.mnt_fsname, fsname_to_find)) {
+            return item;
+        }
+    }
+    return NULL;
 }
 
 /* Remounting filesystems read-only is difficult when there are files
@@ -64,38 +129,92 @@
  * repeatedly until there are no more writable filesystems mounted on
  * block devices.
  */
-static void remount_ro(void)
+static void remount_ro(void (*cb_on_remount)(const struct mntent*))
 {
-    int fd, cnt = 0;
+    int fd, cnt;
+    FILE* fp;
+    struct mntent* mentry;
+    struct listnode* node;
+
+    list_declare(rw_entries);
+    list_declare(ro_entries);
+
+    sync();
+    find_rw(&rw_entries);
 
     /* Trigger the remount of the filesystems as read-only,
      * which also marks them clean.
      */
-    fd = open("/proc/sysrq-trigger", O_WRONLY);
+    fd = TEMP_FAILURE_RETRY(open("/proc/sysrq-trigger", O_WRONLY));
     if (fd < 0) {
-        return;
+        KLOG_WARNING(TAG, "Failed to open sysrq-trigger.\n");
+        /* TODO: Try to remount each rw parition manually in readonly mode.
+         * This may succeed if no process is using the partition.
+         */
+        goto out;
     }
-    write(fd, "u", 1);
+    if (TEMP_FAILURE_RETRY(write(fd, "u", 1)) != 1) {
+        close(fd);
+        KLOG_WARNING(TAG, "Failed to write to sysrq-trigger.\n");
+        /* TODO: The same. Manually remount the paritions. */
+        goto out;
+    }
     close(fd);
 
-
     /* Now poll /proc/mounts till it's done */
-    while (!remount_ro_done() && (cnt < 50)) {
-        usleep(100000);
+    cnt = 0;
+    while (cnt < READONLY_CHECK_TIMES) {
+        if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
+            /* If we can't read /proc/mounts, just give up. */
+            KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+            goto out;
+        }
+        while ((mentry = getmntent(fp)) != NULL) {
+            if (!is_block_device(mentry->mnt_fsname) ||
+                !has_mount_option(mentry->mnt_opts, "ro")) {
+                continue;
+            }
+            mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);
+            if (item) {
+                /* |item| has now been ro remounted. */
+                list_remove(&item->list);
+                list_add_tail(&ro_entries, &item->list);
+            }
+        }
+        endmntent(fp);
+        if (list_empty(&rw_entries)) {
+            /* All rw block devices are now readonly. */
+            break;
+        }
+        TEMP_FAILURE_RETRY(
+            usleep(READONLY_CHECK_MS * 1000 / READONLY_CHECK_TIMES));
         cnt++;
     }
 
-    return;
+    list_for_each(node, &rw_entries) {
+        mntent_list* item = node_to_item(node, mntent_list, list);
+        KLOG_WARNING(TAG, "Failed to remount %s in readonly mode.\n",
+                     item->entry.mnt_fsname);
+    }
+
+    if (cb_on_remount) {
+        list_for_each(node, &ro_entries) {
+            mntent_list* item = node_to_item(node, mntent_list, list);
+            cb_on_remount(&item->entry);
+        }
+    }
+
+out:
+    free_entries(&rw_entries);
+    free_entries(&ro_entries);
 }
 
-
-int android_reboot(int cmd, int flags UNUSED, const char *arg)
+int android_reboot_with_callback(
+    int cmd, int flags __unused, const char *arg,
+    void (*cb_on_remount)(const struct mntent*))
 {
     int ret;
-
-    sync();
-    remount_ro();
-
+    remount_ro(cb_on_remount);
     switch (cmd) {
         case ANDROID_RB_RESTART:
             ret = reboot(RB_AUTOBOOT);
@@ -117,3 +236,7 @@
     return ret;
 }
 
+int android_reboot(int cmd, int flags, const char *arg)
+{
+    return android_reboot_with_callback(cmd, flags, arg, NULL);
+}
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3a6276e..777dafe 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -355,7 +355,8 @@
         }
 
         if (poll_fds[0].revents & POLLIN) {
-            sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
+            sz = TEMP_FAILURE_RETRY(
+                read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
 
             sz += b;
             // Log one line at a time
@@ -490,7 +491,7 @@
     }
 
     /* Use ptty instead of socketpair so that STDOUT is not buffered */
-    parent_ptty = open("/dev/ptmx", O_RDWR);
+    parent_ptty = TEMP_FAILURE_RETRY(open("/dev/ptmx", O_RDWR));
     if (parent_ptty < 0) {
         ERROR("Cannot create parent ptty\n");
         rc = -1;
@@ -505,7 +506,7 @@
         goto err_ptty;
     }
 
-    child_ptty = open(child_devname, O_RDWR);
+    child_ptty = TEMP_FAILURE_RETRY(open(child_devname, O_RDWR));
     if (child_ptty < 0) {
         ERROR("Cannot open child_ptty\n");
         rc = -1;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index de10535..d6dad2d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,7 +26,7 @@
 #
 # create some directories (some are mount points)
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data oem acct config storage mnt root)
+    sbin dev proc sys system data oem acct cache config storage mnt root)
 
 include $(BUILD_SYSTEM)/base_rules.mk