Merge "debuggerd: Dump list of open files on process crash."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 8b6b2b5..3cd50ba 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -30,7 +30,9 @@
 #include <sys/time.h>
 #include <time.h>
 
+#include <chrono>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/errors.h>
@@ -51,6 +53,7 @@
 #include <sys/capability.h>
 #include <sys/mount.h>
 #include <android-base/properties.h>
+using namespace std::chrono_literals;
 #endif
 
 std::string adb_version() {
@@ -375,7 +378,7 @@
                     adbd_auth_verified(t);
                     t->failed_auth_attempts = 0;
                 } else {
-                    if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
+                    if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
                     send_auth_request(t);
                 }
                 break;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 919e1c1..0b1ba32 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/stringprintf.h>
@@ -38,6 +39,7 @@
 #include "adb_io.h"
 #include "adb_utils.h"
 #include "socket_spec.h"
+#include "sysdeps/chrono.h"
 
 static TransportType __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
@@ -188,8 +190,8 @@
         } else {
             fprintf(stdout,"* daemon started successfully *\n");
         }
-        /* give the server some time to start properly and detect devices */
-        adb_sleep_ms(3000);
+        // Give the server some time to start properly and detect devices.
+        std::this_thread::sleep_for(3s);
         // fall through to _adb_connect
     } else {
         // If a server is already running, check its version matches.
@@ -234,7 +236,7 @@
             }
 
             /* XXX can we better detect its death? */
-            adb_sleep_ms(2000);
+            std::this_thread::sleep_for(2s);
             goto start_server;
         }
     }
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index ae16834..ca8729e 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -20,6 +20,8 @@
 
 #include <unistd.h>
 
+#include <thread>
+
 #include <android-base/stringprintf.h>
 
 #include "adb.h"
@@ -104,7 +106,7 @@
         if (r == -1) {
             D("writex: fd=%d error %d: %s", fd, errno, strerror(errno));
             if (errno == EAGAIN) {
-                adb_sleep_ms(1); // just yield some cpu time
+                std::this_thread::yield();
                 continue;
             } else if (errno == EPIPE) {
                 D("writex: fd=%d disconnected", fd);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e15bcad..a064de2 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -33,6 +33,7 @@
 
 #include <memory>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/file.h>
@@ -59,6 +60,7 @@
 #include "file_sync_service.h"
 #include "services.h"
 #include "shell_service.h"
+#include "sysdeps/chrono.h"
 
 static int install_app(TransportType t, const char* serial, int argc, const char** argv);
 static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
@@ -1080,7 +1082,7 @@
 
     // Give adbd some time to kill itself and come back up.
     // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
-    adb_sleep_ms(3000);
+    std::this_thread::sleep_for(3s);
     return true;
 }
 
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index f1e4179..caa7a5f 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -43,6 +43,7 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 #include "line_printer.h"
+#include "sysdeps/stat.h"
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
@@ -64,15 +65,11 @@
 }
 
 static bool should_pull_file(mode_t mode) {
-    return mode & (S_IFREG | S_IFBLK | S_IFCHR);
+    return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
 }
 
 static bool should_push_file(mode_t mode) {
-    mode_t mask = S_IFREG;
-#if !defined(_WIN32)
-    mask |= S_IFLNK;
-#endif
-    return mode & mask;
+    return S_ISREG(mode) || S_ISLNK(mode);
 }
 
 struct copyinfo {
@@ -149,7 +146,7 @@
     void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
                         uint64_t file_total_bytes) {
         char overall_percentage_str[5] = "?";
-        if (bytes_expected != 0) {
+        if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
             int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
             // If we're pulling symbolic links, we'll pull the target of the link rather than
             // just create a local link, and that will cause us to go over 100%.
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index e2b388b..4975fab 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -106,20 +106,6 @@
 
 namespace {
 
-void init_subproc_child()
-{
-    setsid();
-
-    // Set OOM score adjustment to prevent killing
-    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        adb_write(fd, "0", 1);
-        adb_close(fd);
-    } else {
-       D("adb: unable to update oom_score_adj");
-    }
-}
-
 // Reads from |fd| until close or failure.
 std::string ReadAll(int fd) {
     char buffer[512];
@@ -316,7 +302,7 @@
 
     if (pid_ == 0) {
         // Subprocess child.
-        init_subproc_child();
+        setsid();
 
         if (type_ == SubprocessType::kPty) {
             child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5e79b5e..f56f7f7 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -22,6 +22,7 @@
 #include <limits>
 #include <queue>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <unistd.h>
@@ -31,6 +32,7 @@
 #include "fdevent_test.h"
 #include "socket.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
 
 struct ThreadArg {
     int first_read_fd;
@@ -44,7 +46,7 @@
     fdevent_loop();
 }
 
-const size_t SLEEP_FOR_FDEVENT_IN_MS = 100;
+constexpr auto SLEEP_FOR_FDEVENT = 100ms;
 
 TEST_F(LocalSocketTest, smoke) {
     // Join two socketpairs with a chain of intermediate socketpairs.
@@ -101,7 +103,7 @@
     ASSERT_EQ(0, adb_close(last[1]));
 
     // Wait until the local sockets are closed.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -154,12 +156,12 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -179,9 +181,9 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Verify if we can read successfully.
@@ -190,7 +192,7 @@
     ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -214,11 +216,11 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -229,7 +231,7 @@
     std::string error;
     int fd = network_loopback_client(5038, SOCK_STREAM, &error);
     ASSERT_GE(fd, 0) << error;
-    adb_sleep_ms(200);
+    std::this_thread::sleep_for(200ms);
     ASSERT_EQ(0, adb_close(fd));
 }
 
@@ -265,13 +267,13 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Wait until the client closes its socket.
     ASSERT_TRUE(adb_thread_join(client_thread));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index ad9b9fd..05d9fde 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -180,8 +180,6 @@
     /* nothing really */
 }
 
-#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
-
 extern int  adb_unlink(const char*  path);
 #undef  unlink
 #define unlink  ___xxx_unlink
@@ -248,11 +246,6 @@
 int unix_isatty(int fd);
 #define  isatty  ___xxx_isatty
 
-static __inline__ void  adb_sleep_ms( int  mseconds )
-{
-    Sleep( mseconds );
-}
-
 int network_loopback_client(int port, int type, std::string* error);
 int network_loopback_server(int port, int type, std::string* error);
 int network_inaddr_any_server(int port, int type, std::string* error);
@@ -766,11 +759,6 @@
 
 #define poll ___xxx_poll
 
-static __inline__ void  adb_sleep_ms( int  mseconds )
-{
-    usleep( mseconds*1000 );
-}
-
 static __inline__ int  adb_mkdir(const std::string& path, int mode)
 {
     return mkdir(path.c_str(), mode);
diff --git a/adb/sysdeps/chrono.h b/adb/sysdeps/chrono.h
new file mode 100644
index 0000000..c73a638
--- /dev/null
+++ b/adb/sysdeps/chrono.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+
+#if defined(_WIN32)
+// We don't have C++14 on Windows yet.
+// Reimplement std::chrono_literals ourselves until we do.
+
+// Silence the following warning (which gets promoted to an error):
+// error: literal operator suffixes not preceded by ‘_’ are reserved for future standardization
+#pragma GCC system_header
+
+constexpr std::chrono::seconds operator"" s(unsigned long long s) {
+    return std::chrono::seconds(s);
+}
+
+constexpr std::chrono::duration<long double> operator"" s(long double s) {
+    return std::chrono::duration<long double>(s);
+}
+
+constexpr std::chrono::milliseconds operator"" ms(unsigned long long ms) {
+    return std::chrono::milliseconds(ms);
+}
+
+constexpr std::chrono::duration<long double, std::milli> operator"" ms(long double ms) {
+    return std::chrono::duration<long double, std::milli>(ms);
+}
+#else
+using namespace std::chrono_literals;
+#endif
diff --git a/adb/sysdeps/stat.h b/adb/sysdeps/stat.h
index 5953595..ed2cf25fb 100644
--- a/adb/sysdeps/stat.h
+++ b/adb/sysdeps/stat.h
@@ -43,4 +43,21 @@
 // Windows doesn't have lstat.
 #define lstat adb_stat
 
+// mingw doesn't define S_IFLNK or S_ISLNK.
+#define S_IFLNK 0120000
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+
+// mingw defines S_IFBLK to a different value from bionic.
+#undef S_IFBLK
+#define S_IFBLK 0060000
+#undef S_ISBLK
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
 #endif
+
+// Make sure that host file mode values match the ones on the device.
+static_assert(S_IFMT == 00170000, "");
+static_assert(S_IFLNK == 0120000, "");
+static_assert(S_IFREG == 0100000, "");
+static_assert(S_IFBLK == 0060000, "");
+static_assert(S_IFDIR == 0040000, "");
+static_assert(S_IFCHR == 0020000, "");
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 9f77942..9007e75 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -16,14 +16,17 @@
 
 #include <gtest/gtest.h>
 #include <unistd.h>
+
 #include <atomic>
 #include <condition_variable>
+#include <thread>
 
 #include "adb_io.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
 
 static void increment_atomic_int(void* c) {
-    sleep(1);
+    std::this_thread::sleep_for(1s);
     reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
 }
 
@@ -34,7 +37,7 @@
         ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
     }
 
-    sleep(2);
+    std::this_thread::sleep_for(2s);
     ASSERT_EQ(100, counter.load());
 }
 
@@ -255,15 +258,15 @@
         ASSERT_FALSE(m.try_lock());
         m.lock();
         finished.store(true);
-        adb_sleep_ms(200);
+        std::this_thread::sleep_for(200ms);
         m.unlock();
     }, nullptr);
 
     ASSERT_FALSE(finished.load());
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     ASSERT_FALSE(finished.load());
     m.unlock();
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     m.lock();
     ASSERT_TRUE(finished.load());
     m.unlock();
@@ -279,13 +282,13 @@
     adb_thread_create([](void*) {
         ASSERT_FALSE(m.try_lock());
         m.lock();
-        adb_sleep_ms(500);
+        std::this_thread::sleep_for(500ms);
         m.unlock();
     }, nullptr);
 
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     m.unlock();
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     ASSERT_FALSE(m.try_lock());
     m.lock();
     m.unlock();
diff --git a/adb/test_device.py b/adb/test_device.py
index 02a16e4..e76aaed 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -890,7 +890,8 @@
             except subprocess.CalledProcessError as e:
                 output = e.output
 
-            self.assertIn('Permission denied', output)
+            self.assertTrue('Permission denied' in output or
+                            'Read-only file system' in output)
 
     def _test_pull(self, remote_file, checksum):
         tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index ba2b28d..c17f869 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -27,6 +27,7 @@
 
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 #include <vector>
 
 #include <android-base/stringprintf.h>
@@ -39,6 +40,7 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
+#include "sysdeps/chrono.h"
 
 #if ADB_HOST
 
@@ -144,7 +146,7 @@
 
 // Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
 constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
-constexpr uint32_t LOCAL_PORT_RETRY_INTERVAL_IN_MS = 1000;
+constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s;
 
 struct RetryPort {
     int port;
@@ -173,7 +175,7 @@
         // Sleep here instead of the end of loop, because if we immediately try to reconnect
         // the emulator just kicked, the adbd on the emulator may not have time to remove the
         // just kicked transport.
-        adb_sleep_ms(LOCAL_PORT_RETRY_INTERVAL_IN_MS);
+        std::this_thread::sleep_for(LOCAL_PORT_RETRY_INTERVAL);
 
         // Try connecting retry ports.
         std::vector<RetryPort> next_ports;
@@ -214,7 +216,7 @@
             serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
             if(serverfd < 0) {
                 D("server: cannot bind socket yet: %s", error.c_str());
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
                 continue;
             }
             close_on_exec(serverfd);
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 3e5028d..e7f1338 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -38,6 +38,7 @@
 #include <list>
 #include <mutex>
 #include <string>
+#include <thread>
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -46,6 +47,7 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
 using namespace std::literals;
 
 /* usb scan debugging is waaaay too verbose */
@@ -577,7 +579,7 @@
         // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
         kick_disconnected_devices();
-        sleep(1);
+        std::this_thread::sleep_for(1s);
     }
 }
 
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 6de10f5..1cc7f68 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,8 +31,10 @@
 
 #include <algorithm>
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -40,6 +42,8 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_PACKET_SIZE_FS	64
 #define MAX_PACKET_SIZE_HS	512
 #define MAX_PACKET_SIZE_SS	1024
@@ -268,7 +272,7 @@
                 fd = unix_open("/dev/android", O_RDWR);
             }
             if (fd < 0) {
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
             }
         } while (fd < 0);
         D("[ opening device succeeded ]");
@@ -476,7 +480,7 @@
             if (init_functionfs(usb)) {
                 break;
             }
-            adb_sleep_ms(1000);
+            std::this_thread::sleep_for(1s);
         }
         android::base::SetProperty("sys.usb.ffs.ready", "1");
 
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 2ee2aae..e541f6e 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -30,8 +30,10 @@
 #include <stdio.h>
 
 #include <atomic>
+#include <chrono>
 #include <memory>
 #include <mutex>
+#include <thread>
 #include <vector>
 
 #include <android-base/logging.h>
@@ -40,6 +42,8 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 struct usb_handle
 {
     UInt8 bulkIn;
@@ -411,7 +415,7 @@
         }
         // Signal the parent that we are running
         usb_inited_flag = true;
-        adb_sleep_ms(1000);
+        std::this_thread::sleep_for(1s);
     }
     VLOG(USB) << "RunLoopThread done";
 }
@@ -436,7 +440,7 @@
 
         // Wait for initialization to finish
         while (!usb_inited_flag) {
-            adb_sleep_ms(100);
+            std::this_thread::sleep_for(100ms);
         }
 
         initialized = true;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 755f07e..640e91e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -28,12 +28,14 @@
 #include <stdlib.h>
 
 #include <mutex>
+#include <thread>
 
 #include <adb_api.h>
 
 #include <android-base/errors.h>
 
 #include "adb.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 
 /** Structure usb_handle describes our connection to the usb device via
@@ -176,9 +178,9 @@
   adb_thread_setname("Device Poll");
   D("Created device thread");
 
-  while(1) {
+  while (true) {
     find_devices();
-    adb_sleep_ms(1000);
+    std::this_thread::sleep_for(1s);
   }
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index e6ad15b..b9a6e0b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -49,6 +49,11 @@
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
         },
+        linux_bionic: {
+            srcs: ["errors_unix.cpp"],
+            cppflags: ["-Wexit-time-destructors"],
+            enabled: true,
+        },
         linux: {
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index 6a9ef2b..73f3295 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -19,13 +19,13 @@
 #include <cstdlib>
 
 #include <android-base/logging.h>
-#include <log/log.h>
+#include <log/log_event_list.h>
 
 namespace bootstat {
 
 void LogHistogram(const std::string& event, int32_t data) {
   LOG(INFO) << "Logging histogram: " << event << " " << data;
-  android_log_event_context log(HISTOGRAM_LOG_TAG);
+  android_log_event_list log(HISTOGRAM_LOG_TAG);
   log << event << data << LOG_ID_EVENTS;
 }
 
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index 3db67b3..b0e8b17 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -160,7 +160,11 @@
 {
     fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
 
-    if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
+    if (!strncmp(arg, "wait-", strlen("wait-"))) {
+      char buf[1];
+      TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
+      return do_action(arg + strlen("wait-"));
+    } else if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
       errno = 0;
       while (errno != EMFILE) {
         open("/dev/null", O_RDONLY);
@@ -235,6 +239,8 @@
     fprintf(stderr, "on the process' main thread.\n");
     fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
     fprintf(stderr, "all available file descriptors before crashing.\n");
+    fprintf(stderr, "prefix any of the above with 'wait-' to wait until input is received on stdin\n");
+
     return EXIT_SUCCESS;
 }
 
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 03b3a17..e76edb9 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -572,7 +572,7 @@
 
     if (log_entry.id() == LOG_ID_EVENTS) {
       if (!g_eventTagMap) {
-        g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        g_eventTagMap = android_openEventTagMap(NULL);
       }
       AndroidLogEntry e;
       char buf[512];
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4cd423a..7f4a0dd 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -43,7 +43,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <functional>
+#include <thread>
 #include <utility>
 #include <vector>
 
@@ -301,7 +303,7 @@
             announce = false;
             fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
-        usleep(1000);
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
     }
 }
 
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 6db1e27..cdab4f1 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -43,11 +43,15 @@
 #include <linux/version.h>
 #include <linux/usb/ch9.h>
 
+#include <chrono>
 #include <memory>
+#include <thread>
 
 #include "fastboot.h"
 #include "usb.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_RETRIES 5
 
 /* Timeout in seconds for usb_wait_for_disconnect.
@@ -426,7 +430,7 @@
         return -1;
     }
 
-    while(len > 0) {
+    while (len > 0) {
         int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
         bulk.ep = handle_->ep_in;
@@ -435,18 +439,17 @@
         bulk.timeout = 0;
         retry = 0;
 
-        do{
-           DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
-           n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
-           DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
+        do {
+            DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
+            n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
+            DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
 
-           if( n < 0 ) {
-            DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
-            if ( ++retry > MAX_RETRIES ) return -1;
-            sleep( 1 );
-           }
-        }
-        while( n < 0 );
+            if (n < 0) {
+                DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
+                if (++retry > MAX_RETRIES) return -1;
+                std::this_thread::sleep_for(1s);
+            }
+        } while (n < 0);
 
         count += n;
         len -= n;
@@ -488,9 +491,8 @@
 {
   double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
   while (now() < deadline) {
-    if (access(handle_->fname, F_OK))
-      return 0;
-    usleep(50000);
+    if (access(handle_->fname, F_OK)) return 0;
+    std::this_thread::sleep_for(50ms);
   }
   return -1;
 }
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 1cdeb32..3dab5ac 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -362,9 +362,3 @@
     std::unique_ptr<usb_handle> handle = find_usb_device(callback);
     return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
 }
-
-// called from fastboot.c
-void sleep(int seconds)
-{
-    Sleep(seconds * 1000);
-}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index d570255..e0d46d3 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -56,6 +56,7 @@
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
 
 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
+#define ZRAM_CONF_MCS   "/sys/block/zram0/max_comp_streams"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
@@ -241,7 +242,7 @@
     return ret;
 }
 
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
 {
     char *n1;
     char *n2;
@@ -651,7 +652,7 @@
  * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
  * in turn, and stop on 1st success, or no more match.
  */
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
@@ -802,6 +803,18 @@
              * we can assume the device number is 0.
              */
             FILE *zram_fp;
+            FILE *zram_mcs_fp;
+
+            if (fstab->recs[i].max_comp_streams >= 0) {
+               zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
+              if (zram_mcs_fp == NULL) {
+                ERROR("Unable to open zram conf comp device %s\n", ZRAM_CONF_MCS);
+                ret = -1;
+                continue;
+              }
+              fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
+              fclose(zram_mcs_fp);
+            }
 
             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
             if (zram_fp == NULL) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 313bc5a..b219b38 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -31,6 +31,7 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
 };
 
@@ -71,6 +72,7 @@
     { "recoveryonly",MF_RECOVERYONLY },
     { "swapprio=",   MF_SWAPPRIO },
     { "zramsize=",   MF_ZRAMSIZE },
+    { "max_comp_streams=",   MF_MAX_COMP_STREAMS },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
     { "notrim",       MF_NOTRIM },
@@ -180,6 +182,8 @@
                     }
                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
+                    flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
                     int is_percent = !!strrchr(p, '%');
                     unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
@@ -329,6 +333,7 @@
         fstab->recs[cnt].label = flag_vals.label;
         fstab->recs[cnt].partnum = flag_vals.partnum;
         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+        fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
         cnt++;
     }
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <libgen.h>
 #include "fs_mgr_priv.h"
 
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
 char *me = "";
 
 static void usage(void)
@@ -32,10 +37,10 @@
  * and exit the program, do not return to the caller.
  * Return the number of argv[] entries consumed.
  */
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
-                     char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+                     const char **n_name, const char **n_blk_dev)
 {
-    me = basename(strdup(argv[0]));
+    me = basename(argv[0]);
 
     if (argc <= 1) {
         usage();
@@ -75,14 +80,14 @@
     return;
 }
 
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
 {
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    char *n_name=NULL;
-    char *n_blk_dev=NULL;
-    char *fstab_file=NULL;
+    const char *n_name=NULL;
+    const char *n_blk_dev=NULL;
+    const char *fstab_file=NULL;
     struct fstab *fstab=NULL;
 
     klog_set_level(6);
@@ -97,7 +102,7 @@
     if (a_flag) {
         return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
     } else if (n_flag) {
-        return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+        return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
     } else if (u_flag) {
         return fs_mgr_unmount_all(fstab);
     } else {
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 6d9492b..741f5e9 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -85,6 +85,7 @@
 #define MF_FORCEFDEORFBE 0x10000
 #define MF_LATEMOUNT    0x20000
 #define MF_NOFAIL       0x40000
+#define MF_MAX_COMP_STREAMS 0x100000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c0116ef..37df8f8 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -73,6 +73,7 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
 };
 
@@ -95,7 +96,7 @@
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
 int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 612885b..857bcb2 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -257,13 +257,13 @@
 
 static int draw_text(const char *str, int x, int y)
 {
-    int str_len_px = gr_measure(str);
+    int str_len_px = gr_measure(gr_sys_font(), str);
 
     if (x < 0)
         x = (gr_fb_width() - str_len_px) / 2;
     if (y < 0)
         y = (gr_fb_height() - char_height) / 2;
-    gr_text(x, y, str, 0);
+    gr_text(gr_sys_font(), x, y, str, 0);
 
     return y + char_height;
 }
@@ -364,7 +364,7 @@
         }
 
         gr_init();
-        gr_font_size(&char_width, &char_height);
+        gr_font_size(gr_sys_font(), &char_width, &char_height);
 
 #ifndef CHARGER_DISABLE_INIT_BLANK
         gr_fb_blank(true);
diff --git a/include/cutils/files.h b/include/cutils/android_get_control_file.h
similarity index 87%
rename from include/cutils/files.h
rename to include/cutils/android_get_control_file.h
index 0210e30..ed8fbf8 100644
--- a/include/cutils/files.h
+++ b/include/cutils/android_get_control_file.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H
+#define __CUTILS_ANDROID_GET_CONTROL_FILE_H
 
 #define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
 
@@ -34,4 +34,4 @@
 }
 #endif
 
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 4626e7a..d724dd6 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -35,6 +35,7 @@
 #else
 
 #include <sys/socket.h>
+#include <netinet/in.h>
 
 typedef int cutils_socket_t;
 #define INVALID_SOCKET (-1)
diff --git a/include/log/log.h b/include/log/log.h
index a44aba8..d6f0eb5 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -27,15 +27,8 @@
 #include <time.h>    /* clock_gettime */
 #include <unistd.h>
 
-#include <log/uio.h> /* helper to define iovec for portability */
-
-#if (defined(__cplusplus) && defined(_USING_LIBCXX))
-extern "C++" {
-#include <string>
-}
-#endif
-
 #include <android/log.h>
+#include <log/uio.h> /* helper to define iovec for portability */
 
 #ifdef __cplusplus
 extern "C" {
@@ -774,207 +767,6 @@
 
 /* --------------------------------------------------------------------- */
 
-#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-#ifndef __ANDROID_API__
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#elif __ANDROID_API__ > 23 /* > Marshmallow */
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#else
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
-#endif
-#endif
-
-#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-#ifndef __android_log_context_defined
-#define __android_log_context_defined
-typedef struct android_log_context_internal* android_log_context;
-#endif
-
-/*
- * Elements returned when reading a list of events.
- */
-#ifndef __android_log_list_element_defined
-#define __android_log_list_element_defined
-typedef struct {
-    AndroidEventLogType type;
-    uint16_t complete;
-    uint16_t len;
-    union {
-        int32_t int32;
-        int64_t int64;
-        char* string;
-        float float32;
-    } data;
-} android_log_list_element;
-#endif
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- *     elements, we will manufacturer a list to embrace it for your API
- *     convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx,
-                                  const char* value, size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char* msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-#ifndef __class_android_log_event_context
-#define __class_android_log_event_context
-/* android_log_context C++ helpers */
-extern "C++" {
-class android_log_event_context {
-    android_log_context ctx;
-    int ret;
-
-    android_log_event_context(const android_log_event_context&) = delete;
-    void operator =(const android_log_event_context&) = delete;
-
-public:
-    explicit android_log_event_context(int tag) : ret(0) {
-        ctx = create_android_logger(static_cast<uint32_t>(tag));
-    }
-    explicit android_log_event_context(log_msg& log_msg) : ret(0) {
-        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
-                                        log_msg.entry.len - sizeof(uint32_t));
-    }
-    ~android_log_event_context() { android_log_destroy(&ctx); }
-
-    int close() {
-        int retval = android_log_destroy(&ctx);
-        if (retval < 0) ret = retval;
-        return retval;
-    }
-
-    /* To allow above C calls to use this class as parameter */
-    operator android_log_context() const { return ctx; }
-
-    int status() const { return ret; }
-
-    int begin() {
-        int retval = android_log_write_list_begin(ctx);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-    int end() {
-        int retval = android_log_write_list_end(ctx);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-
-    android_log_event_context& operator <<(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(uint32_t value) {
-        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(uint64_t value) {
-        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-#if defined(_USING_LIBCXX)
-    android_log_event_context& operator <<(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx,
-                                                   value.data(),
-                                                   value.length());
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-#endif
-    android_log_event_context& operator <<(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-
-    int write(log_id_t id = LOG_ID_EVENTS) {
-        int retval = android_log_write_list(ctx, id);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-
-    int operator <<(log_id_t id) {
-        int retval = android_log_write_list(ctx, id);
-        if (retval < 0) ret = retval;
-        android_log_destroy(&ctx);
-        return ret;
-    }
-
-    /*
-     * Append should be a lesser-used interface, but adds
-     * access to string with length. So we offer all types.
-     */
-    template <typename Tvalue>
-    bool Append(Tvalue value) { *this << value; return ret >= 0; }
-
-    bool Append(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) ret = retval;
-        return ret >= 0;
-    }
-
-    android_log_list_element read() { return android_log_read_next(ctx); }
-    android_log_list_element peek() { return android_log_peek_next(ctx); }
-
-};
-}
-#endif
-#endif
-
-#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
-
-/* --------------------------------------------------------------------- */
-
 #ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
 #ifndef __ANDROID_API__
 #define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
diff --git a/include/log/log_event_list.h b/include/log/log_event_list.h
new file mode 100644
index 0000000..31d49b2
--- /dev/null
+++ b/include/log/log_event_list.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2005-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_LOG_EVENT_LIST_H
+#define _LIBS_LOG_EVENT_LIST_H
+
+#include <stdint.h>
+
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+#ifndef __android_log_context_defined
+#define __android_log_context_defined
+typedef struct android_log_context_internal* android_log_context;
+#endif
+
+/*
+ * Elements returned when reading a list of events.
+ */
+#ifndef __android_log_list_element_defined
+#define __android_log_list_element_defined
+typedef struct {
+    AndroidEventLogType type;
+    uint16_t complete;
+    uint16_t len;
+    union {
+        int32_t int32;
+        int64_t int64;
+        char* string;
+        float float32;
+    } data;
+} android_log_list_element;
+#endif
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ *     elements, we will manufacturer a list to embrace it for your API
+ *     convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char* value);
+int android_log_write_string8_len(android_log_context ctx,
+                                  const char* value, size_t maxlen);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char* msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context* ctx);
+
+#ifdef __cplusplus
+#ifndef __class_android_log_event_list_defined
+#define __class_android_log_event_list_defined
+/* android_log_list C++ helpers */
+extern "C++" {
+class android_log_event_list {
+friend class __android_log_event_list;
+
+private:
+    android_log_context ctx;
+    int ret;
+
+    android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const android_log_event_list&) = delete;
+
+public:
+    explicit android_log_event_list(int tag) : ret(0) {
+        ctx = create_android_logger(static_cast<uint32_t>(tag));
+    }
+    explicit android_log_event_list(log_msg& log_msg) : ret(0) {
+        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+                                        log_msg.entry.len - sizeof(uint32_t));
+    }
+    ~android_log_event_list() { android_log_destroy(&ctx); }
+
+    int close() {
+        int retval = android_log_destroy(&ctx);
+        if (retval < 0) ret = retval;
+        return retval;
+    }
+
+    /* To allow above C calls to use this class as parameter */
+    operator android_log_context() const { return ctx; }
+
+    int status() const { return ret; }
+
+    int begin() {
+        int retval = android_log_write_list_begin(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+    int end() {
+        int retval = android_log_write_list_end(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    android_log_event_list& operator <<(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint32_t value) {
+        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint64_t value) {
+        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+#if defined(_USING_LIBCXX)
+    android_log_event_list& operator <<(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+#endif
+
+    android_log_event_list& operator <<(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    int write(log_id_t id = LOG_ID_EVENTS) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    int operator <<(log_id_t id) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        android_log_destroy(&ctx);
+        return ret;
+    }
+
+    /*
+     * Append<Type> methods removes any integer promotion
+     * confusion, and adds access to string with length.
+     * Append methods are also added for all types for
+     * convenience.
+     */
+
+    bool AppendInt(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendLong(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+#if defined(_USING_LIBCXX)
+    bool AppendString(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    bool Append(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+#endif
+
+    bool AppendFloat(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    template <typename Tvalue>
+    bool Append(Tvalue value) { *this << value; return ret >= 0; }
+
+    bool Append(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    android_log_list_element read() { return android_log_read_next(ctx); }
+    android_log_list_element peek() { return android_log_peek_next(ctx); }
+
+};
+}
+#endif
+#endif
+
+#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index f3c6cf7..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -25,6 +25,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log_event_list.h>
 #include <log/log.h>
 
 #define LOGGER_MAGIC 'l'
@@ -146,6 +153,40 @@
 unsigned long __android_logger_get_buffer_size(log_id_t logId);
 bool __android_logger_valid_buffer_size(unsigned long value);
 
+/* Retrieve the composed event buffer */
+int android_log_write_list_buffer(android_log_context ctx, const char** msg);
+
+#ifdef __cplusplus
+#ifdef __class_android_log_event_list_defined
+#ifndef __class_android_log_event_list_private_defined
+#define __class_android_log_event_list_private_defined
+/* android_log_context C++ helpers */
+extern "C++" {
+class __android_log_event_list : public android_log_event_list {
+    __android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const __android_log_event_list&) = delete;
+
+public:
+    explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
+    explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+
+#if defined(_USING_LIBCXX)
+    operator std::string() {
+        if (ret) return std::string("");
+        const char* cp = NULL;
+        ssize_t len = android_log_write_list_buffer(ctx, &cp);
+        if (len < 0) ret = len;
+        if (!cp || (len <= 0)) return std::string("");
+        return std::string(cp, len);
+    }
+#endif
+
+};
+}
+#endif
+#endif
+#endif
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index fc845a4..54946fc 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -195,7 +195,8 @@
  * Uncompress and write an entry to an open file identified by |fd|.
  * |entry->uncompressed_length| bytes will be written to the file at
  * its current offset, and the file will be truncated at the end of
- * the uncompressed data.
+ * the uncompressed data (no truncation if |fd| references a block
+ * device).
  *
  * Returns 0 on success and negative values on failure.
  */
diff --git a/init/action.cpp b/init/action.cpp
index ed88f6d..0ea7e14 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -105,7 +105,10 @@
 }
 
 void Action::ExecuteOneCommand(std::size_t command) const {
-    ExecuteCommand(commands_[command]);
+    // We need a copy here since some Command execution may result in
+    // changing commands_ vector by importing .rc files through parser
+    Command cmd = commands_[command];
+    ExecuteCommand(cmd);
 }
 
 void Action::ExecuteAllCommands() const {
@@ -118,14 +121,16 @@
     Timer t;
     int result = command.InvokeFunc();
 
-    // TODO: this should probably be changed to "if (failed || took a long time)"...
-    if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+    double duration_ms = t.duration() * 1000;
+    // Any action longer than 50ms will be warned to user as slow operation
+    if (duration_ms > 50.0 ||
+        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
         std::string source = command.BuildSourceString();
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
-                  << " returned " << result << " took " << t.duration() << "s";
+                  << " returned " << result << " took " << duration_ms << "ms.";
     }
 }
 
@@ -152,6 +157,11 @@
 bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
     const static std::string prop_str("property:");
     for (std::size_t i = 0; i < args.size(); ++i) {
+        if (args[i].empty()) {
+            *err = "empty trigger is not valid";
+            return false;
+        }
+
         if (i % 2) {
             if (args[i] != "&&") {
                 *err = "&& is the only symbol allowed to concatenate actions";
@@ -181,7 +191,11 @@
 bool Action::InitSingleTrigger(const std::string& trigger) {
     std::vector<std::string> name_vector{trigger};
     std::string err;
-    return InitTriggers(name_vector, &err);
+    bool ret = InitTriggers(name_vector, &err);
+    if (!ret) {
+        LOG(ERROR) << "InitSingleTrigger failed due to: " << err;
+    }
+    return ret;
 }
 
 // This function checks that all property triggers are satisfied, that is
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f37ccc2..6d58754 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -38,6 +38,9 @@
 #include <linux/loop.h>
 #include <linux/module.h>
 
+#include <thread>
+
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
@@ -65,10 +68,9 @@
 #include "util.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
-#define UNMOUNT_CHECK_MS 5000
 #define UNMOUNT_CHECK_TIMES 10
 
-static const int kTerminateServiceDelayMicroSeconds = 50000;
+static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
 
 static int insmod(const char *filename, const char *options, int flags) {
     int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
@@ -192,11 +194,9 @@
             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));
+            // Some processes using |entry->mnt_dir| are still alive. Wait for a
+            // while then retry.
+            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
             continue;
         } else {
             /* Cannot open the device. Give up. */
@@ -444,7 +444,7 @@
         return -1;
     } else {
         if (wait)
-            wait_for_file(source, COMMAND_RETRY_TIMEOUT);
+            wait_for_file(source, kCommandRetryTimeout);
         if (mount(source, target, system, flags, options) < 0) {
             return -1;
         }
@@ -590,9 +590,9 @@
 
     for (na = args.size() - 1; na > 1; --na) {
         if (args[na] == "--early") {
-             path_arg_end = na;
-             queue_event = false;
-             mount_mode = MOUNT_MODE_EARLY;
+            path_arg_end = na;
+            queue_event = false;
+            mount_mode = MOUNT_MODE_EARLY;
         } else if (args[na] == "--late") {
             path_arg_end = na;
             import_rc = false;
@@ -703,6 +703,15 @@
             callback_on_ro_remount = unmount_and_fsck;
         } else if (cmd == ANDROID_RB_RESTART2) {
             reboot_target = &command[len + 1];
+            // When rebooting to the bootloader notify the bootloader writing
+            // also the BCB.
+            if (strcmp(reboot_target, "bootloader") == 0) {
+                std::string err;
+                if (!write_reboot_bootloader(&err)) {
+                    LOG(ERROR) << "reboot-bootloader: Error writing "
+                                  "bootloader_message: " << err;
+                }
+            }
         }
     } else if (command[len] != '\0') {
         LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
@@ -740,7 +749,7 @@
             }
 
             // Wait a bit before recounting the number or running services.
-            usleep(kTerminateServiceDelayMicroSeconds);
+            std::this_thread::sleep_for(50ms);
         }
         LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds";
     }
@@ -896,21 +905,49 @@
 static int do_restorecon(const std::vector<std::string>& args) {
     int ret = 0;
 
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon(it->c_str()) < 0)
-            ret = -errno;
+    struct flag_type {const char* name; int value;};
+    static const flag_type flags[] = {
+        {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
+        {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
+        {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
+        {0, 0}
+    };
+
+    int flag = 0;
+
+    bool in_flags = true;
+    for (size_t i = 1; i < args.size(); ++i) {
+        if (android::base::StartsWith(args[i], "--")) {
+            if (!in_flags) {
+                LOG(ERROR) << "restorecon - flags must precede paths";
+                return -1;
+            }
+            bool found = false;
+            for (size_t j = 0; flags[j].name; ++j) {
+                if (args[i] == flags[j].name) {
+                    flag |= flags[j].value;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                LOG(ERROR) << "restorecon - bad flag " << args[i];
+                return -1;
+            }
+        } else {
+            in_flags = false;
+            if (restorecon(args[i].c_str(), flag) < 0) {
+                ret = -errno;
+            }
+        }
     }
     return ret;
 }
 
 static int do_restorecon_recursive(const std::vector<std::string>& args) {
-    int ret = 0;
-
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon_recursive(it->c_str()) < 0)
-            ret = -errno;
-    }
-    return ret;
+    std::vector<std::string> non_const_args(args);
+    non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
+    return do_restorecon(non_const_args);
 }
 
 static int do_loglevel(const std::vector<std::string>& args) {
@@ -947,11 +984,11 @@
 
 static int do_wait(const std::vector<std::string>& args) {
     if (args.size() == 2) {
-        return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
+        return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
     } else if (args.size() == 3) {
         int timeout;
         if (android::base::ParseInt(args[2], &timeout)) {
-            return wait_for_file(args[1].c_str(), timeout);
+            return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
         }
     }
     return -1;
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 10aae88..429a76e 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -23,7 +23,7 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
 #include "init.h"
diff --git a/init/devices.cpp b/init/devices.cpp
index 1a6912f..2db24b7 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/sendfile.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -34,6 +35,7 @@
 #include <linux/netlink.h>
 
 #include <memory>
+#include <thread>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
@@ -109,13 +111,18 @@
         return -ENOMEM;
 
     node->dp.name = strdup(name);
-    if (!node->dp.name)
+    if (!node->dp.name) {
+        free(node);
         return -ENOMEM;
+    }
 
     if (attr) {
         node->dp.attr = strdup(attr);
-        if (!node->dp.attr)
+        if (!node->dp.attr) {
+            free(node->dp.name);
+            free(node);
             return -ENOMEM;
+        }
     }
 
     node->dp.perm = perm;
@@ -183,7 +190,7 @@
 
     if (access(path.c_str(), F_OK) == 0) {
         LOG(VERBOSE) << "restorecon_recursive: " << path;
-        restorecon_recursive(path.c_str());
+        restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
     }
 }
 
@@ -784,139 +791,87 @@
     }
 }
 
-static int load_firmware(int fw_fd, int loading_fd, int data_fd)
-{
-    struct stat st;
-    long len_to_copy;
-    int ret = 0;
+static void load_firmware(uevent* uevent, const std::string& root,
+                          int fw_fd, size_t fw_size,
+                          int loading_fd, int data_fd) {
+    // Start transfer.
+    android::base::WriteFully(loading_fd, "1", 1);
 
-    if(fstat(fw_fd, &st) < 0)
-        return -1;
-    len_to_copy = st.st_size;
-
-    write(loading_fd, "1", 1);  /* start transfer */
-
-    while (len_to_copy > 0) {
-        char buf[PAGE_SIZE];
-        ssize_t nr;
-
-        nr = read(fw_fd, buf, sizeof(buf));
-        if(!nr)
-            break;
-        if(nr < 0) {
-            ret = -1;
-            break;
-        }
-        if (!android::base::WriteFully(data_fd, buf, nr)) {
-            ret = -1;
-            break;
-        }
-        len_to_copy -= nr;
+    // Copy the firmware.
+    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
+    if (rc == -1) {
+        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
     }
 
-    if(!ret)
-        write(loading_fd, "0", 1);  /* successful end of transfer */
-    else
-        write(loading_fd, "-1", 2); /* abort transfer */
-
-    return ret;
+    // Tell the firmware whether to abort or commit.
+    const char* response = (rc != -1) ? "0" : "-1";
+    android::base::WriteFully(loading_fd, response, strlen(response));
 }
 
-static int is_booting(void)
-{
+static int is_booting() {
     return access("/dev/.booting", F_OK) == 0;
 }
 
-static void process_firmware_event(struct uevent *uevent)
-{
-    char *root, *loading, *data;
-    int l, loading_fd, data_fd, fw_fd;
-    size_t i;
+static void process_firmware_event(uevent* uevent) {
     int booting = is_booting();
 
     LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
 
-    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
-    if (l == -1)
+    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+    std::string loading = root + "/loading";
+    std::string data = root + "/data";
+
+    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
+    if (loading_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
         return;
+    }
 
-    l = asprintf(&loading, "%sloading", root);
-    if (l == -1)
-        goto root_free_out;
-
-    l = asprintf(&data, "%sdata", root);
-    if (l == -1)
-        goto loading_free_out;
-
-    loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
-    if(loading_fd < 0)
-        goto data_free_out;
-
-    data_fd = open(data, O_WRONLY|O_CLOEXEC);
-    if(data_fd < 0)
-        goto loading_close_out;
+    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
+    if (data_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
+        return;
+    }
 
 try_loading_again:
-    for (i = 0; i < arraysize(firmware_dirs); i++) {
-        char *file = NULL;
-        l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
-        if (l == -1)
-            goto data_free_out;
-        fw_fd = open(file, O_RDONLY|O_CLOEXEC);
-        free(file);
-        if (fw_fd >= 0) {
-            if (!load_firmware(fw_fd, loading_fd, data_fd)) {
-                LOG(INFO) << "firmware: copy success { '" << root << "', '" << uevent->firmware << "' }";
-            } else {
-                LOG(ERROR) << "firmware: copy failure { '" << root << "', '" << uevent->firmware << "' }";
-            }
-            break;
+    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
+        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
+        struct stat sb;
+        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
+            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
+            return;
         }
     }
-    if (fw_fd < 0) {
-        if (booting) {
-            /* If we're not fully booted, we may be missing
-             * filesystems needed for firmware, wait and retry.
-             */
-            usleep(100000);
-            booting = is_booting();
-            goto try_loading_again;
-        }
-        PLOG(ERROR) << "firmware: could not open '" << uevent->firmware << "'";
-        write(loading_fd, "-1", 2);
-        goto data_close_out;
-    }
 
-    close(fw_fd);
-data_close_out:
-    close(data_fd);
-loading_close_out:
-    close(loading_fd);
-data_free_out:
-    free(data);
-loading_free_out:
-    free(loading);
-root_free_out:
-    free(root);
+    if (booting) {
+        // If we're not fully booted, we may be missing
+        // filesystems needed for firmware, wait and retry.
+        std::this_thread::sleep_for(100ms);
+        booting = is_booting();
+        goto try_loading_again;
+    }
+
+    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
+
+    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
+    write(loading_fd, "-1", 2);
 }
 
-static void handle_firmware_event(struct uevent *uevent)
-{
-    pid_t pid;
+static void handle_firmware_event(uevent* uevent) {
+    if (strcmp(uevent->subsystem, "firmware")) return;
+    if (strcmp(uevent->action, "add")) return;
 
-    if(strcmp(uevent->subsystem, "firmware"))
-        return;
-
-    if(strcmp(uevent->action, "add"))
-        return;
-
-    /* we fork, to avoid making large memory allocations in init proper */
-    pid = fork();
-    if (!pid) {
+    // Loading the firmware in a child means we can do that in parallel...
+    // (We ignore SIGCHLD rather than wait for our children.)
+    pid_t pid = fork();
+    if (pid == 0) {
+        Timer t;
         process_firmware_event(uevent);
+        LOG(INFO) << "loading " << uevent->path << " took " << t.duration() << "s";
         _exit(EXIT_SUCCESS);
-    } else if (pid < 0) {
-        PLOG(ERROR) << "could not fork to process firmware event";
+    } else if (pid == -1) {
+        PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
     }
 }
 
@@ -1091,7 +1046,6 @@
     LOG(INFO) << "Coldboot took " << t.duration() << "s.";
 }
 
-int get_device_fd()
-{
+int get_device_fd() {
     return device_fd;
 }
diff --git a/init/init.cpp b/init/init.cpp
index 7c37d28..734f129 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -67,6 +68,8 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::StringPrintf;
+
 struct selabel_handle *sehandle;
 struct selabel_handle *sehandle_prop;
 
@@ -75,7 +78,7 @@
 static char qemu[32];
 
 std::string default_console = "/dev/console";
-static time_t process_needs_restart;
+static time_t process_needs_restart_at;
 
 const char *ENV[32];
 
@@ -132,11 +135,10 @@
 
 static void restart_processes()
 {
-    process_needs_restart = 0;
-    ServiceManager::GetInstance().
-        ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {
-                s->RestartIfNeeded(process_needs_restart);
-            });
+    process_needs_restart_at = 0;
+    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
+        s->RestartIfNeeded(&process_needs_restart_at);
+    });
 }
 
 void handle_control_message(const std::string& msg, const std::string& name) {
@@ -164,7 +166,7 @@
     // Any longer than 1s is an unreasonable length of time to delay booting.
     // If you're hitting this timeout, check that you didn't make your
     // sepolicy regular expressions too expensive (http://b/19899875).
-    if (wait_for_file(COLDBOOT_DONE, 1)) {
+    if (wait_for_file(COLDBOOT_DONE, 1s)) {
         LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
     }
 
@@ -268,15 +270,14 @@
 
     if (for_emulator) {
         // In the emulator, export any kernel option with the "ro.kernel." prefix.
-        property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
+        property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
         return;
     }
 
     if (key == "qemu") {
         strlcpy(qemu, value.c_str(), sizeof(qemu));
     } else if (android::base::StartsWith(key, "androidboot.")) {
-        property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
-                     value.c_str());
+        property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());
     }
 }
 
@@ -314,7 +315,7 @@
 static void process_kernel_dt() {
     static const char android_dir[] = "/proc/device-tree/firmware/android";
 
-    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+    std::string file_name = StringPrintf("%s/compatible", android_dir);
 
     std::string dt_file;
     android::base::ReadFileToString(file_name, &dt_file);
@@ -332,12 +333,12 @@
             continue;
         }
 
-        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
+        file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
 
         android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
 
-        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        std::string property_name = StringPrintf("ro.boot.%s", dp->d_name);
         property_set(property_name.c_str(), dt_file.c_str());
     }
 }
@@ -566,12 +567,14 @@
         return watchdogd_main(argc, argv);
     }
 
+    boot_clock::time_point start_time = boot_clock::now();
+
     // Clear the umask.
     umask(0);
 
     add_environment("PATH", _PATH_DEFPATH);
 
-    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
 
     // Don't expose the raw commandline to unprivileged processes.
     chmod("/proc/cmdline", 0440);
@@ -590,38 +593,42 @@
         mount("sysfs", "/sys", "sysfs", 0, NULL);
         mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
         mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
+        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
     }
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
     // talk to the outside world...
     InitKernelLogging(argv);
 
-    if (is_first_stage) {
-        LOG(INFO) << "init first stage started!";
+    LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
 
+    if (is_first_stage) {
         // Mount devices defined in android.early.* kernel commandline
         early_mount();
 
-        // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+        // Set up SELinux, loading the SELinux policy.
         selinux_initialize(true);
 
-        // If we're in the kernel domain, re-exec init to transition to the init domain now
+        // We're in the kernel domain, so re-exec init to transition to the init domain now
         // that the SELinux policy has been loaded.
-
         if (restorecon("/init") == -1) {
             PLOG(ERROR) << "restorecon failed";
             security_failure();
         }
+
+        setenv("INIT_SECOND_STAGE", "true", 1);
+
+        uint64_t start_ns = start_time.time_since_epoch().count();
+        setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1);
+
         char* path = argv[0];
-        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+        char* args[] = { path, nullptr };
         if (execv(path, args) == -1) {
             PLOG(ERROR) << "execv(\"" << path << "\") failed";
             security_failure();
         }
-
     } else {
-        LOG(INFO) << "init second stage started!";
-
         // Indicate that booting is in progress to background fw loaders, etc.
         close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
@@ -636,7 +643,10 @@
         // used by init as well as the current required properties.
         export_kernel_boot_props();
 
-        // Now set up SELinux for second stage
+        // Make the time that init started available for bootstat to log.
+        property_set("init.start", getenv("INIT_STARTED_AT"));
+
+        // Now set up SELinux for second stage.
         selinux_initialize(false);
     }
 
@@ -647,10 +657,12 @@
     restorecon("/dev");
     restorecon("/dev/kmsg");
     restorecon("/dev/socket");
+    restorecon("/dev/random");
+    restorecon("/dev/urandom");
     restorecon("/dev/__properties__");
     restorecon("/property_contexts");
-    restorecon_recursive("/sys");
-    restorecon_recursive("/dev/block");
+    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
     restorecon("/dev/device-mapper");
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
@@ -710,21 +722,22 @@
             restart_processes();
         }
 
-        int timeout = -1;
-        if (process_needs_restart) {
-            timeout = (process_needs_restart - gettime()) * 1000;
-            if (timeout < 0)
-                timeout = 0;
+        // By default, sleep until something happens.
+        int epoll_timeout_ms = -1;
+
+        // If there's more work to do, wake up again immediately.
+        if (am.HasMoreCommands()) epoll_timeout_ms = 0;
+
+        // If there's a process that needs restarting, wake up in time for that.
+        if (process_needs_restart_at != 0) {
+            epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
+            if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
         }
 
-        if (am.HasMoreCommands()) {
-            timeout = 0;
-        }
-
-        bootchart_sample(&timeout);
+        bootchart_sample(&epoll_timeout_ms);
 
         epoll_event ev;
-        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
         if (nr == -1) {
             PLOG(ERROR) << "epoll_wait failed";
         } else if (nr == 1) {
diff --git a/init/init.h b/init/init.h
index 0019337..cfb3139 100644
--- a/init/init.h
+++ b/init/init.h
@@ -22,8 +22,6 @@
 class Action;
 class Service;
 
-#define COMMAND_RETRY_TIMEOUT 5
-
 extern const char *ENV[32];
 extern bool waiting_for_exec;
 extern std::string default_console;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e7176c6..e198297 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,6 +42,7 @@
 #include <netinet/in.h>
 #include <sys/mman.h>
 
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
@@ -175,7 +176,7 @@
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
     if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
-        if (restorecon_recursive(value) != 0) {
+        if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
diff --git a/init/readme.txt b/init/readme.txt
index 500b1d8..7e9d21b 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -440,8 +440,16 @@
 Init provides information about the services that it is responsible
 for via the below properties.
 
+init.start
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first
+  stage of init started.
+
 init.svc.<name>
-   State of a named service ("stopped", "stopping", "running", "restarting")
+  State of a named service ("stopped", "stopping", "running", "restarting")
+
+init.svc.<name>.start
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was
+  most recently started.
 
 
 Bootcharting
@@ -537,10 +545,10 @@
 
 For quicker turnaround when working on init itself, use:
 
-  mm -j
-  m ramdisk-nodeps
-  m bootimage-nodeps
-  adb reboot bootloader
+  mm -j &&
+  m ramdisk-nodeps &&
+  m bootimage-nodeps &&
+  adb reboot bootloader &&
   fastboot boot $ANDROID_PRODUCT_OUT/boot.img
 
 Alternatively, use the emulator:
diff --git a/init/service.cpp b/init/service.cpp
index 9fa11b8..1f53a1b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,7 @@
 #include "service.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <linux/securebits.h>
 #include <sched.h>
 #include <sys/mount.h>
@@ -51,9 +52,6 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
-#define CRITICAL_CRASH_THRESHOLD    4       // if we crash >4 times ...
-#define CRITICAL_CRASH_WINDOW       (4*60)  // ... in 4 minutes, goto recovery
-
 static std::string ComputeContextFromExecutable(std::string& service_name,
                                                 const std::string& service_path) {
     std::string computed_context;
@@ -154,8 +152,8 @@
 
 Service::Service(const std::string& name, const std::string& classname,
                  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
-      time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
+    : name_(name), classname_(classname), flags_(0), pid_(0),
+      crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
       seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
       priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
@@ -168,7 +166,7 @@
                  const std::string& seclabel,
                  const std::vector<std::string>& args)
     : name_(name), classname_(classname), flags_(flags), pid_(0),
-      time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
+      crash_count_(0), uid_(uid), gid_(gid),
       supp_gids_(supp_gids), capabilities_(capabilities),
       namespace_flags_(namespace_flags), seclabel_(seclabel),
       ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
@@ -190,6 +188,12 @@
     }
 
     property_set(prop_name.c_str(), new_state.c_str());
+
+    if (new_state == "running") {
+        prop_name += ".start";
+        uint64_t start_ns = time_started_.time_since_epoch().count();
+        property_set(prop_name.c_str(), StringPrintf("%" PRIu64, start_ns).c_str());
+    }
 }
 
 void Service::KillProcessGroup(int signal) {
@@ -274,20 +278,19 @@
         return false;
     }
 
-    time_t now = gettime();
+    // If we crash > 4 times in 4 minutes, reboot into recovery.
+    boot_clock::time_point now = boot_clock::now();
     if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
-        if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
-            if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
-                LOG(ERROR) << "critical process '" << name_ << "' exited "
-                           << CRITICAL_CRASH_THRESHOLD << " times in "
-                           << (CRITICAL_CRASH_WINDOW / 60) << " minutes; "
+        if (now < time_crashed_ + 4min) {
+            if (++crash_count_ > 4) {
+                LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes; "
                            << "rebooting into recovery mode";
                 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
                 return false;
             }
         } else {
             time_crashed_ = now;
-            nr_crashed_ = 1;
+            crash_count_ = 1;
         }
     }
 
@@ -357,8 +360,8 @@
 bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
     priority_ = 0;
     if (!ParseInt(args[1], &priority_,
-                  static_cast<int>(ANDROID_PRIORITY_LOWEST),
-                  static_cast<int>(ANDROID_PRIORITY_HIGHEST))) {
+                  static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
+                  static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
         *err = StringPrintf("process priority value must be range %d - %d",
                 ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
         return false;
@@ -553,7 +556,6 @@
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
-    time_started_ = 0;
 
     // Running processes require no additional work --- if they're in the
     // process of exiting, we've ensured that they will immediately restart
@@ -667,7 +669,7 @@
         }
     }
 
-    time_started_ = gettime();
+    time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
 
@@ -731,18 +733,19 @@
     } /* else: Service is restarting anyways. */
 }
 
-void Service::RestartIfNeeded(time_t& process_needs_restart) {
-    time_t next_start_time = time_started_ + 5;
-
-    if (next_start_time <= gettime()) {
+void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
+    boot_clock::time_point now = boot_clock::now();
+    boot_clock::time_point next_start = time_started_ + 5s;
+    if (now > next_start) {
         flags_ &= (~SVC_RESTARTING);
         Start();
         return;
     }
 
-    if ((next_start_time < process_needs_restart) ||
-        (process_needs_restart == 0)) {
-        process_needs_restart = next_start_time;
+    time_t next_start_time_t = time(nullptr) +
+        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
+    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
+        *process_needs_restart_at = next_start_time_t;
     }
 }
 
diff --git a/init/service.h b/init/service.h
index d9e8f57..013e65f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -30,6 +30,7 @@
 #include "descriptors.h"
 #include "init_parser.h"
 #include "keyword_map.h"
+#include "util.h"
 
 #define SVC_DISABLED       0x001  // do not autostart with class
 #define SVC_ONESHOT        0x002  // do not restart on exit
@@ -75,7 +76,7 @@
     void Stop();
     void Terminate();
     void Restart();
-    void RestartIfNeeded(time_t& process_needs_restart);
+    void RestartIfNeeded(time_t* process_needs_restart_at);
     bool Reap();
     void DumpState() const;
 
@@ -134,9 +135,9 @@
 
     unsigned flags_;
     pid_t pid_;
-    time_t time_started_;    // time of last start
-    time_t time_crashed_;    // first crash within inspection window
-    int nr_crashed_;         // number of times crashed within window
+    boot_clock::time_point time_started_; // time of last start
+    boot_clock::time_point time_crashed_; // first crash within inspection window
+    int crash_count_;                     // number of times crashed within window
 
     uid_t uid_;
     gid_t gid_;
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index e7794ec..361b925 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -95,7 +95,6 @@
     int prefix = 0;
     int wildcard = 0;
     char *endptr;
-    char *tmp = 0;
 
     if (nargs == 0)
         return;
@@ -129,14 +128,12 @@
     perm = strtol(args[1], &endptr, 8);
     if (!endptr || *endptr != '\0') {
         LOG(ERROR) << "invalid mode '" << args[1] << "'";
-        free(tmp);
         return;
     }
 
     struct passwd* pwd = getpwnam(args[2]);
     if (!pwd) {
         LOG(ERROR) << "invalid uid '" << args[2] << "'";
-        free(tmp);
         return;
     }
     uid = pwd->pw_uid;
@@ -144,11 +141,17 @@
     struct group* grp = getgrnam(args[3]);
     if (!grp) {
         LOG(ERROR) << "invalid gid '" << args[3] << "'";
-        free(tmp);
         return;
     }
     gid = grp->gr_gid;
 
-    add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
-    free(tmp);
+    if (add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard) != 0) {
+        PLOG(ERROR) << "add_dev_perms(name=" << name <<
+                       ", attr=" << attr <<
+                       ", perm=" << std::oct << perm << std::dec <<
+                       ", uid=" << uid << ", gid=" << gid <<
+                       ", prefix=" << prefix << ", wildcard=" << wildcard <<
+                       ")";
+        return;
+    }
 }
diff --git a/init/util.cpp b/init/util.cpp
index ab6837d..5205ea0 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,10 +34,13 @@
 #include <sys/types.h>
 #include <sys/un.h>
 
+#include <thread>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
 
@@ -89,10 +92,6 @@
 int create_socket(const char *name, int type, mode_t perm, uid_t uid,
                   gid_t gid, const char *socketcon)
 {
-    struct sockaddr_un addr;
-    int fd, ret, savederrno;
-    char *filecon;
-
     if (socketcon) {
         if (setsockcreatecon(socketcon) == -1) {
             PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -100,52 +99,49 @@
         }
     }
 
-    fd = socket(PF_UNIX, type, 0);
+    android::base::unique_fd fd(socket(PF_UNIX, type, 0));
     if (fd < 0) {
         PLOG(ERROR) << "Failed to open socket '" << name << "'";
         return -1;
     }
 
-    if (socketcon)
-        setsockcreatecon(NULL);
+    if (socketcon) setsockcreatecon(NULL);
 
+    struct sockaddr_un addr;
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
              name);
 
-    ret = unlink(addr.sun_path);
-    if (ret != 0 && errno != ENOENT) {
+    if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
         PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
-        goto out_close;
+        return -1;
     }
 
-    filecon = NULL;
+    char *filecon = NULL;
     if (sehandle) {
-        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
-        if (ret == 0)
+        if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
             setfscreatecon(filecon);
+        }
     }
 
-    ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
-    savederrno = errno;
+    int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+    int savederrno = errno;
 
     setfscreatecon(NULL);
     freecon(filecon);
 
     if (ret) {
-      errno = savederrno;
+        errno = savederrno;
         PLOG(ERROR) << "Failed to bind socket '" << name << "'";
         goto out_unlink;
     }
 
-    ret = lchown(addr.sun_path, uid, gid);
-    if (ret) {
+    if (lchown(addr.sun_path, uid, gid)) {
         PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
         goto out_unlink;
     }
-    ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
-    if (ret) {
+    if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
         PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
         goto out_unlink;
     }
@@ -155,12 +151,10 @@
               << ", user " << uid
               << ", group " << gid;
 
-    return fd;
+    return fd.release();
 
 out_unlink:
     unlink(addr.sun_path);
-out_close:
-    close(fd);
     return -1;
 }
 
@@ -173,7 +167,6 @@
                   gid_t gid, const char *filecon)
 {
     char *secontext = NULL;
-    int ret;
 
     if (filecon) {
         if (setsockcreatecon(filecon) == -1) {
@@ -181,18 +174,17 @@
             return -1;
         }
     } else if (sehandle) {
-        ret = selabel_lookup(sehandle, &secontext, path, perm);
-        if (ret != -1) {
-            ret = setfscreatecon(secontext);
-            if (ret == -1) {
-                freecon(secontext);
+        if (selabel_lookup(sehandle, &secontext, path, perm) != -1) {
+            if (setfscreatecon(secontext) == -1) {
+                freecon(secontext); // does not upset errno value
                 PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
                 return -1;
             }
         }
     }
 
-    int fd = TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm));
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+    int savederrno = errno;
 
     if (filecon) {
         setsockcreatecon(NULL);
@@ -202,23 +194,22 @@
         freecon(secontext);
     }
 
-    if (fd == -1) {
+    if (fd < 0) {
+        errno = savederrno;
         PLOG(ERROR) << "Failed to open/create file '" << path << "'";
-        goto out_close;
+        return -1;
     }
 
     if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
 
-    ret = lchown(path, uid, gid);
-    if (ret) {
+    if (lchown(path, uid, gid)) {
         PLOG(ERROR) << "Failed to lchown file '" << path << "'";
-        goto out_close;
+        return -1;
     }
     if (perm != static_cast<mode_t>(-1)) {
-        ret = fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW);
-        if (ret) {
+        if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
             PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
-            goto out_close;
+            return -1;
         }
     }
 
@@ -227,11 +218,7 @@
               << ", user " << uid
               << ", group " << gid;
 
-    return fd;
-
-out_close:
-    if (fd >= 0) close(fd);
-    return -1;
+    return fd.release();
 }
 
 bool read_file(const char* path, std::string* content) {
@@ -273,16 +260,11 @@
     return result;
 }
 
-time_t gettime() {
-    timespec now;
-    clock_gettime(CLOCK_MONOTONIC, &now);
-    return now.tv_sec;
-}
-
-uint64_t gettime_ns() {
-    timespec now;
-    clock_gettime(CLOCK_MONOTONIC, &now);
-    return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
+boot_clock::time_point boot_clock::now() {
+  timespec ts;
+  clock_gettime(CLOCK_BOOTTIME, &ts);
+  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+                                std::chrono::nanoseconds(ts.tv_nsec));
 }
 
 int mkdir_recursive(const char *pathname, mode_t mode)
@@ -340,16 +322,15 @@
     }
 }
 
-int wait_for_file(const char *filename, int timeout)
-{
-    struct stat info;
-    uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
-    int ret = -1;
+int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
+    boot_clock::time_point timeout_time = boot_clock::now() + timeout;
+    while (boot_clock::now() < timeout_time) {
+        struct stat sb;
+        if (stat(filename, &sb) != -1) return 0;
 
-    while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
-        usleep(10000);
-
-    return ret;
+        std::this_thread::sleep_for(10ms);
+    }
+    return -1;
 }
 
 void import_kernel_cmdline(bool in_qemu,
@@ -388,14 +369,9 @@
     return rc;
 }
 
-int restorecon(const char* pathname)
+int restorecon(const char* pathname, int flags)
 {
-    return selinux_android_restorecon(pathname, 0);
-}
-
-int restorecon_recursive(const char* pathname)
-{
-    return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
+    return selinux_android_restorecon(pathname, flags);
 }
 
 /*
diff --git a/init/util.h b/init/util.h
index 12ab173..d56da39 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,11 +20,14 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <string>
 #include <functional>
 
 #define COLDBOOT_DONE "/dev/.coldboot_done"
 
+using namespace std::chrono_literals;
+
 int create_socket(const char *name, int type, mode_t perm,
                   uid_t uid, gid_t gid, const char *socketcon);
 int create_file(const char *path, int mode, mode_t perm,
@@ -33,32 +36,39 @@
 bool read_file(const char* path, std::string* content);
 int write_file(const char* path, const char* content);
 
-time_t gettime();
-uint64_t gettime_ns();
+// A std::chrono clock based on CLOCK_BOOTTIME.
+class boot_clock {
+ public:
+  typedef std::chrono::nanoseconds duration;
+  typedef std::chrono::time_point<boot_clock, duration> time_point;
+  static constexpr bool is_steady = true;
+
+  static time_point now();
+};
 
 class Timer {
  public:
-  Timer() : t0(gettime_ns()) {
+  Timer() : start_(boot_clock::now()) {
   }
 
   double duration() {
-    return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+    typedef std::chrono::duration<double> double_duration;
+    return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
   }
 
  private:
-  uint64_t t0;
+  boot_clock::time_point start_;
 };
 
 unsigned int decode_uid(const char *s);
 
 int mkdir_recursive(const char *pathname, mode_t mode);
 void sanitize(char *p);
-int wait_for_file(const char *filename, int timeout);
+int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
 void import_kernel_cmdline(bool in_qemu,
                            const std::function<void(const std::string&, const std::string&, bool)>&);
 int make_dir(const char *path, mode_t mode);
-int restorecon(const char *pathname);
-int restorecon_recursive(const char *pathname);
+int restorecon(const char *pathname, int flags = 0);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 6ecbf90..e9f164d 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -16,6 +16,7 @@
 
 #include "util.h"
 
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -23,7 +24,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/files.h>
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
 #include <gtest/gtest.h>
 #include <selinux/android.h>
 
@@ -55,45 +58,48 @@
 TEST(util, create_file) {
   if (!sehandle) sehandle = selinux_android_file_context_handle();
 
-  static const char path[] = "/data/local/tmp/util.create_file.test";
-  static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test";
-  EXPECT_EQ(unsetenv(key), 0);
-  unlink(path);
+  TemporaryFile tf;
+  close(tf.fd);
+  EXPECT_GE(unlink(tf.path), 0);
 
-  int fd;
+  std::string key(ANDROID_FILE_ENV_PREFIX);
+  key += tf.path;
+
+  std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+  EXPECT_EQ(unsetenv(key.c_str()), 0);
+
   uid_t uid = decode_uid("logd");
   gid_t gid = decode_uid("system");
   mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
   static const char context[] = "u:object_r:misc_logd_file:s0";
-  EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
-  if (fd < 0) return;
+  EXPECT_GE(tf.fd = create_file(tf.path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
+  if (tf.fd < 0) return;
   static const char hello[] = "hello world\n";
   static const ssize_t len = strlen(hello);
-  EXPECT_EQ(write(fd, hello, len), len);
-  char buffer[sizeof(hello)];
+  EXPECT_EQ(write(tf.fd, hello, len), len);
+  char buffer[sizeof(hello) + 1];
   memset(buffer, 0, sizeof(buffer));
-  EXPECT_GE(lseek(fd, 0, SEEK_SET), 0);
-  EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len);
-  EXPECT_EQ(strcmp(hello, buffer), 0);
-  char val[32];
-  snprintf(val, sizeof(val), "%d", fd);
-  EXPECT_EQ(android_get_control_file(path), -1);
-  setenv(key, val, true);
-  EXPECT_EQ(android_get_control_file(path), fd);
-  close(fd);
-  EXPECT_EQ(android_get_control_file(path), -1);
-  EXPECT_EQ(unsetenv(key), 0);
+  EXPECT_GE(lseek(tf.fd, 0, SEEK_SET), 0);
+  EXPECT_EQ(read(tf.fd, buffer, sizeof(buffer)), len);
+  EXPECT_EQ(std::string(hello), buffer);
+  EXPECT_EQ(android_get_control_file(tf.path), -1);
+  EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+  EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+  close(tf.fd);
+  EXPECT_EQ(android_get_control_file(tf.path), -1);
+  EXPECT_EQ(unsetenv(key.c_str()), 0);
   struct stat st;
-  EXPECT_EQ(stat(path, &st), 0);
+  EXPECT_EQ(stat(tf.path, &st), 0);
   EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
   EXPECT_EQ(st.st_uid, uid);
   EXPECT_EQ(st.st_gid, gid);
   security_context_t con;
-  EXPECT_GE(getfilecon(path, &con), 0);
+  EXPECT_GE(getfilecon(tf.path, &con), 0);
   EXPECT_NE(con, static_cast<security_context_t>(NULL));
   if (con) {
     EXPECT_EQ(context, std::string(con));
   }
   freecon(con);
-  EXPECT_EQ(unlink(path), 0);
+  EXPECT_EQ(unlink(tf.path), 0);
 }
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index 8b46154..f729faf 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -15,12 +15,20 @@
     name: "libappfuse",
     defaults: ["libappfuse_defaults"],
     export_include_dirs: ["include"],
-    srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
+    srcs: [
+        "FuseAppLoop.cc",
+        "FuseBuffer.cc",
+        "FuseBridgeLoop.cc",
+    ]
 }
 
 cc_test {
     name: "libappfuse_test",
     defaults: ["libappfuse_defaults"],
     shared_libs: ["libappfuse"],
-    srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
+    srcs: [
+        "tests/FuseAppLoopTest.cc",
+        "tests/FuseBridgeLoopTest.cc",
+        "tests/FuseBufferTest.cc",
+    ]
 }
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
new file mode 100644
index 0000000..a31880e
--- /dev/null
+++ b/libappfuse/FuseAppLoop.cc
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/stat.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+namespace {
+
+void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  // AppFuse does not support directory structure now.
+  // It can lookup only files under the mount point.
+  if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
+    LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  // Ensure that the filename ends with 0.
+  const size_t filename_length =
+      buffer->request.header.len - sizeof(fuse_in_header);
+  if (buffer->request.lookup_name[filename_length - 1] != 0) {
+    LOG(ERROR) << "File name does not end with 0.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const uint64_t inode =
+      static_cast<uint64_t>(atol(buffer->request.lookup_name));
+  if (inode == 0 || inode == LONG_MAX) {
+    LOG(ERROR) << "Invalid filename";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const int64_t size = callback->OnGetSize(inode);
+  if (size < 0) {
+    buffer->response.Reset(0, size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_entry_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.entry_out.nodeid = inode;
+  buffer->response.entry_out.attr_valid = 10;
+  buffer->response.entry_out.entry_valid = 10;
+  buffer->response.entry_out.attr.ino = inode;
+  buffer->response.entry_out.attr.mode = S_IFREG | 0777;
+  buffer->response.entry_out.attr.size = size;
+}
+
+void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  int64_t size;
+  uint32_t mode;
+  if (nodeid == FUSE_ROOT_ID) {
+    size = 0;
+    mode = S_IFDIR | 0777;
+  } else {
+    size = callback->OnGetSize(buffer->request.header.nodeid);
+    if (size < 0) {
+      buffer->response.Reset(0, size, buffer->request.header.unique);
+      return;
+    }
+    mode = S_IFREG | 0777;
+  }
+
+  buffer->response.Reset(sizeof(fuse_attr_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.attr_out.attr_valid = 10;
+  buffer->response.attr_out.attr.ino = nodeid;
+  buffer->response.attr_out.attr.mode = mode;
+  buffer->response.attr_out.attr.size = size;
+}
+
+void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
+  if (file_handle < 0) {
+    buffer->response.Reset(0, file_handle, buffer->request.header.unique);
+    return;
+  }
+  buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
+                         buffer->request.header.unique);
+  buffer->response.open_out.fh = file_handle;
+}
+
+void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.read_in.offset;
+  const uint32_t size = buffer->request.read_in.size;
+
+  if (size > kFuseMaxRead) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t read_size = callback->OnRead(nodeid, offset, size,
+                                             buffer->response.read_data);
+  if (read_size < 0) {
+    buffer->response.Reset(0, read_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
+}
+
+void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.write_in.offset;
+  const uint32_t size = buffer->request.write_in.size;
+
+  if (size > kFuseMaxWrite) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t write_size = callback->OnWrite(nodeid, offset, size,
+                                               buffer->request.write_data);
+  if (write_size < 0) {
+    buffer->response.Reset(0, write_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
+  buffer->response.write_out.size = write_size;
+}
+
+} // namespace
+
+bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
+  base::unique_fd fd(raw_fd);
+  FuseBuffer buffer;
+
+  LOG(DEBUG) << "Start fuse loop.";
+  while (callback->IsActive()) {
+    if (!buffer.request.Read(fd)) {
+      return false;
+    }
+
+    const uint32_t opcode = buffer.request.header.opcode;
+    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+    switch (opcode) {
+      case FUSE_FORGET:
+        // Do not reply to FUSE_FORGET.
+        continue;
+
+      case FUSE_LOOKUP:
+        HandleLookUp(&buffer, callback);
+        break;
+
+      case FUSE_GETATTR:
+        HandleGetAttr(&buffer, callback);
+        break;
+
+      case FUSE_OPEN:
+        HandleOpen(&buffer, callback);
+        break;
+
+      case FUSE_READ:
+        HandleRead(&buffer, callback);
+        break;
+
+      case FUSE_WRITE:
+        HandleWrite(&buffer, callback);
+        break;
+
+      case FUSE_RELEASE:
+        HandleRelease(&buffer, callback);
+        break;
+
+      case FUSE_FSYNC:
+        HandleFsync(&buffer, callback);
+        break;
+
+      default:
+        buffer.HandleNotImpl();
+        break;
+    }
+
+    if (!buffer.response.Write(fd)) {
+      LOG(ERROR) << "Failed to write a response to the device.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 332556d..2386bf8 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -20,19 +20,22 @@
 #include <android-base/unique_fd.h>
 
 namespace android {
+namespace fuse {
 
-bool FuseBridgeLoop::Start(
-    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
+bool StartFuseBridgeLoop(
+    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) {
   base::unique_fd dev_fd(raw_dev_fd);
   base::unique_fd proxy_fd(raw_proxy_fd);
+  FuseBuffer buffer;
+  size_t open_count = 0;
 
   LOG(DEBUG) << "Start fuse loop.";
   while (true) {
-    if (!buffer_.request.Read(dev_fd)) {
+    if (!buffer.request.Read(dev_fd)) {
       return false;
     }
 
-    const uint32_t opcode = buffer_.request.header.opcode;
+    const uint32_t opcode = buffer.request.header.opcode;
     LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
     switch (opcode) {
       case FUSE_FORGET:
@@ -45,35 +48,54 @@
       case FUSE_READ:
       case FUSE_WRITE:
       case FUSE_RELEASE:
-      case FUSE_FLUSH:
-        if (!buffer_.request.Write(proxy_fd)) {
+      case FUSE_FSYNC:
+        if (!buffer.request.Write(proxy_fd)) {
           LOG(ERROR) << "Failed to write a request to the proxy.";
           return false;
         }
-        if (!buffer_.response.Read(proxy_fd)) {
+        if (!buffer.response.Read(proxy_fd)) {
           LOG(ERROR) << "Failed to read a response from the proxy.";
           return false;
         }
         break;
 
       case FUSE_INIT:
-        buffer_.HandleInit();
+        buffer.HandleInit();
         break;
 
       default:
-        buffer_.HandleNotImpl();
+        buffer.HandleNotImpl();
         break;
     }
 
-    if (!buffer_.response.Write(dev_fd)) {
+    if (!buffer.response.Write(dev_fd)) {
       LOG(ERROR) << "Failed to write a response to the device.";
       return false;
     }
 
-    if (opcode == FUSE_INIT) {
-      callback->OnMount();
+    switch (opcode) {
+      case FUSE_INIT:
+        callback->OnMount();
+        break;
+      case FUSE_OPEN:
+        if (buffer.response.header.error == fuse::kFuseSuccess) {
+          open_count++;
+        }
+        break;
+      case FUSE_RELEASE:
+        if (open_count != 0) {
+            open_count--;
+        } else {
+            LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
+            break;
+        }
+        if (open_count == 0) {
+          return true;
+        }
+        break;
     }
   }
 }
 
+}  // namespace fuse
 }  // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 45280a5..3ade31c 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -21,15 +21,22 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <type_traits>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 
 namespace android {
+namespace fuse {
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckHeaderLength() const {
-  if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+static_assert(
+    std::is_standard_layout<FuseBuffer>::value,
+    "FuseBuffer must be standard layout union.");
+
+template <typename T>
+bool FuseMessage<T>::CheckHeaderLength() const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (sizeof(header) <= header.len && header.len <= sizeof(T)) {
     return true;
   } else {
     LOG(ERROR) << "Packet size is invalid=" << header.len;
@@ -37,27 +44,29 @@
   }
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckResult(
+template <typename T>
+bool FuseMessage<T>::CheckResult(
     int result, const char* operation_name) const {
+  const auto& header = static_cast<const T*>(this)->header;
   if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
     return true;
   } else {
     PLOG(ERROR) << "Failed to " << operation_name
-        << " a packet from FD. result=" << result << " header.len="
+        << " a packet. result=" << result << " header.len="
         << header.len;
     return false;
   }
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Read(int fd) {
+template <typename T>
+bool FuseMessage<T>::Read(int fd) {
   const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
   return CheckHeaderLength() && CheckResult(result, "read");
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Write(int fd) const {
+template <typename T>
+bool FuseMessage<T>::Write(int fd) const {
+  const auto& header = static_cast<const T*>(this)->header;
   if (!CheckHeaderLength()) {
     return false;
   }
@@ -65,8 +74,16 @@
   return CheckResult(result, "write");
 }
 
-template struct FuseMessage<FuseRequest, fuse_in_header>;
-template struct FuseMessage<FuseResponse, fuse_out_header>;
+template class FuseMessage<FuseRequest>;
+template class FuseMessage<FuseResponse>;
+
+void FuseRequest::Reset(
+    uint32_t data_length, uint32_t opcode, uint64_t unique) {
+  memset(this, 0, sizeof(fuse_in_header) + data_length);
+  header.len = sizeof(fuse_in_header) + data_length;
+  header.opcode = opcode;
+  header.unique = unique;
+}
 
 void FuseResponse::ResetHeader(
     uint32_t data_length, int32_t error, uint64_t unique) {
@@ -101,23 +118,18 @@
     return;
   }
 
-  // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
-  size_t response_size = sizeof(fuse_init_out);
+  // We limit ourselves to minor=15 because we don't handle BATCH_FORGET yet.
+  // Thus we need to use FUSE_COMPAT_22_INIT_OUT_SIZE.
 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
   // FUSE_KERNEL_VERSION >= 23.
-
-  // If the kernel only works on minor revs older than or equal to 22,
-  // then use the older structure size since this code only uses the 7.22
-  // version of the structure.
-  if (minor <= 22) {
-    response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-  }
+  const size_t response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+#else
+  const size_t response_size = sizeof(fuse_init_out);
 #endif
 
   response.Reset(response_size, kFuseSuccess, unique);
   fuse_init_out* const out = &response.init_out;
   out->major = FUSE_KERNEL_VERSION;
-  // We limit ourselves to 15 because we don't handle BATCH_FORGET yet.
   out->minor = std::min(minor, 15u);
   out->max_readahead = max_readahead;
   out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
@@ -133,4 +145,5 @@
   response.Reset(0, -ENOSYS, unique);
 }
 
+}  // namespace fuse
 }  // namespace android
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h
new file mode 100644
index 0000000..c3edfcc
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseAppLoop.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseAppLoopCallback {
+ public:
+  virtual bool IsActive() = 0;
+  virtual int64_t OnGetSize(uint64_t inode) = 0;
+  virtual int32_t OnFsync(uint64_t inode) = 0;
+  virtual int32_t OnWrite(
+      uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
+  virtual int32_t OnRead(
+      uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
+  virtual int32_t OnOpen(uint64_t inode) = 0;
+  virtual int32_t OnRelease(uint64_t inode) = 0;
+  virtual ~FuseAppLoopCallback() = default;
+};
+
+bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);
+
+}  // namespace fuse
+}  // namespace android
+
+#endif  // ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
index 2006532..1f71cf2 100644
--- a/libappfuse/include/libappfuse/FuseBridgeLoop.h
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -20,21 +20,18 @@
 #include "libappfuse/FuseBuffer.h"
 
 namespace android {
+namespace fuse {
 
-class FuseBridgeLoop {
+class FuseBridgeLoopCallback {
  public:
-  class Callback {
-   public:
-    virtual void OnMount() = 0;
-    virtual ~Callback() = default;
-  };
-
-  bool Start(int dev_fd, int proxy_fd, Callback* callback);
-
- private:
-  FuseBuffer buffer_;
+  virtual void OnMount() = 0;
+  virtual ~FuseBridgeLoopCallback() = default;
 };
 
+bool StartFuseBridgeLoop(
+    int dev_fd, int proxy_fd, FuseBridgeLoopCallback* callback);
+
+}  // namespace fuse
 }  // namespace android
 
 #endif  // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 071b777..e7f620c 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -20,6 +20,7 @@
 #include <linux/fuse.h>
 
 namespace android {
+namespace fuse {
 
 // The numbers came from sdcard.c.
 // Maximum number of bytes to write/read in one request/one reply.
@@ -27,9 +28,9 @@
 constexpr size_t kFuseMaxRead = 128 * 1024;
 constexpr int32_t kFuseSuccess = 0;
 
-template<typename T, typename Header>
-struct FuseMessage {
-  Header header;
+template<typename T>
+class FuseMessage {
+ public:
   bool Read(int fd);
   bool Write(int fd) const;
  private:
@@ -37,33 +38,53 @@
   bool CheckResult(int result, const char* operation_name) const;
 };
 
-struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
+// FuseRequest represents file operation requests from /dev/fuse. It starts
+// from fuse_in_header. The body layout depends on the operation code.
+struct FuseRequest : public FuseMessage<FuseRequest> {
+  fuse_in_header header;
   union {
+    // for FUSE_WRITE
     struct {
       fuse_write_in write_in;
       char write_data[kFuseMaxWrite];
     };
+    // for FUSE_OPEN
     fuse_open_in open_in;
+    // for FUSE_INIT
     fuse_init_in init_in;
+    // for FUSE_READ
     fuse_read_in read_in;
+    // for FUSE_LOOKUP
     char lookup_name[0];
   };
+  void Reset(uint32_t data_length, uint32_t opcode, uint64_t unique);
 };
 
-struct FuseResponse : public FuseMessage<FuseResponse, fuse_out_header> {
+// FuseResponse represents file operation responses to /dev/fuse. It starts
+// from fuse_out_header. The body layout depends on the operation code.
+struct FuseResponse : public FuseMessage<FuseResponse> {
+  fuse_out_header header;
   union {
+    // for FUSE_INIT
     fuse_init_out init_out;
+    // for FUSE_LOOKUP
     fuse_entry_out entry_out;
+    // for FUSE_GETATTR
     fuse_attr_out attr_out;
+    // for FUSE_OPEN
     fuse_open_out open_out;
+    // for FUSE_READ
     char read_data[kFuseMaxRead];
+    // for FUSE_WRITE
     fuse_write_out write_out;
   };
   void Reset(uint32_t data_length, int32_t error, uint64_t unique);
   void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique);
 };
 
-union FuseBuffer {
+// To reduce memory usage, FuseBuffer shares the memory region for request and
+// response.
+union FuseBuffer final {
   FuseRequest request;
   FuseResponse response;
 
@@ -71,19 +92,7 @@
   void HandleNotImpl();
 };
 
-class FuseProxyLoop {
-  class IFuseProxyLoopCallback {
-   public:
-    virtual void OnMount() = 0;
-    virtual ~IFuseProxyLoopCallback() = default;
-  };
-
-  bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
-
- private:
-  FuseBuffer buffer_;
-};
-
+}  // namespace fuse
 }  // namespace android
 
 #endif  // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
new file mode 100644
index 0000000..25906cf
--- /dev/null
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/socket.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+namespace fuse {
+namespace {
+
+constexpr unsigned int kTestFileSize = 1024;
+
+struct CallbackRequest {
+  uint32_t code;
+  uint64_t inode;
+};
+
+class Callback : public FuseAppLoopCallback {
+ public:
+  std::vector<CallbackRequest> requests;
+
+  bool IsActive() override {
+    return true;
+  }
+
+  int64_t OnGetSize(uint64_t inode) override {
+    if (inode == FUSE_ROOT_ID) {
+      return 0;
+    } else {
+      return kTestFileSize;
+    }
+  }
+
+  int32_t OnFsync(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_FSYNC,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnWrite(uint64_t inode,
+                  uint64_t offset ATTRIBUTE_UNUSED,
+                  uint32_t size ATTRIBUTE_UNUSED,
+                  const void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_WRITE,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRead(uint64_t inode,
+                 uint64_t offset ATTRIBUTE_UNUSED,
+                 uint32_t size ATTRIBUTE_UNUSED,
+                 void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_READ,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnOpen(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_OPEN,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRelease(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_RELEASE,
+      .inode = inode
+    });
+    return 0;
+  }
+};
+
+class FuseAppLoopTest : public ::testing::Test {
+ private:
+  std::thread thread_;
+
+ protected:
+  base::unique_fd sockets_[2];
+  Callback callback_;
+  FuseRequest request_;
+  FuseResponse response_;
+
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets));
+    sockets_[0].reset(sockets[0]);
+    sockets_[1].reset(sockets[1]);
+    thread_ = std::thread([this] {
+      StartFuseAppLoop(sockets_[1].release(), &callback_);
+    });
+  }
+
+  void CheckCallback(
+      size_t data_size, uint32_t code, size_t expected_out_size) {
+    request_.Reset(data_size, code, 1);
+    request_.header.nodeid = 10;
+
+    ASSERT_TRUE(request_.Write(sockets_[0]));
+    ASSERT_TRUE(response_.Read(sockets_[0]));
+
+    Close();
+
+    EXPECT_EQ(kFuseSuccess, response_.header.error);
+    EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
+              response_.header.len);
+    EXPECT_EQ(1u, response_.header.unique);
+
+    ASSERT_EQ(1u, callback_.requests.size());
+    EXPECT_EQ(code, callback_.requests[0].code);
+    EXPECT_EQ(10u, callback_.requests[0].inode);
+  }
+
+  void Close() {
+    sockets_[0].reset();
+    sockets_[1].reset();
+    if (thread_.joinable()) {
+      thread_.join();
+    }
+  }
+
+  void TearDown() override {
+    Close();
+  }
+};
+
+}  // namespace
+
+TEST_F(FuseAppLoopTest, LookUp) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "10");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.entry_out.nodeid);
+  EXPECT_EQ(0u, response_.entry_out.generation);
+  EXPECT_EQ(10u, response_.entry_out.entry_valid);
+  EXPECT_EQ(10u, response_.entry_out.attr_valid);
+  EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
+  EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.entry_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
+  EXPECT_EQ(0u, response_.entry_out.attr.blocks);
+  EXPECT_EQ(0u, response_.entry_out.attr.atime);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtime);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctime);
+  EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
+  EXPECT_EQ(0u, response_.entry_out.attr.nlink);
+  EXPECT_EQ(0u, response_.entry_out.attr.uid);
+  EXPECT_EQ(0u, response_.entry_out.attr.gid);
+  EXPECT_EQ(0u, response_.entry_out.attr.rdev);
+  EXPECT_EQ(0u, response_.entry_out.attr.blksize);
+  EXPECT_EQ(0u, response_.entry_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "aa");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
+  request_.Reset(21u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "18446744073709551616");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = 10;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.attr_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr_Root) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
+  EXPECT_EQ(0u, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, Open) {
+  CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
+}
+
+TEST_F(FuseAppLoopTest, Fsync) {
+  CheckCallback(0u, FUSE_FSYNC, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Release) {
+  CheckCallback(0u, FUSE_RELEASE, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Read) {
+  CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Write) {
+  CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
index 31e3690..e74d9e7 100644
--- a/libappfuse/tests/FuseBridgeLoopTest.cc
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -21,11 +21,15 @@
 #include <sstream>
 #include <thread>
 
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 
 namespace android {
+namespace fuse {
+namespace {
 
-class Callback : public FuseBridgeLoop::Callback {
+class Callback : public FuseBridgeLoopCallback {
  public:
   bool mounted;
   Callback() : mounted(false) {}
@@ -36,20 +40,28 @@
 
 class FuseBridgeLoopTest : public ::testing::Test {
  protected:
-  int dev_sockets_[2];
-  int proxy_sockets_[2];
+  base::unique_fd dev_sockets_[2];
+  base::unique_fd proxy_sockets_[2];
   Callback callback_;
   std::thread thread_;
 
   FuseRequest request_;
   FuseResponse response_;
 
-  void SetUp() {
-    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
-    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int dev_sockets[2];
+    int proxy_sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets));
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets));
+    dev_sockets_[0].reset(dev_sockets[0]);
+    dev_sockets_[1].reset(dev_sockets[1]);
+    proxy_sockets_[0].reset(proxy_sockets[0]);
+    proxy_sockets_[1].reset(proxy_sockets[1]);
+
     thread_ = std::thread([this] {
-      FuseBridgeLoop loop;
-      loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
+      StartFuseBridgeLoop(
+          dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
     });
   }
 
@@ -103,20 +115,22 @@
   }
 
   void Close() {
-    close(dev_sockets_[0]);
-    close(dev_sockets_[1]);
-    close(proxy_sockets_[0]);
-    close(proxy_sockets_[1]);
+    dev_sockets_[0].reset();
+    dev_sockets_[1].reset();
+    proxy_sockets_[0].reset();
+    proxy_sockets_[1].reset();
     if (thread_.joinable()) {
       thread_.join();
     }
   }
 
-  void TearDown() {
+  void TearDown() override {
     Close();
   }
 };
 
+} //  namespace
+
 TEST_F(FuseBridgeLoopTest, FuseInit) {
   SendInitRequest(1u);
 
@@ -156,11 +170,11 @@
   CheckNotImpl(FUSE_RENAME);
   CheckNotImpl(FUSE_LINK);
   CheckNotImpl(FUSE_STATFS);
-  CheckNotImpl(FUSE_FSYNC);
   CheckNotImpl(FUSE_SETXATTR);
   CheckNotImpl(FUSE_GETXATTR);
   CheckNotImpl(FUSE_LISTXATTR);
   CheckNotImpl(FUSE_REMOVEXATTR);
+  CheckNotImpl(FUSE_FLUSH);
   CheckNotImpl(FUSE_OPENDIR);
   CheckNotImpl(FUSE_READDIR);
   CheckNotImpl(FUSE_RELEASEDIR);
@@ -186,11 +200,17 @@
 TEST_F(FuseBridgeLoopTest, Proxy) {
   CheckProxy(FUSE_LOOKUP);
   CheckProxy(FUSE_GETATTR);
-  CheckProxy(FUSE_OPEN);
   CheckProxy(FUSE_READ);
   CheckProxy(FUSE_WRITE);
+  CheckProxy(FUSE_FSYNC);
+
+  // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
+  CheckProxy(FUSE_OPEN);
   CheckProxy(FUSE_RELEASE);
-  CheckProxy(FUSE_FLUSH);
+
+  // Ensure the loop exits.
+  Close();
 }
 
-}  // android
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index 1aacfe3..c822135 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -24,6 +24,7 @@
 #include <gtest/gtest.h>
 
 namespace android {
+namespace fuse {
 
 constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
 
@@ -163,7 +164,7 @@
 
   buffer.HandleInit();
 
-  ASSERT_EQ(sizeof(fuse_out_header) + sizeof(fuse_init_out),
+  ASSERT_EQ(sizeof(fuse_out_header) + FUSE_COMPAT_22_INIT_OUT_SIZE,
             buffer.response.header.len);
   EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
   EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
@@ -183,5 +184,6 @@
   ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
   EXPECT_EQ(-ENOSYS, buffer.response.header.error);
 }
-}
-  // namespace android
+
+} // namespace fuse
+} // namespace android
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index 148c418..fd8b713 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -17,7 +17,6 @@
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
-#include <sys/uio.h>
 #include <sys/param.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
@@ -73,20 +72,42 @@
   if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
     return 0;
   }
+
   bytes = MIN(map.end - addr, bytes);
-
-  struct iovec local_io;
-  local_io.iov_base = buffer;
-  local_io.iov_len = bytes;
-
-  struct iovec remote_io;
-  remote_io.iov_base = reinterpret_cast<void*>(addr);
-  remote_io.iov_len = bytes;
-
-  ssize_t bytes_read = process_vm_readv(Tid(), &local_io, 1, &remote_io, 1, 0);
-  if (bytes_read == -1) {
-    return 0;
+  size_t bytes_read = 0;
+  word_t data_word;
+  size_t align_bytes = addr & (sizeof(word_t) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
+      return 0;
+    }
+    size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    buffer += copy_bytes;
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
   }
-  return static_cast<size_t>(bytes_read);
+
+  size_t num_words = bytes / sizeof(word_t);
+  for (size_t i = 0; i < num_words; i++) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, sizeof(word_t));
+    buffer += sizeof(word_t);
+    addr += sizeof(word_t);
+    bytes_read += sizeof(word_t);
+  }
+
+  size_t left_over = bytes & (sizeof(word_t) - 1);
+  if (left_over) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
 #endif
 }
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index f7b497d..39f8aba 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,6 +18,7 @@
 // they correspond to features not used by our host development tools
 // which are also hard or even impossible to port to native Win32
 libcutils_nonwindows_sources = [
+    "android_get_control_file.cpp",
     "fs.c",
     "multiuser.c",
     "socket_inaddr_any_server_unix.c",
@@ -34,7 +35,6 @@
     host_supported: true,
     srcs: [
         "config_utils.c",
-        "files.cpp",
         "fs_config.c",
         "canned_fs_config.c",
         "hashmap.c",
diff --git a/include/cutils/files.h b/libcutils/android_get_control_env.h
similarity index 63%
copy from include/cutils/files.h
copy to libcutils/android_get_control_env.h
index 0210e30..638c831 100644
--- a/include/cutils/files.h
+++ b/libcutils/android_get_control_env.h
@@ -14,24 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
 
-#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+/* To declare library function hidden and internal */
+#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/*
- * android_get_control_file - simple helper function to get the file
- * descriptor of our init-managed file. `path' is the filename path as
- * given in init.rc. Returns -1 on error.
- */
-int android_get_control_file(const char* path);
-
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name);
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
diff --git a/libcutils/files.cpp b/libcutils/android_get_control_file.cpp
similarity index 74%
rename from libcutils/files.cpp
rename to libcutils/android_get_control_file.cpp
index bf15b42..780d9f1 100644
--- a/libcutils/files.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -25,11 +25,6 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
-// This file contains files implementation that can be shared between
-// platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // for asprintf
-
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -41,17 +36,20 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
 
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
 #endif
 
-int android_get_control_file(const char* path) {
-    if (!path) return -1;
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name) {
+    if (!prefix || !name) return -1;
 
     char *key = NULL;
-    if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1;
+    if (asprintf(&key, "%s%s", prefix, name) < 0) return -1;
     if (!key) return -1;
 
     char *cp = key;
@@ -70,29 +68,33 @@
 
     // validity checking
     if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
-    if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
-    if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
-    if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
 
-#if defined(F_GETFD)
+    // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
+
+    // Still open?
+#if defined(F_GETFD) // Lowest overhead
     if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
+#elif defined(F_GETFL) // Alternate lowest overhead
     if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
+#else // Hail Mary pass
     struct stat s;
     if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
 #endif
 
+    return static_cast<int>(fd);
+}
+
+int android_get_control_file(const char* path) {
+    int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+
 #if defined(__linux__)
+    // Find file path from /proc and make sure it is correct
     char *proc = NULL;
-    if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
+    if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
     if (!proc) return -1;
 
     size_t len = strlen(path);
+    // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
     char *buf = static_cast<char *>(calloc(1, len + 2));
     if (!buf) {
         free(proc);
@@ -104,8 +106,8 @@
     free(buf);
     if (ret < 0) return -1;
     if (cmp != 0) return -1;
+    // It is what we think it is
 #endif
 
-    // It is what we think it is
-    return static_cast<int>(fd);
+    return fd;
 }
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 9d823cf..4bad28a 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,7 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 
 static int klog_level = KLOG_DEFAULT_LEVEL;
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index 63761a2..23a447b 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -28,33 +28,9 @@
 
 // This file contains socket implementation that can be shared between
 // platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // For asprintf
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#if !defined(_WIN32)
-#include <netinet/in.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#if !defined(_WIN32)
-#include <sys/un.h>
-#endif
-#include <unistd.h>
-
-#include <string>
 
 #include <cutils/sockets.h>
 
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
-#endif
-
 int socket_get_local_port(cutils_socket_t sock) {
     sockaddr_storage addr;
     socklen_t addr_size = sizeof(addr);
@@ -65,58 +41,3 @@
     }
     return -1;
 }
-
-int android_get_control_socket(const char* name) {
-    char *key = NULL;
-    if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1;
-    if (!key) return -1;
-
-    char *cp = key;
-    while (*cp) {
-        if (!isalnum(*cp)) *cp = '_';
-        ++cp;
-    }
-
-    const char* val = getenv(key);
-    free(key);
-    if (!val) return -1;
-
-    errno = 0;
-    long fd = strtol(val, NULL, 10);
-    if (errno) return -1;
-
-    // validity checking
-    if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
-    if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
-    if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
-    if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
-
-#if defined(F_GETFD)
-    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
-    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
-    struct stat s;
-    if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
-#endif
-
-#if !defined(_WIN32)
-    struct sockaddr_un addr;
-    socklen_t addrlen = sizeof(addr);
-    int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
-    if (ret < 0) return -1;
-    char *path = NULL;
-    if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1;
-    if (!path) return -1;
-    int cmp = strcmp(addr.sun_path, path);
-    free(path);
-    if (cmp != 0) return -1;
-#endif
-
-    // It is what we think it is
-    return static_cast<int>(fd);
-}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 3545403..5a14a5c 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -16,13 +16,25 @@
 
 #define LOG_TAG "socket-unix"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
 #include <sys/uio.h>
+#include <sys/un.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <android/log.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
+
 #if defined(__ANDROID__)
 /* For the socket trust (credentials) check */
 #include <private/android_filesystem_config.h>
@@ -80,3 +92,24 @@
 
     return writev(sock, iovec_buffers, num_buffers);
 }
+
+int android_get_control_socket(const char* name) {
+    int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
+
+    if (fd < 0) return fd;
+
+    // Compare to UNIX domain socket name, must match!
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+    int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+    if (ret < 0) return -1;
+    char *path = NULL;
+    if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
+    if (!path) return -1;
+    int cmp = strcmp(addr.sun_path, path);
+    free(path);
+    if (cmp != 0) return -1;
+
+    // It is what we think it is
+    return fd;
+}
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index ed6b1a7..3064c70 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -84,3 +84,7 @@
 
     return -1;
 }
+
+int android_get_control_socket(const char* name) {
+    return -1;
+}
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index bd35412..72e2eac 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -14,7 +14,7 @@
 
 cc_defaults {
     name: "libcutils_test_default",
-    srcs: ["sockets_test.cpp", "files_test.cpp"],
+    srcs: ["sockets_test.cpp"],
 
     target: {
         android: {
@@ -28,7 +28,11 @@
         },
 
         not_windows: {
-            srcs: ["test_str_parms.cpp"],
+            srcs: [
+                "test_str_parms.cpp",
+                "android_get_control_socket_test.cpp",
+                "android_get_control_file_test.cpp"
+            ],
         },
     },
 
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
new file mode 100644
index 0000000..6c6fd2a
--- /dev/null
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
+#include <gtest/gtest.h>
+
+TEST(FilesTest, android_get_control_file) {
+    TemporaryFile tf;
+    ASSERT_GE(tf.fd, 0);
+
+    std::string key(ANDROID_FILE_ENV_PREFIX);
+    key += tf.path;
+
+    std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+
+    EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+
+    EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+    close(tf.fd);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+}
diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/tests/android_get_control_socket_test.cpp
new file mode 100644
index 0000000..e586748
--- /dev/null
+++ b/libcutils/tests/android_get_control_socket_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <cutils/sockets.h>
+#include <gtest/gtest.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+TEST(SocketsTest, android_get_control_socket) {
+    static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
+    static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
+
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    int fd;
+    ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
+#ifdef F_GETFL
+    int flags;
+    ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
+    ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
+#endif
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    struct sockaddr_un addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
+    unlink(addr.sun_path);
+
+    EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    char val[32];
+    snprintf(val, sizeof(val), "%d", fd);
+    EXPECT_EQ(setenv(key, val, true), 0);
+
+    EXPECT_EQ(android_get_control_socket(name), fd);
+    socket_close(fd);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unlink(addr.sun_path), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+}
diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/files_test.cpp
deleted file mode 100644
index 1a7d673..0000000
--- a/libcutils/tests/files_test.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <cutils/files.h>
-#include <gtest/gtest.h>
-
-TEST(FilesTest, android_get_control_file) {
-    static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg";
-    static const char name[] = "/dev/kmsg";
-
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-
-    int fd;
-    ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-
-    char val[32];
-    snprintf(val, sizeof(val), "%d", fd);
-    EXPECT_EQ(setenv(key, val, true), 0);
-
-    EXPECT_EQ(android_get_control_file(name), fd);
-    close(fd);
-    EXPECT_EQ(android_get_control_file(name), -1);
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index adfbf4a..0441fb6 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,11 +18,9 @@
 // IPv6 capabilities. These tests assume that no UDP packets are lost, which
 // should be the case for loopback communication, but is not guaranteed.
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <sys/un.h>
 #include <time.h>
 
 #include <cutils/sockets.h>
@@ -189,49 +187,3 @@
 TEST(SocketsTest, TestSocketSendBuffersFailure) {
     EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
 }
-
-#ifndef SOCK_NONBLOCK
-#define SOCK_NONBLOCK 0
-#endif
-
-#ifndef SOCK_CLOEXEC
-#define SOCK_CLOEXEC 0
-#endif
-
-TEST(SocketsTest, android_get_control_socket) {
-    static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
-    static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
-
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    int fd;
-    ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
-#ifdef F_GETFL
-    int flags;
-    ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
-    ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
-#endif
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    struct sockaddr_un addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
-    unlink(addr.sun_path);
-
-    EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    char val[32];
-    snprintf(val, sizeof(val), "%d", fd);
-    EXPECT_EQ(setenv(key, val, true), 0);
-
-    EXPECT_EQ(android_get_control_socket(name), fd);
-    socket_close(fd);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-    EXPECT_EQ(unlink(addr.sun_path), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 16aa4fa..c498153 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -73,6 +73,9 @@
         linux: {
             host_ldlibs: ["-lrt"],
         },
+        linux_bionic: {
+            enabled: true,
+        },
     },
 
     cflags: [
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index f9cad99..e8e0335 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,12 +73,13 @@
     EventTagMap* newTagMap;
     off_t end;
     int save_errno;
+    const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
 
-    int fd = open(fileName, O_RDONLY | O_CLOEXEC);
+    int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         save_errno = errno;
         fprintf(stderr, "%s: unable to open map '%s': %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_errno;
     }
 
@@ -87,7 +88,7 @@
     (void) lseek(fd, 0L, SEEK_SET);
     if (end < 0) {
         fprintf(stderr, "%s: unable to seek map '%s' %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_close;
     }
 
@@ -103,7 +104,7 @@
     fd = -1;
     if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
         fprintf(stderr, "%s: mmap(%s) failed: %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
+                OUT_TAG, tagfile, strerror(save_errno));
         goto fail_free;
     }
 
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 11d8afb..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <log/log_event_list.h>
 #include <private/android_logger.h>
 
 #include "log_portability.h"
@@ -319,7 +320,7 @@
     context->storage[1] = context->count[0];
     len = context->len = context->pos;
     msg = (const char *)context->storage;
-    /* it'snot a list */
+    /* it's not a list */
     if (context->count[0] <= 1) {
         len -= sizeof(uint8_t) + sizeof(uint8_t);
         if (len < 0) {
@@ -332,6 +333,38 @@
         __android_log_security_bwrite(context->tag, msg, len);
 }
 
+LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
+                                                     const char **buffer) {
+    android_log_context_internal *context;
+    const char *msg;
+    ssize_t len;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+    if (buffer == NULL) {
+        return -EFAULT;
+    }
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char *)context->storage;
+    /* it's not a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+    *buffer = msg;
+    return len;
+}
+
 /*
  * Extract a 4-byte value from a byte stream.
  */
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 7262fc5..14d6482 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index c481e36..f19c3ab 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -48,7 +48,7 @@
 
 static int check_log_uid_permissions()
 {
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     uid_t uid = __android_log_uid();
 
     /* Matches clientHasLogCredentials() in logd */
@@ -130,7 +130,7 @@
     return kLogNotAvailable;
 }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
 static atomic_uintptr_t tagMap;
 #endif
 
@@ -140,7 +140,7 @@
 LIBLOG_ABI_PUBLIC void __android_log_close()
 {
     struct android_log_transport_write *transport;
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     EventTagMap *m;
 #endif
 
@@ -170,7 +170,7 @@
         }
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     /*
      * Additional risk here somewhat mitigated by immediately unlock flushing
      * the processor cache. The multi-threaded race that we choose to accept,
@@ -188,8 +188,8 @@
 
     __android_log_unlock();
 
-#if defined(__BIONIC__)
-    android_closeEventTagMap(m);
+#if defined(__ANDROID__)
+    if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
 #endif
 
 }
@@ -261,7 +261,7 @@
         return -EINVAL;
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     if (log_id == LOG_ID_SECURITY) {
         if (vec[0].iov_len < 4) {
             return -EINVAL;
@@ -293,7 +293,7 @@
             ret = __android_log_trylock();
             m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
             if (!m) {
-                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+                m = android_openEventTagMap(NULL);
                 if (ret) { /* trylock failed, use local copy, mark for close */
                     f = m;
                 } else {
diff --git a/liblog/logprint.c b/liblog/logprint.c
index fb942a1..da80e36 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -632,8 +632,8 @@
     size_t len;
     int64_t lval;
 
-    if (eventDataLen < 1)
-        return -1;
+    if (eventDataLen < 1) return -1;
+
     type = *eventData++;
     eventDataLen--;
 
@@ -729,8 +729,7 @@
         {
             int32_t ival;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
@@ -740,8 +739,7 @@
         goto pr_lval;
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
-        if (eventDataLen < 8)
-            return -1;
+        if (eventDataLen < 8) return -1;
         lval = get8LE(eventData);
         eventData += 8;
         eventDataLen -= 8;
@@ -761,8 +759,7 @@
             uint32_t ival;
             float fval;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             fval = *(float*)&ival;
             eventData += 4;
@@ -783,14 +780,12 @@
         {
             unsigned int strLen;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             strLen = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
 
-            if (eventDataLen < strLen)
-                return -1;
+            if (eventDataLen < strLen) return -1;
 
             if (cp && (strLen == 0)) {
                 /* reset the format if no content */
@@ -818,41 +813,32 @@
             unsigned char count;
             int i;
 
-            if (eventDataLen < 1)
-                return -1;
+            if (eventDataLen < 1) return -1;
 
             count = *eventData++;
             eventDataLen--;
 
-            if (outBufLen > 0) {
-                *outBuf++ = '[';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = '[';
+            outBufLen--;
 
             for (i = 0; i < count; i++) {
                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
                         &outBuf, &outBufLen, fmtStr, fmtLen);
-                if (result != 0)
-                    goto bail;
+                if (result != 0) goto bail;
 
-                if (i < count-1) {
-                    if (outBufLen > 0) {
-                        *outBuf++ = ',';
-                        outBufLen--;
-                    } else {
-                        goto no_room;
-                    }
+                if (i < (count - 1)) {
+                    if (outBufLen <= 0) goto no_room;
+                    *outBuf++ = ',';
+                    outBufLen--;
                 }
             }
 
-            if (outBufLen > 0) {
-                *outBuf++ = ']';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = ']';
+            outBufLen--;
         }
         break;
     default:
@@ -997,8 +983,7 @@
         }
     }
     inCount = buf->len;
-    if (inCount < 4)
-        return -1;
+    if (inCount < 4) return -1;
     tagIndex = get4LE(eventData);
     eventData += 4;
     inCount -= 4;
@@ -1031,16 +1016,20 @@
     /*
      * Format the event log data into the buffer.
      */
-    char* outBuf = messageBuf;
-    size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
-    int result;
     const char* fmtStr = NULL;
     size_t fmtLen = 0;
     if (descriptive_output && map) {
         fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
     }
-    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
-                &outRemaining, &fmtStr, &fmtLen);
+
+    char* outBuf = messageBuf;
+    size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
+    int result = 0;
+
+    if ((inCount > 0) || fmtLen) {
+        result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+                                              &outRemaining, &fmtStr, &fmtLen);
+    }
     if ((result == 1) && fmtStr) {
         /* We overflowed :-(, let's repaint the line w/o format dressings */
         eventData = (const unsigned char*)buf->msg;
@@ -1055,18 +1044,18 @@
     }
     if (result < 0) {
         fprintf(stderr, "Binary log entry conversion failed\n");
-        return -1;
-    } else if (result == 1) {
-        if (outBuf > messageBuf) {
-            /* leave an indicator */
-            *(outBuf-1) = '!';
-        } else {
-            /* no room to output anything at all */
-            *outBuf++ = '!';
-            outRemaining--;
+    }
+    if (result) {
+        if (!outRemaining) {
+            /* make space to leave an indicator */
+            --outBuf;
+            ++outRemaining;
         }
-        /* pretend we ate all the data */
+        *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
+        outRemaining--;
+        /* pretend we ate all the data to prevent log stutter */
         inCount = 0;
+        if (result > 0) result = 0;
     }
 
     /* eat the silly terminating '\n' */
@@ -1090,7 +1079,7 @@
 
     entry->message = messageBuf;
 
-    return 0;
+    return result;
 }
 
 /*
@@ -1802,8 +1791,7 @@
     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
             sizeof(defaultBuffer), entry, &totalLen);
 
-    if (!outBuffer)
-        return -1;
+    if (!outBuffer) return -1;
 
     do {
         ret = write(fd, outBuffer, totalLen);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9c09523..02a572d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -33,6 +33,7 @@
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <log/logprint.h>
+#include <log/log_event_list.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -328,6 +329,9 @@
             EXPECT_TRUE(NULL != logformat);
             AndroidLogEntry entry;
             char msgBuf[1024];
+            if (length != total) {
+                fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
+            }
             int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
                 &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
             EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
@@ -2647,6 +2651,19 @@
     ASSERT_TRUE(NULL == ctx);
 }
 
+TEST(liblog, android_log_write_list_buffer) {
+    __android_log_event_list ctx(1005);
+    ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
+    std::string buffer(ctx);
+    ctx.close();
+
+    char msgBuf[1024];
+    memset(msgBuf, 0, sizeof(msgBuf));
+    EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
+                                           msgBuf, sizeof(msgBuf)), 0);
+    EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
+}
+
 static const char __pmsg_file[] =
         "/data/william-shakespeare/MuchAdoAboutNothing.txt";
 
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 7c15429..eb66727 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -31,12 +31,15 @@
 #include <chrono>
 #include <memory>
 #include <mutex>
+#include <thread>
 
 #include <android-base/logging.h>
 #include <private/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
+using namespace std::chrono_literals;
+
 // Uncomment line below use memory cgroups for keeping track of (forked) PIDs
 // #define USE_MEMCG 1
 
@@ -288,7 +291,7 @@
     while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
         LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
         if (retry > 0) {
-            usleep(5 * 1000); // 5ms
+            std::this_thread::sleep_for(5ms);
             --retry;
         } else {
             LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
new file mode 100644
index 0000000..b8c6428
--- /dev/null
+++ b/libprocinfo/.clang-format
@@ -0,0 +1,14 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
new file mode 100644
index 0000000..8e17f1b
--- /dev/null
+++ b/libprocinfo/Android.bp
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+libprocinfo_cppflags = [
+    "-Wall",
+    "-Wextra",
+    "-Werror",
+]
+
+cc_library {
+    name: "libprocinfo",
+    host_supported: true,
+    srcs: [
+        "process.cpp",
+    ],
+    cppflags: libprocinfo_cppflags,
+
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libbase"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+}
+
+// Tests
+// ------------------------------------------------------------------------------
+cc_test {
+    name: "libprocinfo_test",
+    host_supported: true,
+    srcs: [
+        "process_test.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+
+    cppflags: libprocinfo_cppflags,
+    shared_libs: ["libbase", "libprocinfo"],
+
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
new file mode 100644
index 0000000..fb140ff
--- /dev/null
+++ b/libprocinfo/include/procinfo/process.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace procinfo {
+
+#if defined(__linux__)
+
+struct ProcessInfo {
+  std::string name;
+  pid_t tid;
+  pid_t pid;
+  pid_t ppid;
+  pid_t tracer;
+  uid_t uid;
+  uid_t gid;
+};
+
+// Parse the contents of /proc/<tid>/status into |process_info|.
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+
+// Parse the contents of <fd>/status into |process_info|.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+
+// Fetch the list of threads from a given process's /proc/<pid> directory.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+template <typename Collection>
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+    typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+  out->clear();
+
+  int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
+  if (!dir) {
+    PLOG(ERROR) << "failed to open task directory";
+    return false;
+  }
+
+  struct dirent* dent;
+  while ((dent = readdir(dir.get()))) {
+    if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
+      pid_t tid;
+      if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
+        LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+        return false;
+      }
+
+      out->insert(out->end(), tid);
+    }
+  }
+
+  return true;
+}
+
+template <typename Collection>
+auto GetProcessTids(pid_t pid, Collection* out) ->
+    typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+  char task_path[PATH_MAX];
+  if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
+    LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+    return false;
+  }
+
+  android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    PLOG(ERROR) << "failed to open " << task_path;
+    return false;
+  }
+
+  return GetProcessTidsFromProcPidFd(fd.get(), out);
+}
+
+#endif
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
new file mode 100644
index 0000000..c513e16
--- /dev/null
+++ b/libprocinfo/process.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+namespace android {
+namespace procinfo {
+
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+  char path[PATH_MAX];
+  snprintf(path, sizeof(path), "/proc/%d", tid);
+
+  unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
+  if (dirfd == -1) {
+    PLOG(ERROR) << "failed to open " << path;
+    return false;
+  }
+
+  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+}
+
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+  int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
+
+  if (status_fd == -1) {
+    PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+    return false;
+  }
+
+  std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
+  if (!fp) {
+    PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+    close(status_fd);
+    return false;
+  }
+
+  int field_bitmap = 0;
+  static constexpr int finished_bitmap = 127;
+  char* line = nullptr;
+  size_t len = 0;
+
+  while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) {
+    char* tab = strchr(line, '\t');
+    if (tab == nullptr) {
+      continue;
+    }
+
+    size_t header_len = tab - line;
+    std::string header = std::string(line, header_len);
+    if (header == "Name:") {
+      std::string name = line + header_len + 1;
+
+      // line includes the trailing newline.
+      name.pop_back();
+      process_info->name = std::move(name);
+
+      field_bitmap |= 1;
+    } else if (header == "Pid:") {
+      process_info->tid = atoi(tab + 1);
+      field_bitmap |= 2;
+    } else if (header == "Tgid:") {
+      process_info->pid = atoi(tab + 1);
+      field_bitmap |= 4;
+    } else if (header == "PPid:") {
+      process_info->ppid = atoi(tab + 1);
+      field_bitmap |= 8;
+    } else if (header == "TracerPid:") {
+      process_info->tracer = atoi(tab + 1);
+      field_bitmap |= 16;
+    } else if (header == "Uid:") {
+      process_info->uid = atoi(tab + 1);
+      field_bitmap |= 32;
+    } else if (header == "Gid:") {
+      process_info->gid = atoi(tab + 1);
+      field_bitmap |= 64;
+    }
+  }
+
+  free(line);
+  return field_bitmap == finished_bitmap;
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
new file mode 100644
index 0000000..5ffd236
--- /dev/null
+++ b/libprocinfo/process_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <set>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+
+#if !defined(__BIONIC__)
+#include <syscall.h>
+static pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+#endif
+
+TEST(process_info, process_info_smoke) {
+  android::procinfo::ProcessInfo self;
+  ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
+  ASSERT_EQ(gettid(), self.tid);
+  ASSERT_EQ(getpid(), self.pid);
+  ASSERT_EQ(getppid(), self.ppid);
+  ASSERT_EQ(getuid(), self.uid);
+  ASSERT_EQ(getgid(), self.gid);
+}
+
+TEST(process_info, process_info_proc_pid_fd_smoke) {
+  android::procinfo::ProcessInfo self;
+  int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
+
+  // Process name is capped at 15 bytes.
+  ASSERT_EQ("libprocinfo_tes", self.name);
+  ASSERT_EQ(gettid(), self.tid);
+  ASSERT_EQ(getpid(), self.pid);
+  ASSERT_EQ(getppid(), self.ppid);
+  ASSERT_EQ(getuid(), self.uid);
+  ASSERT_EQ(getgid(), self.gid);
+  close(fd);
+}
+
+TEST(process_info, process_tids_smoke) {
+  pid_t main_tid = gettid();
+  std::thread([main_tid]() {
+    pid_t thread_tid = gettid();
+
+    {
+      std::vector<pid_t> vec;
+      ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
+      ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
+      ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
+    }
+
+    {
+      std::set<pid_t> set;
+      ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
+      ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
+      ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
+    }
+  }).join();
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 25c779e..217b8c3 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -86,6 +86,13 @@
                 "ProcessCallStack.cpp",
             ],
         },
+        linux_bionic: {
+            enabled: true,
+            srcs: [
+                "Looper.cpp",
+                "ProcessCallStack.cpp",
+            ],
+        },
 
         darwin: {
             cflags: ["-Wno-unused-parameter"],
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 5ed0fe8..fce1378 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -62,7 +62,17 @@
         android: {
             static_libs: ["libz"],
         },
-        host: {
+        linux_bionic: {
+            static_libs: ["libz"],
+            enabled: true,
+        },
+        linux: {
+            shared_libs: ["libz-host"],
+        },
+        darwin: {
+            shared_libs: ["libz-host"],
+        },
+        windows: {
             shared_libs: ["libz-host"],
         },
     },
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index d36cc3f..e6e0276 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -781,7 +781,8 @@
   // Creates a FileWriter for |fd| and prepare to write |entry| to it,
   // guaranteeing that the file descriptor is valid and that there's enough
   // space on the volume to write out the entry completely and that the file
-  // is truncated to the correct length.
+  // is truncated to the correct length (no truncation if |fd| references a
+  // block device).
   //
   // Returns a valid FileWriter on success, |nullptr| if an error occurred.
   static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
@@ -814,13 +815,22 @@
     }
 #endif  // __linux__
 
-    result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-    if (result == -1) {
-      ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-            static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+    struct stat sb;
+    if (fstat(fd, &sb) == -1) {
+      ALOGW("Zip: unable to fstat file: %s", strerror(errno));
       return std::unique_ptr<FileWriter>(nullptr);
     }
 
+    // Block device doesn't support ftruncate(2).
+    if (!S_ISBLK(sb.st_mode)) {
+      result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+      if (result == -1) {
+        ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        return std::unique_ptr<FileWriter>(nullptr);
+      }
+    }
+
     return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
   }
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d0c693d..94b8691 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -81,6 +81,7 @@
 static size_t g_maxCount;
 static size_t g_printCount;
 static bool g_printItAnyways;
+static bool g_debug;
 
 enum helpType {
     HELP_FALSE,
@@ -176,7 +177,7 @@
         static EventTagMap *eventTagMap = NULL;
 
         if (!eventTagMap && !hasOpenedEventTagMap) {
-            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            eventTagMap = android_openEventTagMap(NULL);
             hasOpenedEventTagMap = true;
         }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
@@ -188,7 +189,7 @@
     } else {
         err = android_log_processLogBuffer(&buf->entry_v1, &entry);
     }
-    if (err < 0) {
+    if ((err < 0) && !g_debug) {
         goto error;
     }
 
@@ -619,6 +620,7 @@
         int option_index = 0;
         // list of long-argument only strings for later comparison
         static const char pid_str[] = "pid";
+        static const char debug_str[] = "debug";
         static const char id_str[] = "id";
         static const char wrap_str[] = "wrap";
         static const char print_str[] = "print";
@@ -627,6 +629,7 @@
           { "buffer",        required_argument, NULL,   'b' },
           { "buffer-size",   optional_argument, NULL,   'g' },
           { "clear",         no_argument,       NULL,   'c' },
+          { debug_str,       no_argument,       NULL,   0 },
           { "dividers",      no_argument,       NULL,   'D' },
           { "file",          required_argument, NULL,   'f' },
           { "format",        required_argument, NULL,   'v' },
@@ -691,6 +694,10 @@
                     g_printItAnyways = true;
                     break;
                 }
+                if (long_options[option_index].name == debug_str) {
+                    g_debug = true;
+                    break;
+                }
                 if (long_options[option_index].name == id_str) {
                     setId = optarg && optarg[0] ? optarg : NULL;
                     break;
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 18067dc..11cffe6 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -29,6 +29,7 @@
 
 #include <gtest/gtest.h>
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #define BIG_BUFFER (5 * 1024)
 
@@ -1091,7 +1092,7 @@
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *hold = *list;
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1126,7 +1127,7 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1255,19 +1256,25 @@
     va_end(ap);
 
     char *str = NULL;
-    asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+    asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
     std::string expect(str);
     free(str);
 
     int count = 0;
     pid_t pid = getpid();
     std::string lastMatch;
+    int maxMatch = 1;
     while (fgets(buffer, sizeof(buffer), fp)) {
+        char space;
         char newline;
         int p;
-        int ret = sscanf(buffer, expect.c_str(), &p, &newline);
-        if ((2 == ret) && (p == pid) && (newline == '\n')) ++count;
-        else if ((1 == ret) && (p == pid) && (count == 0)) lastMatch = buffer;
+        int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
+        if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
+            ++count;
+        } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
+            lastMatch = buffer;
+            maxMatch = ret;
+        }
     }
 
     pclose(fp);
@@ -1289,7 +1296,7 @@
 
     {
         static const struct tag hhgtg = { 42, "answer" };
-        android_log_event_context ctx(hhgtg.tagNo);
+        android_log_event_list ctx(hhgtg.tagNo);
         static const char theAnswer[] = "what is five by seven";
         ctx << theAnswer;
         ctx.write();
@@ -1301,7 +1308,7 @@
         static const struct tag sync = { 2720, "sync" };
         static const char id[] = "logcat.decriptive";
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1311,7 +1318,7 @@
 
         // Partial match to description
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1321,7 +1328,7 @@
 
         // Negative Test of End_to_End, ensure it is working
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
             ctx.write();
             fprintf(stderr, "Expect a \"Closest match\" message\n");
@@ -1334,7 +1341,7 @@
     {
         static const struct tag sync = { 2747, "contacts_aggregation" };
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)30 << (int32_t)2;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1342,7 +1349,7 @@
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)31570 << (int32_t)911;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1353,46 +1360,52 @@
     {
         static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)512;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3072;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097152;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097153;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)1073741824;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
         }
     }
 
+    {
+        static const struct tag sync = { 27501, "notification_panel_hidden" };
+        android_log_event_list ctx(sync.tagNo);
+        ctx.write();
+        EXPECT_TRUE(End_to_End(sync.tagStr, ""));
+    }
 }
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 7394f11..52c6742 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -48,6 +48,7 @@
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
     registerCmd(new ReinitCmd());
+    registerCmd(new ExitCmd(this));
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
@@ -297,6 +298,21 @@
     return 0;
 }
 
+CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
+        LogCommand("EXIT"),
+        mParent(*parent) {
+}
+
+int CommandListener::ExitCmd::runCommand(SocketClient * cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+
+    cli->sendMsg("success");
+    release(cli);
+
+    return 0;
+}
+
 int CommandListener::getLogSocket() {
     static const char socketName[] = "logd";
     int sock = android_get_control_socket(socketName);
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index cbcd601..5d50177 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -52,22 +52,38 @@
         explicit name##Cmd(LogBuffer *buf);                      \
         virtual ~name##Cmd() {}                                  \
         int runCommand(SocketClient *c, int argc, char ** argv); \
-    };
+    }
 
-    LogBufferCmd(Clear)
-    LogBufferCmd(GetBufSize)
-    LogBufferCmd(SetBufSize)
-    LogBufferCmd(GetBufSizeUsed)
-    LogBufferCmd(GetStatistics)
-    LogBufferCmd(GetPruneList)
-    LogBufferCmd(SetPruneList)
+    LogBufferCmd(Clear);
+    LogBufferCmd(GetBufSize);
+    LogBufferCmd(SetBufSize);
+    LogBufferCmd(GetBufSizeUsed);
+    LogBufferCmd(GetStatistics);
+    LogBufferCmd(GetPruneList);
+    LogBufferCmd(SetPruneList);
 
-    class ReinitCmd : public LogCommand {
-    public:
-        ReinitCmd();
-        virtual ~ReinitCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
+#define LogCmd(name)                                             \
+    class name##Cmd : public LogCommand {                        \
+    public:                                                      \
+        name##Cmd();                                             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+    }
+
+    LogCmd(Reinit);
+
+#define LogParentCmd(name)                                       \
+    class name##Cmd : public LogCommand {                        \
+        CommandListener &mParent;                                \
+    public:                                                      \
+        name##Cmd();                                             \
+        explicit name##Cmd(CommandListener *parent);             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+        void release(SocketClient *c) { mParent.release(c); }    \
+    }
+
+    LogParentCmd(Exit);
 
 };
 
diff --git a/logd/main.cpp b/logd/main.cpp
index d698976..c3343d7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -37,9 +37,9 @@
 #include <memory>
 
 #include <android-base/macros.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <cutils/files.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
@@ -311,7 +311,7 @@
     if (!map) {
         sem_wait(&sem_name);
         if (!map) {
-            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            map = android_openEventTagMap(NULL);
         }
         sem_post(&sem_name);
         if (!map) {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e060a2c..0fc701a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -56,6 +56,7 @@
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
+    ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
     ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
     ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
 ifdef BOARD_USES_VENDORIMAGE
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4c49791..ecc3ccd 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -293,11 +293,8 @@
     mount none /mnt/runtime/default /storage slave bind rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
-    restorecon_recursive /sys/kernel/debug
-
-    # On systems with tracefs, tracing is a separate mount, so make sure
-    # it too is correctly labeled
-    restorecon_recursive /sys/kernel/debug/tracing
+    # Note that tracefs may be mounted under debug, so we need to cross filesystems
+    restorecon --recursive --cross-filesystems /sys/kernel/debug
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -433,10 +430,6 @@
 
     mkdir /data/anr 0775 system system
 
-    # symlink to bugreport storage location
-    rm /data/bugreports
-    symlink /data/user_de/0/com.android.shell/files/bugreports /data/bugreports
-
     # Create all remaining /data root dirs so that they are made through init
     # and get proper encryption policy installed
     mkdir /data/backup 0700 system system
@@ -462,7 +455,7 @@
     init_user0
 
     # Set SELinux security contexts on upgrade or policy update.
-    restorecon_recursive /data
+    restorecon --recursive --skip-ce /data
 
     # Check any timezone data in /data is newer than the copy in /system, delete if not.
     exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
@@ -566,7 +559,7 @@
 
 on nonencrypted
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier nonencrypted
+    exec - root cache -- /system/bin/update_verifier nonencrypted
     class_start main
     class_start late_start
 
@@ -589,12 +582,12 @@
 
 on property:vold.decrypt=trigger_restart_min_framework
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+    exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier trigger_restart_framework
+    exec - root cache -- /system/bin/update_verifier trigger_restart_framework
     class_start main
     class_start late_start
 
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index d4c51fd..9393846 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -1262,12 +1262,9 @@
 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
     /* FUSE_KERNEL_VERSION >= 23. */
 
-    /* If the kernel only works on minor revs older than or equal to 22,
-     * then use the older structure size since this code only uses the 7.22
-     * version of the structure. */
-    if (req->minor <= 22) {
-        fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-    }
+    /* Since we return minor version 15, the kernel does not accept the latest
+     * fuse_init_out size. We need to use FUSE_COMPAT_22_INIT_OUT_SIZE always.*/
+    fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
 #endif
 
     out.major = FUSE_KERNEL_VERSION;
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index bc502a0..df3ce85 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -331,6 +331,27 @@
     return true;
 }
 
+static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
+                                        gid_t gid, mode_t mask) {
+    std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
+
+    if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
+            MS_BIND, nullptr) != 0) {
+        PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
+        return false;
+    }
+
+    if (mount(source_path.c_str(), dest_path.c_str(), "none",
+            MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+        if (umount2(dest_path.c_str(), MNT_DETACH))
+            PLOG(WARNING) << "Failed to unmount bind";
+        return false;
+    }
+
+    return true;
+}
+
 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
         gid_t gid, userid_t userid, bool multi_user, bool full_write) {
     std::string dest_path_default = "/mnt/runtime/default/" + label;
@@ -343,9 +364,8 @@
         // permissions are completely masked off.
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, 0027)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027)
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0027)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
@@ -355,9 +375,9 @@
         // deep inside attr_from_stat().
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read,
                                                       AID_EVERYBODY, full_write ? 0027 : 0022)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0022)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5319ff4..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -81,15 +81,6 @@
 $(INPUT_H_LABELS_H):
 	$(transform-generated-source)
 
-# We only want 'r' on userdebug and eng builds.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := r.c
-LOCAL_CFLAGS += $(common_cflags)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_MODULE := r
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
-
 
 # We build BSD grep separately, so it can provide egrep and fgrep too.
 include $(CLEAR_VARS)
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 30053af..e6def6b 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -9,6 +9,7 @@
 #include <sys/limits.h>
 #include <sys/poll.h>
 #include <linux/input.h>
+#include <err.h>
 #include <errno.h>
 #include <unistd.h>
 
@@ -110,10 +111,8 @@
                 break;
             bits_size = res + 16;
             bits = realloc(bits, bits_size * 2);
-            if(bits == NULL) {
-                fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
-                return 1;
-            }
+            if(bits == NULL)
+                err(1, "failed to allocate buffer of size %d\n", (int)bits_size);
         }
         res2 = 0;
         switch(i) {
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27ea9e8..d7047e2 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -741,6 +741,7 @@
                 exit(1);
             }
         }
+        free(img);
     }
     return 0;
 }
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
-    fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
-    return -1;
-}
-
-int main(int argc, char *argv[])
-{
-    if(argc < 2) return usage();
-
-    int width = 4;
-    if(!strcmp(argv[1], "-b")) {
-        width = 1;
-        argc--;
-        argv++;
-    } else if(!strcmp(argv[1], "-s")) {
-        width = 2;
-        argc--;
-        argv++;
-    }
-
-    if(argc < 2) return usage();
-    uintptr_t addr = strtoptr(argv[1], 0, 16);
-
-    uintptr_t endaddr = 0;
-    char* end = strchr(argv[1], '-');
-    if (end)
-        endaddr = strtoptr(end + 1, 0, 16);
-
-    if (!endaddr)
-        endaddr = addr + width - 1;
-
-    if (endaddr <= addr) {
-        fprintf(stderr, "end address <= start address\n");
-        return -1;
-    }
-
-    bool set = false;
-    uint32_t value = 0;
-    if(argc > 2) {
-        set = true;
-        value = strtoul(argv[2], 0, 16);
-    }
-
-    int fd = open("/dev/mem", O_RDWR | O_SYNC);
-    if(fd < 0) {
-        fprintf(stderr,"cannot open /dev/mem\n");
-        return -1;
-    }
-
-    off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
-    size_t mmap_size = endaddr - mmap_start + 1;
-    mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-    void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
-                        MAP_SHARED, fd, mmap_start);
-
-    if(page == MAP_FAILED){
-        fprintf(stderr,"cannot mmap region\n");
-        return -1;
-    }
-
-    while (addr <= endaddr) {
-        switch(width){
-        case 4: {
-            uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
-            break;
-        }
-        case 2: {
-            uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
-            break;
-        }
-        case 1: {
-            uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
-            break;
-        }
-        }
-        addr += width;
-    }
-    return 0;
-}