Merge "Revert "Switch sdcardfs over to bind mounts.""
diff --git a/adb/Android.mk b/adb/Android.mk
index 0114ca3..be04cfa 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -18,11 +18,9 @@
     -DADB_REVISION='"$(adb_version)"' \
 
 ADB_COMMON_linux_CFLAGS := \
-    -std=c++14 \
     -Wexit-time-destructors \
 
 ADB_COMMON_darwin_CFLAGS := \
-    -std=c++14 \
     -Wexit-time-destructors \
 
 # Define windows.h and tchar.h Unicode preprocessor symbols so that
@@ -45,7 +43,6 @@
 # get enough of adb in here that we no longer need minadb. https://b/17626262
 LIBADB_SRC_FILES := \
     adb.cpp \
-    adb_auth.cpp \
     adb_io.cpp \
     adb_listeners.cpp \
     adb_trace.cpp \
@@ -103,7 +100,7 @@
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
-    adb_auth_client.cpp \
+    adbd_auth.cpp \
     jdwp_service.cpp \
     usb_linux_client.cpp \
 
@@ -324,7 +321,6 @@
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_C_INCLUDES += system/extras/ext4_utils
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_STRIP_MODULE := keep_symbols
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 9ae3f1c..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() {
@@ -94,6 +97,18 @@
     abort();
 }
 
+uint32_t calculate_apacket_checksum(const apacket* p) {
+    const unsigned char* x = reinterpret_cast<const unsigned char*>(p->data);
+    uint32_t sum = 0;
+    size_t count = p->msg.data_length;
+
+    while (count-- > 0) {
+        sum += *x++;
+    }
+
+    return sum;
+}
+
 apacket* get_apacket(void)
 {
     apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
@@ -351,19 +366,31 @@
         break;
 
     case A_AUTH:
-        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
-            t->connection_state = kCsUnauthorized;
-            send_auth_response(p->data, p->msg.data_length, t);
-        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
-            if (adb_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
-                adb_auth_verified(t);
-                t->failed_auth_attempts = 0;
-            } else {
-                if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
-                send_auth_request(t);
-            }
-        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
-            adb_auth_confirm_key(p->data, p->msg.data_length, t);
+        switch (p->msg.arg0) {
+#if ADB_HOST
+            case ADB_AUTH_TOKEN:
+                t->connection_state = kCsUnauthorized;
+                send_auth_response(p->data, p->msg.data_length, t);
+                break;
+#else
+            case ADB_AUTH_SIGNATURE:
+                if (adbd_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
+                    adbd_auth_verified(t);
+                    t->failed_auth_attempts = 0;
+                } else {
+                    if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
+                    send_auth_request(t);
+                }
+                break;
+
+            case ADB_AUTH_RSAPUBLICKEY:
+                adbd_auth_confirm_key(p->data, p->msg.data_length, t);
+                break;
+#endif
+            default:
+                t->connection_state = kCsOffline;
+                handle_offline(t);
+                break;
         }
         break;
 
@@ -1065,6 +1092,31 @@
         return 1;
     }
 
+    if (!strcmp(service, "reconnect-offline")) {
+        std::string response;
+        close_usb_devices([&response](const atransport* transport) {
+            switch (transport->connection_state) {
+                case kCsOffline:
+                case kCsUnauthorized:
+                    response += "reconnecting ";
+                    if (transport->serial) {
+                        response += transport->serial;
+                    } else {
+                        response += "<unknown>";
+                    }
+                    response += "\n";
+                    return true;
+                default:
+                    return false;
+            }
+        });
+        if (!response.empty()) {
+            response.resize(response.size() - 1);
+        }
+        SendOkay(reply_fd, response);
+        return 0;
+    }
+
     if (!strcmp(service, "features")) {
         std::string error;
         atransport* t = acquire_one_transport(type, serial, nullptr, &error);
diff --git a/adb/adb.h b/adb/adb.h
index 0b9fe5b..df59aaa 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -18,6 +18,7 @@
 #define __ADB_H
 
 #include <limits.h>
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <string>
@@ -56,25 +57,27 @@
 struct usb_handle;
 
 struct amessage {
-    unsigned command;       /* command identifier constant      */
-    unsigned arg0;          /* first argument                   */
-    unsigned arg1;          /* second argument                  */
-    unsigned data_length;   /* length of payload (0 is allowed) */
-    unsigned data_check;    /* checksum of data payload         */
-    unsigned magic;         /* command ^ 0xffffffff             */
+    uint32_t command;     /* command identifier constant      */
+    uint32_t arg0;        /* first argument                   */
+    uint32_t arg1;        /* second argument                  */
+    uint32_t data_length; /* length of payload (0 is allowed) */
+    uint32_t data_check;  /* checksum of data payload         */
+    uint32_t magic;       /* command ^ 0xffffffff             */
 };
 
 struct apacket
 {
     apacket *next;
 
-    unsigned len;
-    unsigned char *ptr;
+    size_t len;
+    char* ptr;
 
     amessage msg;
-    unsigned char data[MAX_PAYLOAD];
+    char data[MAX_PAYLOAD];
 };
 
+uint32_t calculate_apacket_checksum(const apacket* packet);
+
 /* the adisconnect structure is used to record a callback that
 ** will be called whenever a transport is disconnected (e.g. by the user)
 ** this should be used to cleanup objects that depend on the
@@ -136,8 +139,10 @@
 int  init_socket_transport(atransport *t, int s, int port, int local);
 void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
 
+std::string getEmulatorSerialString(int console_port);
 #if ADB_HOST
 atransport* find_emulator_transport_by_adb_port(int adb_port);
+atransport* find_emulator_transport_by_console_port(int console_port);
 #endif
 
 int service_to_fd(const char* name, const atransport* transport);
@@ -199,7 +204,7 @@
 
 // USB device detection.
 #if ADB_HOST
-int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
 ConnectionState connection_state(atransport *t);
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
deleted file mode 100644
index 0b07158..0000000
--- a/adb/adb_auth.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.
- */
-
-#define TRACE_TAG ADB
-
-#include "adb.h"
-#include "adb_auth.h"
-#include "transport.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-bool auth_required = true;
-
-void send_auth_request(atransport *t)
-{
-    LOG(INFO) << "Calling send_auth_request...";
-
-    if (!adb_auth_generate_token(t->token, sizeof(t->token))) {
-        PLOG(ERROR) << "Error generating token";
-        return;
-    }
-
-    apacket* p = get_apacket();
-    memcpy(p->data, t->token, sizeof(t->token));
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_TOKEN;
-    p->msg.data_length = sizeof(t->token);
-    send_packet(p, t);
-}
-
-static void send_auth_publickey(atransport* t) {
-    LOG(INFO) << "Calling send_auth_publickey";
-
-    std::string key = adb_auth_get_userkey();
-    if (key.empty()) {
-        D("Failed to get user public key");
-        return;
-    }
-
-    if (key.size() >= MAX_PAYLOAD_V1) {
-        D("User public key too large (%zu B)", key.size());
-        return;
-    }
-
-    apacket* p = get_apacket();
-    memcpy(p->data, key.c_str(), key.size() + 1);
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
-
-    // adbd expects a null-terminated string.
-    p->msg.data_length = key.size() + 1;
-    send_packet(p, t);
-}
-
-void send_auth_response(uint8_t* token, size_t token_size, atransport* t) {
-    std::shared_ptr<RSA> key = t->NextKey();
-    if (key == nullptr) {
-        // No more private keys to try, send the public key.
-        send_auth_publickey(t);
-        return;
-    }
-
-    LOG(INFO) << "Calling send_auth_response";
-    apacket* p = get_apacket();
-
-    int ret = adb_auth_sign(key.get(), token, token_size, p->data);
-    if (!ret) {
-        D("Error signing the token");
-        put_apacket(p);
-        return;
-    }
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-void adb_auth_verified(atransport *t)
-{
-    handle_online(t);
-    send_connect(t);
-}
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 59b80d8..a6f224f 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -24,14 +24,6 @@
 
 #include <openssl/rsa.h>
 
-extern bool auth_required;
-
-int adb_auth_keygen(const char* filename);
-void adb_auth_verified(atransport *t);
-
-void send_auth_request(atransport *t);
-void send_auth_response(uint8_t *token, size_t token_size, atransport *t);
-
 /* AUTH packets first argument */
 /* Request */
 #define ADB_AUTH_TOKEN         1
@@ -42,25 +34,25 @@
 #if ADB_HOST
 
 void adb_auth_init();
-int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig);
+
+int adb_auth_keygen(const char* filename);
 std::string adb_auth_get_userkey();
 std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
 
-static inline bool adb_auth_generate_token(void*, size_t) { abort(); }
-static inline bool adb_auth_verify(void*, size_t, void*, int) { abort(); }
-static inline void adb_auth_confirm_key(unsigned char*, size_t, atransport*) { abort(); }
+void send_auth_response(const char* token, size_t token_size, atransport* t);
 
 #else // !ADB_HOST
 
-static inline int adb_auth_sign(void*, const unsigned char*, size_t, unsigned char*) { abort(); }
-static inline std::string adb_auth_get_userkey() { abort(); }
-static inline std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { abort(); }
+extern bool auth_required;
 
 void adbd_auth_init(void);
+void adbd_auth_verified(atransport *t);
+
 void adbd_cloexec_auth_socket();
-bool adb_auth_generate_token(void* token, size_t token_size);
-bool adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int sig_len);
-void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
+bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len);
+void adbd_auth_confirm_key(const char* data, size_t len, atransport* t);
+
+void send_auth_request(atransport *t);
 
 #endif // ADB_HOST
 
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 072c7f5..ff2d76d 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -45,6 +45,7 @@
 #include "adb_auth.h"
 #include "adb_utils.h"
 #include "sysdeps.h"
+#include "transport.h"
 
 static std::mutex& g_keys_mutex = *new std::mutex;
 static std::map<std::string, std::shared_ptr<RSA>>& g_keys =
@@ -297,14 +298,15 @@
     return result;
 }
 
-int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig) {
+static int adb_auth_sign(RSA* key, const char* token, size_t token_size, char* sig) {
     if (token_size != TOKEN_SIZE) {
         D("Unexpected token size %zd", token_size);
         return 0;
     }
 
     unsigned int len;
-    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key)) {
+    if (!RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+                  reinterpret_cast<uint8_t*>(sig), &len, key)) {
         return 0;
     }
 
@@ -421,3 +423,52 @@
         read_keys(path.c_str());
     }
 }
+
+static void send_auth_publickey(atransport* t) {
+    LOG(INFO) << "Calling send_auth_publickey";
+
+    std::string key = adb_auth_get_userkey();
+    if (key.empty()) {
+        D("Failed to get user public key");
+        return;
+    }
+
+    if (key.size() >= MAX_PAYLOAD_V1) {
+        D("User public key too large (%zu B)", key.size());
+        return;
+    }
+
+    apacket* p = get_apacket();
+    memcpy(p->data, key.c_str(), key.size() + 1);
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+
+    // adbd expects a null-terminated string.
+    p->msg.data_length = key.size() + 1;
+    send_packet(p, t);
+}
+
+void send_auth_response(const char* token, size_t token_size, atransport* t) {
+    std::shared_ptr<RSA> key = t->NextKey();
+    if (key == nullptr) {
+        // No more private keys to try, send the public key.
+        send_auth_publickey(t);
+        return;
+    }
+
+    LOG(INFO) << "Calling send_auth_response";
+    apacket* p = get_apacket();
+
+    int ret = adb_auth_sign(key.get(), token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_SIGNATURE;
+    p->msg.data_length = ret;
+    send_packet(p, t);
+}
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/adb_trace.cpp b/adb/adb_trace.cpp
index 369dec9..002d061 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -155,7 +155,24 @@
     }
 #endif
 
+#if !defined(_WIN32)
+    // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
+    // If set, move it out of the way so that libbase logging doesn't try to parse it.
+    std::string log_tags;
+    char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
+    if (ANDROID_LOG_TAGS) {
+        log_tags = ANDROID_LOG_TAGS;
+        unsetenv("ANDROID_LOG_TAGS");
+    }
+#endif
+
     android::base::InitLogging(argv, &AdbLogger);
+
+#if !defined(_WIN32)
+    // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
+    if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
+#endif
+
     setup_trace_mask();
 
     VLOG(ADB) << adb_version();
diff --git a/adb/adb_auth_client.cpp b/adb/adbd_auth.cpp
similarity index 79%
rename from adb/adb_auth_client.cpp
rename to adb/adbd_auth.cpp
index 84ad6ef..b5f87be 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adbd_auth.cpp
@@ -44,7 +44,9 @@
 static atransport* usb_transport;
 static bool needs_retry = false;
 
-bool adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int sig_len) {
+bool auth_required = true;
+
+bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len) {
     static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
 
     for (const auto& path : key_paths) {
@@ -76,7 +78,9 @@
                     continue;
                 }
 
-                bool verified = (RSA_verify(NID_sha1, token, token_size, sig, sig_len, key) == 1);
+                bool verified =
+                    (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+                                reinterpret_cast<const uint8_t*>(sig), sig_len, key) == 1);
                 RSA_free(key);
                 if (verified) return true;
             }
@@ -85,7 +89,7 @@
     return false;
 }
 
-bool adb_auth_generate_token(void* token, size_t token_size) {
+static bool adbd_auth_generate_token(void* token, size_t token_size) {
     FILE* fp = fopen("/dev/urandom", "re");
     if (!fp) return false;
     bool okay = (fread(token, token_size, 1, fp) == 1);
@@ -105,7 +109,7 @@
     framework_fd = -1;
 }
 
-static void adb_auth_event(int fd, unsigned events, void*) {
+static void adbd_auth_event(int fd, unsigned events, void*) {
     if (events & FDE_READ) {
         char response[2];
         int ret = unix_read(fd, response, sizeof(response));
@@ -113,13 +117,13 @@
             framework_disconnected();
         } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
             if (usb_transport) {
-                adb_auth_verified(usb_transport);
+                adbd_auth_verified(usb_transport);
             }
         }
     }
 }
 
-void adb_auth_confirm_key(unsigned char* key, size_t len, atransport* t) {
+void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) {
     if (!usb_transport) {
         usb_transport = t;
         t->AddDisconnect(&usb_disconnect);
@@ -150,7 +154,7 @@
     }
 }
 
-static void adb_auth_listener(int fd, unsigned events, void* data) {
+static void adbd_auth_listener(int fd, unsigned events, void* data) {
     int s = adb_socket_accept(fd, nullptr, nullptr);
     if (s < 0) {
         PLOG(ERROR) << "Failed to accept";
@@ -163,7 +167,7 @@
     }
 
     framework_fd = s;
-    fdevent_install(&framework_fde, framework_fd, adb_auth_event, nullptr);
+    fdevent_install(&framework_fde, framework_fd, adbd_auth_event, nullptr);
     fdevent_add(&framework_fde, FDE_READ);
 
     if (needs_retry) {
@@ -193,6 +197,28 @@
         return;
     }
 
-    fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
+    fdevent_install(&listener_fde, fd, adbd_auth_listener, NULL);
     fdevent_add(&listener_fde, FDE_READ);
 }
+
+void send_auth_request(atransport* t) {
+    LOG(INFO) << "Calling send_auth_request...";
+
+    if (!adbd_auth_generate_token(t->token, sizeof(t->token))) {
+        PLOG(ERROR) << "Error generating token";
+        return;
+    }
+
+    apacket* p = get_apacket();
+    memcpy(p->data, t->token, sizeof(t->token));
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_TOKEN;
+    p->msg.data_length = sizeof(t->token);
+    send_packet(p, t);
+}
+
+void adbd_auth_verified(atransport *t)
+{
+    handle_online(t);
+    send_connect(t);
+}
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index c348dd5..9b59d05 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -237,8 +237,7 @@
         // Uses a default value until device provides the proper name
         dest_file = "bugreport.zip";
     } else {
-        if (!android::base::EndsWith(dest_file, ".zip")) {
-            // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+        if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
             dest_file += ".zip";
         }
     }
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 54e254a..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);
@@ -686,100 +688,100 @@
 static int adb_shell(int argc, const char** argv) {
     FeatureSet features;
     std::string error;
-
     if (!adb_get_feature_set(&features, &error)) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
 
-    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
-    if (!use_shell_protocol) {
-        D("shell protocol not supported, using raw data transfer");
-    } else {
-        D("using shell protocol");
-    }
+    enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
+
+    // Defaults.
+    char escape_char = '~'; // -e
+    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
+    PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
 
     // Parse shell-specific command-line options.
-    // argv[0] is always "shell".
-    --argc;
-    ++argv;
-    int t_arg_count = 0;
-    char escape_char = '~';
-    while (argc) {
-        if (!strcmp(argv[0], "-e")) {
-            if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
-                fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+    argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
+    optind = 1; // argv[0] is always "shell", so set `optind` appropriately.
+    int opt;
+    while ((opt = getopt(argc, const_cast<char**>(argv), "+e:ntTx")) != -1) {
+        switch (opt) {
+            case 'e':
+                if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) {
+                    fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+                    return 1;
+                }
+                escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0];
+                break;
+            case 'n':
+                close_stdin();
+                break;
+            case 'x':
+                // This option basically asks for historical behavior, so set options that
+                // correspond to the historical defaults. This is slightly weird in that -Tx
+                // is fine (because we'll undo the -T) but -xT isn't, but that does seem to
+                // be our least worst choice...
+                use_shell_protocol = false;
+                tty = kPtyDefinitely;
+                escape_char = '~';
+                break;
+            case 't':
+                // Like ssh, -t arguments are cumulative so that multiple -t's
+                // are needed to force a PTY.
+                tty = (tty >= kPtyYes) ? kPtyDefinitely : kPtyYes;
+                break;
+            case 'T':
+                tty = kPtyNo;
+                break;
+            default:
+                // getopt(3) already printed an error message for us.
                 return 1;
-            }
-            escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
-            argc -= 2;
-            argv += 2;
-        } else if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
-            // Like ssh, -t arguments are cumulative so that multiple -t's
-            // are needed to force a PTY.
-            if (argv[0][1] == 't') {
-                ++t_arg_count;
-            } else {
-                t_arg_count = -1;
-            }
-            --argc;
-            ++argv;
-        } else if (!strcmp(argv[0], "-x")) {
-            use_shell_protocol = false;
-            --argc;
-            ++argv;
-        } else if (!strcmp(argv[0], "-n")) {
-            close_stdin();
-
-            --argc;
-            ++argv;
-        } else {
-            break;
         }
     }
 
-    // Legacy shell protocol requires a remote PTY to close the subprocess properly which creates
-    // some weird interactions with -tT.
-    if (!use_shell_protocol && t_arg_count != 0) {
-        if (!CanUseFeature(features, kFeatureShell2)) {
-            fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
-        } else {
-            fprintf(stderr, "error: PTY args -Tt cannot be used with -x\n");
-        }
-        return 1;
-    }
+    bool is_interactive = (optind == argc);
 
-    std::string shell_type_arg;
-    if (CanUseFeature(features, kFeatureShell2)) {
-        if (t_arg_count < 0) {
+    std::string shell_type_arg = kShellServiceArgPty;
+    if (tty == kPtyNo) {
+        shell_type_arg = kShellServiceArgRaw;
+    } else if (tty == kPtyAuto) {
+        // If stdin isn't a TTY, default to a raw shell; this lets
+        // things like `adb shell < my_script.sh` work as expected.
+        // Non-interactive shells should also not have a pty.
+        if (!unix_isatty(STDIN_FILENO) || !is_interactive) {
             shell_type_arg = kShellServiceArgRaw;
-        } else if (t_arg_count == 0) {
-            // If stdin isn't a TTY, default to a raw shell; this lets
-            // things like `adb shell < my_script.sh` work as expected.
-            // Otherwise leave |shell_type_arg| blank which uses PTY for
-            // interactive shells and raw for non-interactive.
-            if (!unix_isatty(STDIN_FILENO)) {
-                shell_type_arg = kShellServiceArgRaw;
-            }
-        } else if (t_arg_count == 1) {
-            // A single -t arg isn't enough to override implicit -T.
-            if (!unix_isatty(STDIN_FILENO)) {
-                fprintf(stderr,
-                        "Remote PTY will not be allocated because stdin is not a terminal.\n"
-                        "Use multiple -t options to force remote PTY allocation.\n");
-                shell_type_arg = kShellServiceArgRaw;
-            } else {
-                shell_type_arg = kShellServiceArgPty;
-            }
+        }
+    } else if (tty == kPtyYes) {
+        // A single -t arg isn't enough to override implicit -T.
+        if (!unix_isatty(STDIN_FILENO)) {
+            fprintf(stderr,
+                    "Remote PTY will not be allocated because stdin is not a terminal.\n"
+                    "Use multiple -t options to force remote PTY allocation.\n");
+            shell_type_arg = kShellServiceArgRaw;
+        }
+    }
+
+    D("shell -e 0x%x t=%d use_shell_protocol=%s shell_type_arg=%s\n",
+      escape_char, tty,
+      use_shell_protocol ? "true" : "false",
+      (shell_type_arg == kShellServiceArgPty) ? "pty" : "raw");
+
+    // Raw mode is only supported when talking to a new device *and* using the shell protocol.
+    if (!use_shell_protocol) {
+        if (shell_type_arg != kShellServiceArgPty) {
+            fprintf(stderr, "error: %s only supports allocating a pty\n",
+                    !CanUseFeature(features, kFeatureShell2) ? "device" : "-x");
+            return 1;
         } else {
-            shell_type_arg = kShellServiceArgPty;
+            // If we're not using the shell protocol, the type argument must be empty.
+            shell_type_arg = "";
         }
     }
 
     std::string command;
-    if (argc) {
+    if (optind < argc) {
         // We don't escape here, just like ssh(1). http://b/20564385.
-        command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
+        command = android::base::Join(std::vector<const char*>(argv + optind, argv + argc), ' ');
     }
 
     return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
@@ -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;
 }
 
@@ -1401,7 +1403,7 @@
     return !CanUseFeature(features, kFeatureCmd);
 }
 
-int adb_commandline(int argc, const char **argv) {
+int adb_commandline(int argc, const char** argv) {
     int no_daemon = 0;
     int is_daemon = 0;
     int is_server = 0;
@@ -1950,10 +1952,17 @@
     } else if (!strcmp(argv[0], "reconnect")) {
         if (argc == 1) {
             return adb_query_command("host:reconnect");
-        } else if (argc == 2 && !strcmp(argv[1], "device")) {
-            std::string err;
-            adb_connect("reconnect", &err);
-            return 0;
+        } else if (argc == 2) {
+            if (!strcmp(argv[1], "device")) {
+                std::string err;
+                adb_connect("reconnect", &err);
+                return 0;
+            } else if (!strcmp(argv[1], "offline")) {
+                std::string err;
+                return adb_query_command("host:reconnect-offline");
+            } else {
+                return usage();
+            }
         }
     }
 
@@ -1983,20 +1992,15 @@
 static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
     // The last argument must be the APK file
     const char* file = argv[argc - 1];
-    const char* dot = strrchr(file, '.');
-    bool found_apk = false;
-    struct stat sb;
-    if (dot && !strcasecmp(dot, ".apk")) {
-        if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-            fprintf(stderr, "Invalid APK file: %s\n", file);
-            return EXIT_FAILURE;
-        }
-        found_apk = true;
+    if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
+        fprintf(stderr, "Filename doesn't end .apk: %s\n", file);
+        return EXIT_FAILURE;
     }
 
-    if (!found_apk) {
-        fprintf(stderr, "Missing APK file\n");
-        return EXIT_FAILURE;
+    struct stat sb;
+    if (stat(file, &sb) == -1) {
+        fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+        return 1;
     }
 
     int localFd = adb_open(file, O_RDONLY);
@@ -2042,22 +2046,16 @@
 static int install_multiple_app(TransportType transport, const char* serial, int argc,
                                 const char** argv)
 {
-    int i;
-    struct stat sb;
-    uint64_t total_size = 0;
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
-    for (i = argc - 1; i >= 0; i--) {
+    uint64_t total_size = 0;
+    for (int i = argc - 1; i >= 0; i--) {
         const char* file = argv[i];
-        const char* dot = strrchr(file, '.');
-        if (dot && !strcasecmp(dot, ".apk")) {
-            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-                fprintf(stderr, "Invalid APK file: %s\n", file);
-                return EXIT_FAILURE;
-            }
 
-            total_size += sb.st_size;
+        if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+            struct stat sb;
+            if (stat(file, &sb) != -1) total_size += sb.st_size;
             first_apk = i;
         } else {
             break;
@@ -2065,7 +2063,7 @@
     }
 
     if (first_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
+        fprintf(stderr, "No APK file on command line\n");
         return 1;
     }
 
@@ -2077,7 +2075,7 @@
     }
 
     std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
-    for (i = 1; i < first_apk; i++) {
+    for (int i = 1; i < first_apk; i++) {
         cmd += " " + escape_arg(argv[i]);
     }
 
@@ -2109,10 +2107,11 @@
 
     // Valid session, now stream the APKs
     int success = 1;
-    for (i = first_apk; i < argc; i++) {
+    for (int i = first_apk; i < argc; i++) {
         const char* file = argv[i];
+        struct stat sb;
         if (stat(file, &sb) == -1) {
-            fprintf(stderr, "Failed to stat %s\n", file);
+            fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
             success = 0;
             goto finalize_session;
         }
@@ -2212,10 +2211,8 @@
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
     const char* where = DATA_DEST;
-    int i;
-    struct stat sb;
 
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "-s")) {
             where = SD_DEST;
         }
@@ -2224,22 +2221,15 @@
     // Find last APK argument.
     // All other arguments passed through verbatim.
     int last_apk = -1;
-    for (i = argc - 1; i >= 0; i--) {
-        const char* file = argv[i];
-        const char* dot = strrchr(file, '.');
-        if (dot && !strcasecmp(dot, ".apk")) {
-            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-                fprintf(stderr, "Invalid APK file: %s\n", file);
-                return EXIT_FAILURE;
-            }
-
+    for (int i = argc - 1; i >= 0; i--) {
+        if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
             last_apk = i;
             break;
         }
     }
 
     if (last_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
+        fprintf(stderr, "No APK file on command line\n");
         return EXIT_FAILURE;
     }
 
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 094988a..78434a0 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -35,7 +35,8 @@
 #include <scoped_minijail.h>
 
 #include "debuggerd/client.h"
-#include "private/android_filesystem_config.h"
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 #include "selinux/android.h"
 
 #include "adb.h"
@@ -48,7 +49,7 @@
 
 static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
 #if defined(ALLOW_ADBD_ROOT)
-    if (android::base::GetBoolProperty("ro.debuggable", false)) {
+    if (__android_log_is_debuggable()) {
         return;
     }
 #endif
@@ -68,7 +69,7 @@
     // ro.secure:
     //   Drop privileges by default. Set to 1 on userdebug and user builds.
     bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
-    bool ro_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+    bool ro_debuggable = __android_log_is_debuggable();
 
     // Drop privileges if ro.secure is set...
     bool drop = ro_secure;
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/file_sync_service.cpp b/adb/file_sync_service.cpp
index 2dfad94..7a92d2e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -31,10 +31,10 @@
 #include <unistd.h>
 #include <utime.h>
 
-#include <android/log.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 #include <selinux/android.h>
 
 #include "adb.h"
@@ -198,11 +198,6 @@
         // Ignore the result of calling fchmod. It's not supported
         // by all filesystems, so we don't check for success. b/12441485
         fchmod(fd, mode);
-
-        if (!update_capabilities(path, capabilities)) {
-            SendSyncFailErrno(s, "update_capabilities failed");
-            goto fail;
-        }
     }
 
     while (true) {
@@ -232,6 +227,11 @@
 
     adb_close(fd);
 
+    if (!update_capabilities(path, capabilities)) {
+        SendSyncFailErrno(s, "update_capabilities failed");
+        goto fail;
+    }
+
     utimbuf u;
     u.actime = timestamp;
     u.modtime = timestamp;
diff --git a/adb/services.cpp b/adb/services.cpp
index 0c3dd00..2fbc15a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -38,8 +38,9 @@
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
-#include "cutils/android_reboot.h"
 #include <android-base/properties.h>
+#include <cutils/android_reboot.h>
+#include <private/android_logger.h>
 #endif
 
 #include "adb.h"
@@ -73,7 +74,7 @@
         WriteFdExactly(fd, "adbd is already running as root\n");
         adb_close(fd);
     } else {
-        if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+        if (!__android_log_is_debuggable()) {
             WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
             adb_close(fd);
             return;
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index ae628e4..f9e028b 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -26,6 +26,7 @@
 
 #include "android-base/properties.h"
 #include "android-base/stringprintf.h"
+#include <private/android_logger.h>
 
 #include "adb.h"
 #include "adb_io.h"
@@ -102,8 +103,7 @@
         WriteFdFmt(fd, "verity not enabled - ENG build\n");
         return;
     }
-
-    if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+    if (!__android_log_is_debuggable()) {
         WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
         return;
     }
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 7b00d9d..4975fab 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -82,6 +82,7 @@
 #include "shell_service.h"
 
 #include <errno.h>
+#include <paths.h>
 #include <pty.h>
 #include <pwd.h>
 #include <sys/select.h>
@@ -92,10 +93,9 @@
 #include <unordered_map>
 #include <vector>
 
-#include <android/log.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
-#include <paths.h>
+#include <private/android_logger.h>
 
 #include "adb.h"
 #include "adb_io.h"
@@ -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/shell_service_protocol_test.cpp b/adb/shell_service_protocol_test.cpp
index a826035..b0fa3ed 100644
--- a/adb/shell_service_protocol_test.cpp
+++ b/adb/shell_service_protocol_test.cpp
@@ -86,9 +86,10 @@
 
 namespace {
 
-// Returns true if the packet contains the given values.
+// Returns true if the packet contains the given values. `data` can't be null.
 bool PacketEquals(const ShellProtocol* protocol, ShellProtocol::Id id,
                     const void* data, size_t data_length) {
+    // Note that passing memcmp null is bad, even if data_length is 0.
     return (protocol->id() == id &&
             protocol->data_length() == data_length &&
             !memcmp(data, protocol->data(), data_length));
@@ -130,7 +131,8 @@
 
     ASSERT_TRUE(write_protocol_->Write(id, 0));
     ASSERT_TRUE(read_protocol_->Read());
-    ASSERT_TRUE(PacketEquals(read_protocol_, id, nullptr, 0));
+    char buf[1];
+    ASSERT_TRUE(PacketEquals(read_protocol_, id, buf, 0));
 }
 
 // Tests exit code packets.
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/sockets.cpp b/adb/sockets.cpp
index b809c4f..c05903f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -32,6 +32,7 @@
 
 #if !ADB_HOST
 #include <android-base/properties.h>
+#include <private/android_logger.h>
 #endif
 
 #include "adb.h"
@@ -122,7 +123,7 @@
 }
 
 static int local_socket_enqueue(asocket* s, apacket* p) {
-    D("LS(%d): enqueue %d", s->id, p->len);
+    D("LS(%d): enqueue %zu", s->id, p->len);
 
     p->ptr = p->data;
 
@@ -195,7 +196,7 @@
 
     /* dispose of any unwritten data */
     for (p = s->pkt_first; p; p = n) {
-        D("LS(%d): discarding %d bytes", s->id, p->len);
+        D("LS(%d): discarding %zu bytes", s->id, p->len);
         n = p->next;
         put_apacket(p);
     }
@@ -305,7 +306,7 @@
 
     if (ev & FDE_READ) {
         apacket* p = get_apacket();
-        unsigned char* x = p->data;
+        char* x = p->data;
         const size_t max_payload = s->get_max_payload();
         size_t avail = max_payload;
         int r = 0;
@@ -416,12 +417,7 @@
     D("LS(%d): bound to '%s' via %d", s->id, name, fd);
 
 #if !ADB_HOST
-    bool debuggable = false;
-    if (!strncmp(name, "root:", 5)) {
-        debuggable = android::base::GetBoolProperty("ro.debuggable", false);
-    }
-
-    if ((!strncmp(name, "root:", 5) && getuid() != 0 && debuggable) ||
+    if ((!strncmp(name, "root:", 5) && getuid() != 0 && __android_log_is_debuggable()) ||
         (!strncmp(name, "unroot:", 7) && getuid() == 0) ||
         !strncmp(name, "usb:", 4) ||
         !strncmp(name, "tcpip:", 6)) {
@@ -553,7 +549,7 @@
     s->close(s);
 }
 
-static unsigned unhex(unsigned char* s, int len) {
+static unsigned unhex(char* s, int len) {
     unsigned n = 0, c;
 
     while (len-- > 0) {
@@ -665,7 +661,7 @@
     TransportType type = kTransportAny;
 #endif
 
-    D("SS(%d): enqueue %d", s->id, p->len);
+    D("SS(%d): enqueue %zu", s->id, p->len);
 
     if (s->pkt_first == 0) {
         s->pkt_first = p;
@@ -698,7 +694,7 @@
     D("SS(%d): len is %d", s->id, len);
     /* can't do anything until we have the full header */
     if ((len + 4) > p->len) {
-        D("SS(%d): waiting for %d more bytes", s->id, len + 4 - p->len);
+        D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len);
         return 0;
     }
 
@@ -795,11 +791,14 @@
     }
 #endif
 
-    if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+    if (!s->transport) {
+        SendFail(s->peer->fd, "device offline (no transport)");
+        goto fail;
+    } else if (s->transport->connection_state == kCsOffline) {
         /* if there's no remote we fail the connection
          ** right here and terminate it
          */
-        SendFail(s->peer->fd, "device offline (x)");
+        SendFail(s->peer->fd, "device offline (transport offline)");
         goto fail;
     }
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3ed589c..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);
@@ -594,11 +587,14 @@
 }
 
 inline int network_loopback_client(int port, int type, std::string* error) {
-  return _fd_set_error_str(socket_loopback_client(port, type), error);
+  return _fd_set_error_str(socket_network_client("localhost", port, type), error);
 }
 
 inline int network_loopback_server(int port, int type, std::string* error) {
-  return _fd_set_error_str(socket_loopback_server(port, type), error);
+  int fd = socket_loopback_server(port, type);
+  if (fd < 0 && errno == EAFNOSUPPORT)
+      return _fd_set_error_str(socket_loopback_server6(port, type), error);
+  return _fd_set_error_str(fd, error);
 }
 
 inline int network_inaddr_any_server(int port, int type, std::string* error) {
@@ -763,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..ed2cf25 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 b12bf88..e76aaed 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -371,15 +371,8 @@
     def test_pty_logic(self):
         """Tests that a PTY is allocated when it should be.
 
-        PTY allocation behavior should match ssh; some behavior requires
-        a terminal stdin to test so this test will be skipped if stdin
-        is not a terminal.
+        PTY allocation behavior should match ssh.
         """
-        if not self.device.has_shell_protocol():
-            raise unittest.SkipTest('PTY arguments unsupported on this device')
-        if not os.isatty(sys.stdin.fileno()):
-            raise unittest.SkipTest('PTY tests require stdin terminal')
-
         def check_pty(args):
             """Checks adb shell PTY allocation.
 
@@ -409,16 +402,34 @@
         # -T: never allocate PTY.
         self.assertEqual((False, False), check_pty(['-T']))
 
-        # No args: PTY only if stdin is a terminal and shell is interactive,
-        # which is difficult to reliably test from a script.
-        self.assertEqual((False, False), check_pty([]))
+        # These tests require a new device.
+        if self.device.has_shell_protocol() and os.isatty(sys.stdin.fileno()):
+            # No args: PTY only if stdin is a terminal and shell is interactive,
+            # which is difficult to reliably test from a script.
+            self.assertEqual((False, False), check_pty([]))
 
-        # -t: PTY if stdin is a terminal.
-        self.assertEqual((True, False), check_pty(['-t']))
+            # -t: PTY if stdin is a terminal.
+            self.assertEqual((True, False), check_pty(['-t']))
 
         # -t -t: always allocate PTY.
         self.assertEqual((True, True), check_pty(['-t', '-t']))
 
+        # -tt: always allocate PTY, POSIX style (http://b/32216152).
+        self.assertEqual((True, True), check_pty(['-tt']))
+
+        # -ttt: ssh has weird even/odd behavior with multiple -t flags, but
+        # we follow the man page instead.
+        self.assertEqual((True, True), check_pty(['-ttt']))
+
+        # -ttx: -x and -tt aren't incompatible (though -Tx would be an error).
+        self.assertEqual((True, True), check_pty(['-ttx']))
+
+        # -Ttt: -tt cancels out -T.
+        self.assertEqual((True, True), check_pty(['-Ttt']))
+
+        # -ttT: -T cancels out -tt.
+        self.assertEqual((False, False), check_pty(['-ttT']))
+
     def test_shell_protocol(self):
         """Tests the shell protocol on the device.
 
@@ -473,8 +484,12 @@
         self.device.shell(proc_query)
         os.kill(sleep_proc.pid, signal.SIGINT)
         sleep_proc.communicate()
-        self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
-                         'subprocess failed to terminate')
+
+        # It can take some time for the process to receive the signal and die.
+        end_time = time.time() + 3
+        while self.device.shell_nocheck(proc_query)[0] != 1:
+            self.assertFalse(time.time() > end_time,
+                             'subprocess failed to terminate in time')
 
     def test_non_interactive_stdin(self):
         """Tests that non-interactive shells send stdin."""
@@ -507,13 +522,14 @@
             trap "echo SIGINT > {path}; exit 0" SIGINT
             trap "echo SIGHUP > {path}; exit 0" SIGHUP
             echo Waiting
-            while true; do sleep 100; done
+            read
         """.format(path=log_path)
 
         script = ";".join([x.strip() for x in script.strip().splitlines()])
 
-        process = self.device.shell_popen(
-            ["sh", "-c", "'{}'".format(script)], kill_atexit=False, stdout=subprocess.PIPE)
+        process = self.device.shell_popen([script], kill_atexit=False,
+                                          stdin=subprocess.PIPE,
+                                          stdout=subprocess.PIPE)
 
         self.assertEqual("Waiting\n", process.stdout.readline())
         process.send_signal(signal.SIGINT)
@@ -521,7 +537,7 @@
 
         # Waiting for the local adb to finish is insufficient, since it hangs
         # up immediately.
-        time.sleep(0.25)
+        time.sleep(1)
 
         stdout, _ = self.device.shell(["cat", log_path])
         self.assertEqual(stdout.strip(), "SIGHUP")
@@ -874,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.cpp b/adb/transport.cpp
index 87712fc..132702d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -150,32 +150,17 @@
     }
 }
 
-void send_packet(apacket *p, atransport *t)
-{
-    unsigned char *x;
-    unsigned sum;
-    unsigned count;
-
+void send_packet(apacket* p, atransport* t) {
     p->msg.magic = p->msg.command ^ 0xffffffff;
-
-    count = p->msg.data_length;
-    x = (unsigned char *) p->data;
-    sum = 0;
-    while(count-- > 0){
-        sum += *x++;
-    }
-    p->msg.data_check = sum;
+    p->msg.data_check = calculate_apacket_checksum(p);
 
     print_packet("send", p);
 
     if (t == NULL) {
-        D("Transport is null");
-        // Zap errno because print_packet() and other stuff have errno effect.
-        errno = 0;
-        fatal_errno("Transport is null");
+        fatal("Transport is null");
     }
 
-    if(write_packet(t->transport_socket, t->serial, &p)){
+    if (write_packet(t->transport_socket, t->serial, &p)) {
         fatal_errno("cannot enqueue packet on transport socket");
     }
 }
@@ -923,12 +908,18 @@
     return result;
 }
 
+void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+    std::lock_guard<std::mutex> lock(transport_lock);
+    for (auto& t : transport_list) {
+        if (predicate(t)) {
+            t->Kick();
+        }
+    }
+}
+
 /* hack for osx */
 void close_usb_devices() {
-    std::lock_guard<std::mutex> lock(transport_lock);
-    for (const auto& t : transport_list) {
-        t->Kick();
-    }
+    close_usb_devices([](const atransport*) { return true; });
 }
 #endif // ADB_HOST
 
@@ -1052,25 +1043,14 @@
     return 0;
 }
 
-int check_data(apacket *p)
-{
-    unsigned count, sum;
-    unsigned char *x;
-
-    count = p->msg.data_length;
-    x = p->data;
-    sum = 0;
-    while(count-- > 0) {
-        sum += *x++;
-    }
-
-    if(sum != p->msg.data_check) {
+int check_data(apacket* p) {
+    if (calculate_apacket_checksum(p) != p->msg.data_check) {
         return -1;
-    } else {
-        return 0;
     }
+    return 0;
 }
 
+#if ADB_HOST
 std::shared_ptr<RSA> atransport::NextKey() {
     if (keys_.empty()) keys_ = adb_auth_get_private_keys();
 
@@ -1078,3 +1058,4 @@
     keys_.pop_front();
     return result;
 }
+#endif
diff --git a/adb/transport.h b/adb/transport.h
index 959681f..b2df838 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <deque>
+#include <functional>
 #include <list>
 #include <memory>
 #include <string>
@@ -108,9 +109,11 @@
         return type == kTransportLocal && local_port_for_emulator_ == -1;
     }
 
+#if ADB_HOST
     std::shared_ptr<RSA> NextKey();
+#endif
 
-    unsigned char token[TOKEN_SIZE] = {};
+    char token[TOKEN_SIZE] = {};
     size_t failed_auth_attempts = 0;
 
     const std::string connection_state_name() const;
@@ -161,7 +164,9 @@
     // A list of adisconnect callbacks called when the transport is kicked.
     std::list<adisconnect*> disconnects_;
 
+#if ADB_HOST
     std::deque<std::shared_ptr<RSA>> keys_;
+#endif
 
     DISALLOW_COPY_AND_ASSIGN(atransport);
 };
@@ -195,8 +200,8 @@
 int check_header(apacket* p, atransport* t);
 int check_data(apacket* p);
 
-/* for MacOS X cleanup */
 void close_usb_devices();
+void close_usb_devices(std::function<bool(const atransport*)> predicate);
 
 void send_packet(apacket* p, atransport* t);
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index a94b41e..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
 
@@ -103,7 +105,8 @@
     int fd = -1;
 
 #if ADB_HOST
-    if (find_emulator_transport_by_adb_port(adb_port) != nullptr) {
+    if (find_emulator_transport_by_adb_port(adb_port) != nullptr ||
+        find_emulator_transport_by_console_port(console_port) != nullptr) {
         return -1;
     }
 
@@ -120,7 +123,7 @@
         D("client: connected on remote on fd %d", fd);
         close_on_exec(fd);
         disable_tcp_nagle(fd);
-        std::string serial = android::base::StringPrintf("emulator-%d", console_port);
+        std::string serial = getEmulatorSerialString(console_port);
         if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
             return 0;
         }
@@ -143,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;
@@ -172,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;
@@ -213,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);
@@ -225,7 +228,8 @@
             D("server: new connection on fd %d", fd);
             close_on_exec(fd);
             disable_tcp_nagle(fd);
-            if (register_socket_transport(fd, "host", port, 1) != 0) {
+            std::string serial = android::base::StringPrintf("host-%d", fd);
+            if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
                 adb_close(fd);
             }
         }
@@ -431,6 +435,11 @@
     return NULL;
 }
 
+std::string getEmulatorSerialString(int console_port)
+{
+    return android::base::StringPrintf("emulator-%d", console_port);
+}
+
 atransport* find_emulator_transport_by_adb_port(int adb_port)
 {
     std::lock_guard<std::mutex> lock(local_transports_lock);
@@ -438,6 +447,12 @@
     return result;
 }
 
+atransport* find_emulator_transport_by_console_port(int console_port)
+{
+    return find_transport(getEmulatorSerialString(console_port).c_str());
+}
+
+
 /* Only call this function if you already hold local_transports_lock. */
 int get_available_local_transport_index_locked()
 {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d05d928..d054601 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -94,7 +94,7 @@
 }
 
 #if ADB_HOST
-int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
 {
     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 500898a..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 */
@@ -205,9 +207,8 @@
                          interface->bInterfaceProtocol, interface->bNumEndpoints);
 
                     if (interface->bNumEndpoints == 2 &&
-                            is_adb_interface(vid, pid, interface->bInterfaceClass,
-                            interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
-
+                        is_adb_interface(interface->bInterfaceClass, interface->bInterfaceSubClass,
+                                         interface->bInterfaceProtocol)) {
                         struct stat st;
                         char pathbuf[128];
                         char link[256];
@@ -578,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 adcbb3e..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;
@@ -345,7 +349,7 @@
 
     //* check to make sure interface class, subclass and protocol match ADB
     //* avoid opening mass storage endpoints
-    if (!is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
+    if (!is_adb_interface(interfaceClass, interfaceSubClass, interfaceProtocol)) {
         goto err_bad_adb_interface;
     }
 
@@ -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 4649454..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);
   }
 }
 
@@ -553,10 +555,9 @@
     return 0;
   }
 
-  if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
-      interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
-
-    if(interf_desc.bInterfaceProtocol == 0x01) {
+  if (is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
+                       interf_desc.bInterfaceProtocol)) {
+    if (interf_desc.bInterfaceProtocol == 0x01) {
       AdbEndpointInformation endpoint_info;
       // assuming zero is a valid bulk endpoint ID
       if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
diff --git a/base/Android.bp b/base/Android.bp
index 88d8ad1..e6ad15b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -73,6 +73,7 @@
         "errors_test.cpp",
         "file_test.cpp",
         "logging_test.cpp",
+        "parsedouble_test.cpp",
         "parseint_test.cpp",
         "parsenetaddress_test.cpp",
         "quick_exit_test.cpp",
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
new file mode 100644
index 0000000..daa6902
--- /dev/null
+++ b/base/include/android-base/parsedouble.h
@@ -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.
+ */
+
+#ifndef ANDROID_BASE_PARSEDOUBLE_H
+#define ANDROID_BASE_PARSEDOUBLE_H
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <limits>
+
+namespace android {
+namespace base {
+
+// Parse double value in the string 's' and sets 'out' to that value.
+// Optionally allows the caller to define a 'min' and 'max' beyond which
+// otherwise valid values will be rejected. Returns boolean success.
+static inline bool ParseDouble(const char* s, double* out,
+                               double min = std::numeric_limits<double>::lowest(),
+                               double max = std::numeric_limits<double>::max()) {
+  errno = 0;
+  char* end;
+  double result = strtod(s, &end);
+  if (errno != 0 || s == end || *end != '\0') {
+    return false;
+  }
+  if (result < min || max < result) {
+    return false;
+  }
+  *out = result;
+  return true;
+}
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_PARSEDOUBLE_H
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index ed75e2d..2c8570e 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -21,17 +21,19 @@
 #include <stdlib.h>
 
 #include <limits>
+#include <string>
 
 namespace android {
 namespace base {
 
 // Parses the unsigned decimal integer in the string 's' and sets 'out' to
 // that value. Optionally allows the caller to define a 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
+// otherwise valid values will be rejected. Returns boolean success; 'out'
+// is untouched if parsing fails.
 template <typename T>
 bool ParseUint(const char* s, T* out,
                T max = std::numeric_limits<T>::max()) {
-  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
+  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
   unsigned long long int result = strtoull(s, &end, base);
@@ -45,15 +47,22 @@
   return true;
 }
 
+// TODO: string_view
+template <typename T>
+bool ParseUint(const std::string& s, T* out,
+               T max = std::numeric_limits<T>::max()) {
+  return ParseUint(s.c_str(), out, max);
+}
+
 // Parses the signed decimal integer in the string 's' and sets 'out' to
 // that value. Optionally allows the caller to define a 'min' and 'max
 // beyond which otherwise valid values will be rejected. Returns boolean
-// success.
+// success; 'out' is untouched if parsing fails.
 template <typename T>
 bool ParseInt(const char* s, T* out,
               T min = std::numeric_limits<T>::min(),
               T max = std::numeric_limits<T>::max()) {
-  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
+  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
   long long int result = strtoll(s, &end, base);
@@ -67,6 +76,14 @@
   return true;
 }
 
+// TODO: string_view
+template <typename T>
+bool ParseInt(const std::string& s, T* out,
+              T min = std::numeric_limits<T>::min(),
+              T max = std::numeric_limits<T>::max()) {
+  return ParseInt(s.c_str(), out, min, max);
+}
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 69781cd..b8a9289 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -58,9 +58,11 @@
 
 // Tests whether 's' starts with 'prefix'.
 bool StartsWith(const std::string& s, const char* prefix);
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
 
 // Tests whether 's' ends with 'suffix'.
 bool EndsWith(const std::string& s, const char* suffix);
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
 
 }  // namespace base
 }  // namespace android
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 4ea3c8e..c0bf0c1 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -48,4 +48,21 @@
   DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
 };
 
+class CapturedStderr {
+ public:
+  CapturedStderr();
+  ~CapturedStderr();
+
+  int fd() const;
+
+ private:
+  void init();
+  void reset();
+
+  TemporaryFile temp_file_;
+  int old_stderr_;
+
+  DISALLOW_COPY_AND_ASSIGN(CapturedStderr);
+};
+
 #endif  // ANDROID_BASE_TEST_UTILS_H
diff --git a/base/logging.cpp b/base/logging.cpp
index ece10ec..cbc3c8a 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -45,7 +45,7 @@
 
 // Headers for LogMessage::LogLine.
 #ifdef __ANDROID__
-#include <android/log.h>
+#include <log/log.h>
 #include <android/set_abort_message.h>
 #else
 #include <sys/types.h>
@@ -415,6 +415,8 @@
         msg[nl] = '\0';
         LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
                 data_->GetSeverity(), &msg[i]);
+        // Undo the zero-termination so we can give the complete message to the aborter.
+        msg[nl] = '\n';
         i = nl + 1;
       }
     }
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 9fc7736..2d9c2ba 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -37,42 +37,6 @@
 #define HOST_TEST(suite, name) TEST(suite, name)
 #endif
 
-class CapturedStderr {
- public:
-  CapturedStderr() : old_stderr_(-1) {
-    init();
-  }
-
-  ~CapturedStderr() {
-    reset();
-  }
-
-  int fd() const {
-    return temp_file_.fd;
-  }
-
- private:
-  void init() {
-#if defined(_WIN32)
-    // On Windows, stderr is often buffered, so make sure it is unbuffered so
-    // that we can immediately read back what was written to stderr.
-    ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
-#endif
-    old_stderr_ = dup(STDERR_FILENO);
-    ASSERT_NE(-1, old_stderr_);
-    ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
-  }
-
-  void reset() {
-    ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
-    ASSERT_EQ(0, close(old_stderr_));
-    // Note: cannot restore prior setvbuf() setting.
-  }
-
-  TemporaryFile temp_file_;
-  int old_stderr_;
-};
-
 #if defined(_WIN32)
 static void ExitSignalAbortHandler(int) {
   _exit(3);
@@ -606,3 +570,27 @@
 
   ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
 }
+
+struct CountLineAborter {
+  static void CountLineAborterFunction(const char* msg) {
+    while (*msg != 0) {
+      if (*msg == '\n') {
+        newline_count++;
+      }
+      msg++;
+    }
+  }
+  static size_t newline_count;
+};
+size_t CountLineAborter::newline_count = 0;
+
+TEST(logging, LOG_FATAL_ABORTER_MESSAGE) {
+  CountLineAborter::newline_count = 0;
+  android::base::SetAborter(CountLineAborter::CountLineAborterFunction);
+
+  android::base::ScopedLogSeverity sls(android::base::ERROR);
+  CapturedStderr cap;
+  LOG(FATAL) << "foo\nbar";
+
+  EXPECT_EQ(CountLineAborter::newline_count, 1U + 1U);  // +1 for final '\n'.
+}
diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp
new file mode 100644
index 0000000..8734c42
--- /dev/null
+++ b/base/parsedouble_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "android-base/parsedouble.h"
+
+#include <gtest/gtest.h>
+
+TEST(parsedouble, smoke) {
+  double d;
+  ASSERT_FALSE(android::base::ParseDouble("", &d));
+  ASSERT_FALSE(android::base::ParseDouble("x", &d));
+  ASSERT_FALSE(android::base::ParseDouble("123.4x", &d));
+
+  ASSERT_TRUE(android::base::ParseDouble("123.4", &d));
+  ASSERT_DOUBLE_EQ(123.4, d);
+  ASSERT_TRUE(android::base::ParseDouble("-123.4", &d));
+  ASSERT_DOUBLE_EQ(-123.4, d);
+
+  ASSERT_TRUE(android::base::ParseDouble("0", &d, 0.0));
+  ASSERT_DOUBLE_EQ(0.0, d);
+  ASSERT_FALSE(android::base::ParseDouble("0", &d, 1e-9));
+  ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0));
+  ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0));
+  ASSERT_DOUBLE_EQ(1.0, d);
+}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 6a3ba31..483b1d3 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -19,7 +19,7 @@
 #include <gtest/gtest.h>
 
 TEST(parseint, signed_smoke) {
-  int i;
+  int i = 0;
   ASSERT_FALSE(android::base::ParseInt("x", &i));
   ASSERT_FALSE(android::base::ParseInt("123x", &i));
 
@@ -28,7 +28,7 @@
   ASSERT_TRUE(android::base::ParseInt("-123", &i));
   ASSERT_EQ(-123, i);
 
-  short s;
+  short s = 0;
   ASSERT_TRUE(android::base::ParseInt("1234", &s));
   ASSERT_EQ(1234, s);
 
@@ -39,7 +39,7 @@
 }
 
 TEST(parseint, unsigned_smoke) {
-  unsigned int i;
+  unsigned int i = 0u;
   ASSERT_FALSE(android::base::ParseUint("x", &i));
   ASSERT_FALSE(android::base::ParseUint("123x", &i));
 
@@ -47,7 +47,7 @@
   ASSERT_EQ(123u, i);
   ASSERT_FALSE(android::base::ParseUint("-123", &i));
 
-  unsigned short s;
+  unsigned short s = 0u;
   ASSERT_TRUE(android::base::ParseUint("1234", &s));
   ASSERT_EQ(1234u, s);
 
@@ -58,21 +58,41 @@
 }
 
 TEST(parseint, no_implicit_octal) {
-  int i;
+  int i = 0;
   ASSERT_TRUE(android::base::ParseInt("0123", &i));
   ASSERT_EQ(123, i);
 
-  unsigned int u;
+  unsigned int u = 0u;
   ASSERT_TRUE(android::base::ParseUint("0123", &u));
   ASSERT_EQ(123u, u);
 }
 
 TEST(parseint, explicit_hex) {
-  int i;
+  int i = 0;
   ASSERT_TRUE(android::base::ParseInt("0x123", &i));
   ASSERT_EQ(0x123, i);
 
-  unsigned int u;
+  unsigned int u = 0u;
   ASSERT_TRUE(android::base::ParseUint("0x123", &u));
   ASSERT_EQ(0x123u, u);
 }
+
+TEST(parseint, string) {
+  int i = 0;
+  ASSERT_TRUE(android::base::ParseInt(std::string("123"), &i));
+  ASSERT_EQ(123, i);
+
+  unsigned int u = 0u;
+  ASSERT_TRUE(android::base::ParseUint(std::string("123"), &u));
+  ASSERT_EQ(123u, u);
+}
+
+TEST(parseint, untouched_on_failure) {
+  int i = 123;
+  ASSERT_FALSE(android::base::ParseInt("456x", &i));
+  ASSERT_EQ(123, i);
+
+  unsigned int u = 123u;
+  ASSERT_FALSE(android::base::ParseInt("456x", &u));
+  ASSERT_EQ(123u, u);
+}
diff --git a/base/properties.cpp b/base/properties.cpp
index fab3005..37daf9a 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -52,7 +52,7 @@
 T GetIntProperty(const std::string& key, T default_value, T min, T max) {
   T result;
   std::string value = GetProperty(key, "");
-  if (!value.empty() && android::base::ParseInt(value.c_str(), &result, min, max)) return result;
+  if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
   return default_value;
 }
 
@@ -60,7 +60,7 @@
 T GetUintProperty(const std::string& key, T default_value, T max) {
   T result;
   std::string value = GetProperty(key, "");
-  if (!value.empty() && android::base::ParseUint(value.c_str(), &result, max)) return result;
+  if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
   return default_value;
 }
 
diff --git a/base/strings.cpp b/base/strings.cpp
index b8775df..7a94ad7 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,17 +87,29 @@
 template std::string Join(const std::vector<const char*>&, const std::string&);
 
 bool StartsWith(const std::string& s, const char* prefix) {
-  return s.compare(0, strlen(prefix), prefix) == 0;
+  return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
 }
 
-bool EndsWith(const std::string& s, const char* suffix) {
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
+  return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
   size_t suffix_length = strlen(suffix);
   size_t string_length = s.size();
   if (suffix_length > string_length) {
     return false;
   }
   size_t offset = string_length - suffix_length;
-  return s.compare(offset, suffix_length, suffix) == 0;
+  return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, true);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, false);
 }
 
 }  // namespace base
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 30ae29e..5fb21dd 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -134,44 +134,113 @@
               "2,1" == android::base::Join(list, ','));
 }
 
-TEST(strings, startswith_empty) {
+TEST(strings, StartsWith_empty) {
   ASSERT_FALSE(android::base::StartsWith("", "foo"));
   ASSERT_TRUE(android::base::StartsWith("", ""));
 }
 
-TEST(strings, startswith_simple) {
+TEST(strings, StartsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
+}
+
+TEST(strings, StartsWith_simple) {
   ASSERT_TRUE(android::base::StartsWith("foo", ""));
   ASSERT_TRUE(android::base::StartsWith("foo", "f"));
   ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
   ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
 }
 
-TEST(strings, startswith_prefix_too_long) {
+TEST(strings, StartsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, StartsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
 }
 
-TEST(strings, startswith_contains_prefix) {
+TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, StartsWith_contains_prefix) {
   ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
 }
 
-TEST(strings, endswith_empty) {
+TEST(strings, StartsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
+}
+
+TEST(strings, EndsWith_empty) {
   ASSERT_FALSE(android::base::EndsWith("", "foo"));
   ASSERT_TRUE(android::base::EndsWith("", ""));
 }
 
-TEST(strings, endswith_simple) {
+TEST(strings, EndsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
+}
+
+TEST(strings, EndsWith_simple) {
   ASSERT_TRUE(android::base::EndsWith("foo", ""));
   ASSERT_TRUE(android::base::EndsWith("foo", "o"));
   ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
   ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
 }
 
-TEST(strings, endswith_prefix_too_long) {
+TEST(strings, EndsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, EndsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
 }
 
-TEST(strings, endswith_contains_prefix) {
+TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, EndsWith_contains_prefix) {
   ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
 }
+
+TEST(strings, EndsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 635af6c..3b3d698 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -102,3 +102,32 @@
            OS_PATH_SEPARATOR);
   return (mkdtemp(path) != nullptr);
 }
+
+CapturedStderr::CapturedStderr() : old_stderr_(-1) {
+  init();
+}
+
+CapturedStderr::~CapturedStderr() {
+  reset();
+}
+
+int CapturedStderr::fd() const {
+  return temp_file_.fd;
+}
+
+void CapturedStderr::init() {
+#if defined(_WIN32)
+  // On Windows, stderr is often buffered, so make sure it is unbuffered so
+  // that we can immediately read back what was written to stderr.
+  CHECK_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
+#endif
+  old_stderr_ = dup(STDERR_FILENO);
+  CHECK_NE(-1, old_stderr_);
+  CHECK_NE(-1, dup2(fd(), STDERR_FILENO));
+}
+
+void CapturedStderr::reset() {
+  CHECK_NE(-1, dup2(old_stderr_, STDERR_FILENO));
+  CHECK_EQ(0, close(old_stderr_));
+  // Note: cannot restore prior setvbuf() setting.
+}
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 89b4598..d98a9d7 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
 
 bootstat_lib_src_files = [
     "boot_event_record_store.cpp",
-    "event_log_list_builder.cpp",
     "histogram_logger.cpp",
     "uptime_parser.cpp",
 ]
@@ -88,7 +87,6 @@
     ],
     srcs: [
         "boot_event_record_store_test.cpp",
-        "event_log_list_builder_test.cpp",
         "testrunner.cpp",
     ],
 }
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 346eada..78be944 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -59,7 +59,7 @@
   // Ignore existing bootstat records (which do not contain file content).
   if (!content.empty()) {
     int32_t value;
-    if (android::base::ParseInt(content.c_str(), &value)) {
+    if (android::base::ParseInt(content, &value)) {
       bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
     }
   }
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 0ab4c98..7c0e85d 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -35,7 +35,6 @@
 #include <cutils/properties.h>
 
 #include "boot_event_record_store.h"
-#include "event_log_list_builder.h" /* ToDo: switch to liblog implementation */
 #include "histogram_logger.h"
 #include "uptime_parser.h"
 
@@ -60,7 +59,7 @@
   BootEventRecordStore boot_event_store;
   if (!value_str.empty()) {
     int32_t value = 0;
-    if (android::base::ParseInt(value_str.c_str(), &value)) {
+    if (android::base::ParseInt(value_str, &value)) {
       boot_event_store.AddBootEventWithValue(event, value);
     }
   } else {
@@ -193,7 +192,7 @@
 
   std::string build_date_str = GetProperty("ro.build.date.utc");
   int32_t build_date;
-  if (!android::base::ParseInt(build_date_str.c_str(), &build_date)) {
+  if (!android::base::ParseInt(build_date_str, &build_date)) {
     return std::string();
   }
 
diff --git a/bootstat/event_log_list_builder.cpp b/bootstat/event_log_list_builder.cpp
deleted file mode 100644
index a6af13e..0000000
--- a/bootstat/event_log_list_builder.cpp
+++ /dev/null
@@ -1,108 +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 "event_log_list_builder.h"
-
-#include <cinttypes>
-#include <memory>
-#include <string>
-
-#include <android/log.h>
-#include <android-base/logging.h>
-
-namespace {
-
-const size_t MAX_EVENT_PAYLOAD_SIZE = 512 - 1;  // Leave room for final '\n'.
-const size_t EVENT_TYPE_SIZE = 1;  // Size in bytes of the event type marker.
-
-}  // namespace
-
-EventLogListBuilder::EventLogListBuilder()
-    : payload_count_(0),
-      payload_size_(0),
-      payload_(std::make_unique<uint8_t[]>(MAX_EVENT_PAYLOAD_SIZE)) {
-  memset(payload_.get(), 0, MAX_EVENT_PAYLOAD_SIZE);
-
-  // Set up the top-level EventLog data type.
-  AppendByte(EVENT_TYPE_LIST);
-
-  // Skip over the byte prepresenting the number of items in the list. This
-  // value is set in Release().
-  payload_size_++;
-}
-
-bool EventLogListBuilder::Append(int value) {
-  DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
-  if (!IsSpaceAvailable(sizeof(value) + EVENT_TYPE_SIZE)) {
-    return false;
-  }
-
-  AppendByte(EVENT_TYPE_INT);
-  AppendData(&value, sizeof(value));
-
-  payload_count_++;
-  return true;
-}
-
-bool EventLogListBuilder::Append(const std::string& value) {
-  DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
-  int len = value.length();
-  if (!IsSpaceAvailable(sizeof(len) + len)) {
-    return false;
-  }
-
-  AppendByte(EVENT_TYPE_STRING);
-  AppendData(&len, sizeof(len));
-  AppendData(value.c_str(), len);
-
-  payload_count_++;
-  return true;
-}
-
-void EventLogListBuilder::Release(std::unique_ptr<uint8_t[]>* log,
-                                  size_t* size) {
-  // Finalize the log payload.
-  payload_[1] = payload_count_;
-
-  // Return the log payload.
-  *size = payload_size_;
-  *log = std::move(payload_);
-}
-
-void EventLogListBuilder::AppendData(const void* data, size_t size) {
-  DCHECK_LT(payload_size_ + size, MAX_EVENT_PAYLOAD_SIZE);
-  memcpy(&payload_[payload_size_], data, size);
-  payload_size_ += size;
-}
-
-void EventLogListBuilder::AppendByte(uint8_t byte) {
-  DCHECK_LT(payload_size_ + sizeof(byte), MAX_EVENT_PAYLOAD_SIZE);
-  payload_[payload_size_++] = byte;
-}
-
-bool EventLogListBuilder::IsSpaceAvailable(size_t value_size) {
-  size_t space_needed = value_size + EVENT_TYPE_SIZE;
-  if (payload_size_ + space_needed > MAX_EVENT_PAYLOAD_SIZE) {
-    size_t remaining = MAX_EVENT_PAYLOAD_SIZE - payload_size_;
-    LOG(WARNING) << "Not enough space for value. remain=" <<
-        remaining << "; needed=" << space_needed;
-    return false;
-  }
-
-  return true;
-}
diff --git a/bootstat/event_log_list_builder.h b/bootstat/event_log_list_builder.h
deleted file mode 100644
index 4e29b01..0000000
--- a/bootstat/event_log_list_builder.h
+++ /dev/null
@@ -1,70 +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.
- */
-
-#ifndef EVENT_LOG_LIST_BUILDER_H_
-#define EVENT_LOG_LIST_BUILDER_H_
-
-#include <cstdint>
-#include <memory>
-
-#include <android-base/macros.h>
-
-// EventLogListBuilder provides a mechanism to build an EventLog list
-// consisting of int and string EventLog values.
-//
-// NOTE: This class does not provide the ability to append an embedded list,
-// i.e., a list containing a list.
-class EventLogListBuilder {
- public:
-  EventLogListBuilder();
-
-  // Append a single value of a specified type.
-  bool Append(int value);
-  bool Append(const std::string& value);
-
-  // Finalizes construction of the EventLog list and releases the data
-  // to the caller. Caller takes ownership of the payload. No further calls
-  // to append* may be made once the payload is acquired by the caller.
-  void Release(std::unique_ptr<uint8_t[]>* log, size_t* size);
-
- private:
-  // Appends |data| of the given |size| to the payload.
-  void AppendData(const void* data, size_t size);
-
-  // Appends a single byte to the payload.
-  void AppendByte(uint8_t byte);
-
-  // Returns true iff the remaining capacity in |payload_| is large enough to
-  // accommodate |value_size| bytes. The space required to log the event type
-  // is included in the internal calculation so must not be passed in to
-  // |value_size|.
-  bool IsSpaceAvailable(size_t value_size);
-
-  // The number of items in the EventLog list.
-  size_t payload_count_;
-
-  // The size of the data stored in |payload_|. Used to track where to insert
-  // new data.
-  size_t payload_size_;
-
-  // The payload constructed by calls to log*. The payload may only contain
-  // MAX_EVENT_PAYLOAD (512) bytes.
-  std::unique_ptr<uint8_t[]> payload_;
-
-  DISALLOW_COPY_AND_ASSIGN(EventLogListBuilder);
-};
-
- #endif  // EVENT_LOG_LIST_BUILDER_H_
diff --git a/bootstat/event_log_list_builder_test.cpp b/bootstat/event_log_list_builder_test.cpp
deleted file mode 100644
index 8f7f323..0000000
--- a/bootstat/event_log_list_builder_test.cpp
+++ /dev/null
@@ -1,114 +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 "event_log_list_builder.h"
-
-#include <inttypes.h>
-
-#include <android/log.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using testing::ElementsAreArray;
-
-TEST(EventLogListBuilder, Empty) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    0,  // Number of items in the list.
-  };
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(2U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleInt) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    1,                // Number of items in the list.
-    EVENT_TYPE_INT,
-    42, 0, 0, 0,      // 4 byte integer value.
-  };
-
-  builder.Append(42);
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(7U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleString) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    1,                        // Number of items in the list.
-    EVENT_TYPE_STRING,
-    5, 0, 0, 0,               // 4 byte length of the string.
-    'D', 'r', 'o', 'i', 'd',
-  };
-
-  builder.Append("Droid");
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(12U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, IntThenString) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    2,                        // Number of items in the list.
-    EVENT_TYPE_INT,
-    42, 0, 0, 0,              // 4 byte integer value.
-    EVENT_TYPE_STRING,
-    5, 0, 0, 0,               // 4 byte length of the string.
-    'D', 'r', 'o', 'i', 'd',
-  };
-
-  builder.Append(42);
-  builder.Append("Droid");
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(17U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index 3144d8b..73f3295 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -17,27 +17,16 @@
 #include "histogram_logger.h"
 
 #include <cstdlib>
-#include <memory>
 
-#include <android/log.h>
 #include <android-base/logging.h>
-
-#include "event_log_list_builder.h"
+#include <log/log_event_list.h>
 
 namespace bootstat {
 
 void LogHistogram(const std::string& event, int32_t data) {
   LOG(INFO) << "Logging histogram: " << event << " " << data;
-
-  EventLogListBuilder log_builder;
-  log_builder.Append(event);
-  log_builder.Append(data);
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  log_builder.Release(&log, &size);
-
-  android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
+  android_log_event_list log(HISTOGRAM_LOG_TAG);
+  log << event << data << LOG_ID_EVENTS;
 }
 
 }  // namespace bootstat
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 0e35323..b89c395 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -51,6 +51,8 @@
 #define CANNED_LINE_LENGTH  (1024)
 #endif
 
+#define TRAILER "TRAILER!!!"
+
 static int verbose = 0;
 static int total_size = 0;
 
@@ -80,8 +82,8 @@
     } else {
         // Use the compiled-in fs_config() function.
         unsigned st_mode = s->st_mode;
-        fs_config(path, S_ISDIR(s->st_mode), target_out_path,
-                       &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        int is_dir = S_ISDIR(s->st_mode) || strcmp(path, TRAILER) == 0;
+        fs_config(path, is_dir, target_out_path, &s->st_uid, &s->st_gid, &st_mode, &capabilities);
         s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
@@ -140,7 +142,7 @@
 {
     struct stat s;
     memset(&s, 0, sizeof(s));
-    _eject(&s, "TRAILER!!!", 10, 0, 0);
+    _eject(&s, TRAILER, 10, 0, 0);
 
     while(total_size & 0xff) {
         total_size++;
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index fdedb76..155b309 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,7 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 
 common_cppflags := \
-    -std=gnu++11 \
     -W \
     -Wall \
     -Wextra \
@@ -121,6 +120,7 @@
     libbacktrace \
     libbase \
     libcutils \
+    liblog
 
 debuggerd_c_includes := \
     $(LOCAL_PATH)/test \
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index cf37701..c67d747 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <pthread.h>
+#include <sched.h>
 #include <signal.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -41,6 +42,7 @@
 #include <sys/socket.h>
 #include <sys/syscall.h>
 #include <sys/un.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include "private/libc_logging.h"
@@ -56,6 +58,13 @@
 
 static debuggerd_callbacks_t g_callbacks;
 
+// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
+#define fatal(...)                                             \
+  do {                                                         \
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", __VA_ARGS__); \
+    _exit(1);                                                  \
+  } while (0)
+
 static int socket_abstract_client(const char* name, int type) {
   sockaddr_un addr;
 
@@ -188,7 +197,7 @@
   return result;
 }
 
-static void send_debuggerd_packet() {
+static void send_debuggerd_packet(pid_t crashing_tid, pid_t pseudothread_tid) {
   // Mutex to prevent multiple crashing threads from trying to talk
   // to debuggerd at the same time.
   static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -218,7 +227,8 @@
   // that's actually in our process.
   debugger_msg_t msg;
   msg.action = DEBUGGER_ACTION_CRASH;
-  msg.tid = gettid();
+  msg.tid = crashing_tid;
+  msg.ignore_tid = pseudothread_tid;
   msg.abort_msg_address = 0;
 
   if (g_callbacks.get_abort_message) {
@@ -229,11 +239,9 @@
   if (ret == sizeof(msg)) {
     char debuggerd_ack;
     ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
-    int saved_errno = errno;
     if (g_callbacks.post_dump) {
       g_callbacks.post_dump();
     }
-    errno = saved_errno;
   } else {
     // read or write failed -- broken connection?
     __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
@@ -243,6 +251,33 @@
   close(s);
 }
 
+struct debugger_thread_info {
+  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+  pid_t crashing_tid;
+  pid_t pseudothread_tid;
+  int signal_number;
+  siginfo_t* info;
+};
+
+// Logging and contacting debuggerd requires free file descriptors, which we might not have.
+// Work around this by spawning a "thread" that shares its parent's address space, but not its file
+// descriptor table, so that we can close random file descriptors without affecting the original
+// process. Note that this doesn't go through pthread_create, so TLS is shared with the spawning
+// process.
+static void* pseudothread_stack;
+static int debuggerd_dispatch_pseudothread(void* arg) {
+  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
+
+  for (int i = 3; i < 1024; ++i) {
+    close(i);
+  }
+
+  log_signal_summary(thread_info->signal_number, thread_info->info);
+  send_debuggerd_packet(thread_info->crashing_tid, thread_info->pseudothread_tid);
+  pthread_mutex_unlock(&thread_info->mutex);
+  return 0;
+}
+
 /*
  * Catches fatal signals so we can ask debuggerd to ptrace us before
  * we crash.
@@ -254,9 +289,25 @@
     info = nullptr;
   }
 
-  log_signal_summary(signal_number, info);
+  debugger_thread_info thread_info = {
+    .crashing_tid = gettid(),
+    .signal_number = signal_number,
+    .info = info
+  };
 
-  send_debuggerd_packet();
+  pthread_mutex_lock(&thread_info.mutex);
+  pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
+                          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID,
+                          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
+
+  if (child_pid == -1) {
+    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
+  }
+
+  // Wait for the child to finish and unlock the mutex.
+  // This relies on bionic behavior that isn't guaranteed by the standard.
+  pthread_mutex_lock(&thread_info.mutex);
+
 
   // We need to return from the signal handler so that debuggerd can dump the
   // thread that crashed, but returning here does not guarantee that the signal
@@ -281,9 +332,7 @@
 
   int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
   if (rc != 0) {
-    __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to resend signal during crash: %s",
-                      strerror(errno));
-    _exit(0);
+    fatal("failed to resend signal during crash: %s", strerror(errno));
   }
 }
 
@@ -292,6 +341,23 @@
     g_callbacks = *callbacks;
   }
 
+  void* thread_stack_allocation =
+    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  if (thread_stack_allocation == MAP_FAILED) {
+    fatal("failed to allocate debuggerd thread stack");
+  }
+
+  char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
+  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+    fatal("failed to mprotect debuggerd thread stack");
+  }
+
+  // Stack grows negatively, set it to the last byte in the page...
+  stack = (stack + PAGE_SIZE - 1);
+  // and align it.
+  stack -= 15;
+  pseudothread_stack = stack;
+
   struct sigaction action;
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index 7d3509c..b0e8b17 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -1,5 +1,24 @@
+/*
+ * Copyright 2006, 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.
+ */
+
+#define LOG_TAG "crasher"
+
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <pthread.h>
 #include <sched.h>
 #include <signal.h>
@@ -141,7 +160,17 @@
 {
     fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
 
-    if (!strncmp(arg, "thread-", strlen("thread-"))) {
+    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);
+      }
+      return do_action(arg + strlen("exhaustfd-"));
+    } else if (!strncmp(arg, "thread-", strlen("thread-"))) {
         return do_action_on_thread(arg + strlen("thread-"));
     } else if (!strcmp(arg, "SIGSEGV-non-null")) {
         sigsegv_non_null();
@@ -208,6 +237,10 @@
     fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
     fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
     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/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 8b46413..867fd29 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "debuggerd"
+
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/input.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -39,16 +42,13 @@
 
 #include <selinux/android.h>
 
-#include <log/logger.h>
-
+#include <android/log.h>
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <cutils/debugger.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 
-#include <linux/input.h>
-
 #include <private/android_filesystem_config.h>
 
 #include <debuggerd/client.h>
@@ -71,6 +71,7 @@
   debugger_action_t action;
   pid_t pid, tid;
   uid_t uid, gid;
+  pid_t ignore_tid;
   uintptr_t abort_msg_address;
 };
 
@@ -227,6 +228,7 @@
 
   out_request->action = static_cast<debugger_action_t>(msg.action);
   out_request->tid = msg.tid;
+  out_request->ignore_tid = msg.ignore_tid;
   out_request->pid = cr.pid;
   out_request->uid = cr.uid;
   out_request->gid = cr.gid;
@@ -435,7 +437,7 @@
   return true;
 }
 
-static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
+static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::set<pid_t>& tids) {
   char task_path[PATH_MAX];
 
   if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
@@ -464,7 +466,7 @@
       continue;
     }
 
-    if (tid == main_tid) {
+    if (tid == main_tid || tid == ignore_tid) {
       continue;
     }
 
@@ -635,7 +637,7 @@
 
   std::set<pid_t> siblings;
   if (!attach_gdb) {
-    ptrace_siblings(request.pid, request.tid, siblings);
+    ptrace_siblings(request.pid, request.tid, request.ignore_tid, siblings);
   }
 
   // Generate the backtrace map before dropping privileges.
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
index dfa7bec..dbb878a 100644
--- a/debuggerd/getevent.cpp
+++ b/debuggerd/getevent.cpp
@@ -26,6 +26,7 @@
 #include <sys/ioctl.h>
 #include <sys/limits.h>
 #include <sys/poll.h>
+#include <unistd.h>
 
 #include <memory>
 
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
index 8225c73..aeb723b 100644
--- a/debuggerd/include/debuggerd/client.h
+++ b/debuggerd/include/debuggerd/client.h
@@ -43,6 +43,7 @@
 typedef struct __attribute__((packed)) {
   int32_t action;
   pid_t tid;
+  pid_t ignore_tid;
   uint64_t abort_msg_address;
 } debugger_msg_t;
 
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
index 4be7e6e..7fe4dee 100644
--- a/debuggerd/signal_sender.cpp
+++ b/debuggerd/signal_sender.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "debuggerd-signal"
+
 #include <errno.h>
+#include <pthread.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -24,7 +27,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <log/logger.h>
+#include <android/log.h>
 
 #include "signal_sender.h"
 
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index ebf966f..3336bcb 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -19,9 +19,8 @@
 
 #include <string>
 
-#include <android/log.h>
 #include <android-base/stringprintf.h>
-#include <log/logger.h>
+#include <log/log.h>
 
 // Forward declarations.
 class Backtrace;
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 5c7f024..b9fbe07 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -32,14 +32,14 @@
 #include <memory>
 #include <string>
 
-#include <android/log.h>
 #include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 #include <cutils/properties.h>
-#include <log/logger.h>
+#include <log/log.h>
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 #include <selinux/android.h>
 
@@ -571,14 +571,14 @@
 
     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];
       android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
-      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
-         'I', e.tag, e.message);
+         'I', (int)e.tagLen, e.tag, e.message);
       continue;
     }
 
@@ -623,9 +623,7 @@
 static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
-  char value[PROPERTY_VALUE_MAX];
-  property_get("ro.debuggable", value, "0");
-  bool want_logs = (value[0] == '1');
+  bool want_logs = __android_log_is_debuggable();
 
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e334e71..419d36c 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -27,9 +27,9 @@
 
 #include <string>
 
-#include <android/log.h>
 #include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 7112d1d..286de5b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,7 +21,6 @@
 LOCAL_C_INCLUDES := \
   $(LOCAL_PATH)/../adb \
   $(LOCAL_PATH)/../mkbootimg \
-  $(LOCAL_PATH)/../../extras/ext4_utils \
   $(LOCAL_PATH)/../../extras/f2fs_utils \
 
 LOCAL_SRC_FILES := \
@@ -38,7 +37,6 @@
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CONLYFLAGS += -std=gnu99
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
 
 LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d6b631f..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));
     }
 }
 
@@ -755,7 +757,7 @@
     max_download_size = android::base::Trim(max_download_size);
 
     uint64_t limit;
-    if (!android::base::ParseUint(max_download_size.c_str(), &limit)) {
+    if (!android::base::ParseUint(max_download_size, &limit)) {
         fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
         return 0;
     }
@@ -903,7 +905,7 @@
     if (!fb_getvar(transport, "slot-count", &var)) {
         if (supports_AB_obsolete(transport)) return 2; // Legacy support
     }
-    if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+    if (!android::base::ParseInt(var, &count)) return 0;
     return count;
 }
 
@@ -1362,7 +1364,7 @@
     }
 
     int64_t size;
-    if (!android::base::ParseInt(partition_size.c_str(), &size)) {
+    if (!android::base::ParseInt(partition_size, &size)) {
         fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
         return;
     }
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 8539e23..9b73165 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,6 @@
 #include "fs.h"
 
 #include "fastboot.h"
-#include "make_ext4fs.h"
 #include "make_f2fs.h"
 
 #include <errno.h>
@@ -12,6 +11,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <ext4_utils/make_ext4fs.h>
 #include <sparse/sparse.h>
 
 static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
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/fingerprintd/Android.mk b/fingerprintd/Android.mk
index 48b9525..55803cf 100644
--- a/fingerprintd/Android.mk
+++ b/fingerprintd/Android.mk
@@ -26,8 +26,11 @@
 LOCAL_MODULE := fingerprintd
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
+	libhidlbase \
+	libhidltransport \
 	liblog \
 	libhardware \
 	libutils \
-	libkeystore_binder
+	libkeystore_binder \
+	android.hardware.biometrics.fingerprint@2.1
 include $(BUILD_EXECUTABLE)
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index 1c7da30..0119e55 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -16,10 +16,10 @@
 
 #define LOG_TAG "fingerprintd"
 
+#include <android/hardware/biometrics/fingerprint/2.1/types.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
 #include <binder/IServiceManager.h>
-#include <hardware/hardware.h>
-#include <hardware/fingerprint.h>
-#include <hardware/hw_auth_token.h>
 #include <keystore/IKeystoreService.h>
 #include <keystore/keystore.h> // for error codes
 #include <utils/Log.h>
@@ -28,12 +28,45 @@
 
 namespace android {
 
-FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
+using hardware::hidl_string;
+using hardware::Return;
+using hardware::biometrics::fingerprint::V2_1::FingerprintMsg;
+using hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using Type = hardware::biometrics::fingerprint::V2_1::FingerprintMsgType;
+using IBiometricsFingerprint = hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
 
-// Supported fingerprint HAL version
-static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
+FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = nullptr;
+static sp<IBiometricsFingerprint> gBFP = nullptr;
+static sp<IBiometricsFingerprintClientCallback> gClientCallback = nullptr;
 
-FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
+template <typename E>
+constexpr typename std::underlying_type<E>::type to_native(E e) {
+    return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+const ssize_t hw_auth_token_size = 69;
+
+namespace hardware {
+
+class BiometricsFingerprintClientCallback : public IBiometricsFingerprintClientCallback {
+  public:
+    BiometricsFingerprintClientCallback() {};
+    virtual ~BiometricsFingerprintClientCallback() = default;
+    Return<void> notify(const FingerprintMsg& msg) {
+        FingerprintDaemonProxy::hal_notify_callback(msg);
+        return Void();
+    }
+};
+
+IBiometricsFingerprintClientCallback* HIDL_FETCH_IBiometricsFingerprintClientCallback(const char* /* name */) {
+    return new BiometricsFingerprintClientCallback();
+}
+
+} // namespace hardware
+
+FingerprintDaemonProxy::FingerprintDaemonProxy() : mCallback(nullptr) {
 
 }
 
@@ -41,76 +74,75 @@
     closeHal();
 }
 
-void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
+void FingerprintDaemonProxy::hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg) {
     FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
     const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
-    if (callback == NULL) {
+    if (callback == nullptr) {
         ALOGE("Invalid callback object");
         return;
     }
-    const int64_t device = (int64_t) instance->mDevice;
-    switch (msg->type) {
-        case FINGERPRINT_ERROR:
-            ALOGD("onError(%d)", msg->data.error);
-            callback->onError(device, msg->data.error);
+    switch (msg.type) {
+        case Type::ERROR:
+            ALOGD("onError(%d)", msg.data.error);
+            callback->onError(0, to_native(msg.data.error));
             break;
-        case FINGERPRINT_ACQUIRED:
-            ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info);
-            callback->onAcquired(device, msg->data.acquired.acquired_info);
+        case Type::ACQUIRED:
+            ALOGD("onAcquired(%d)", msg.data.acquired.acquiredInfo);
+            callback->onAcquired(0, to_native(msg.data.acquired.acquiredInfo));
             break;
-        case FINGERPRINT_AUTHENTICATED:
+        case Type::AUTHENTICATED:
             ALOGD("onAuthenticated(fid=%d, gid=%d)",
-                    msg->data.authenticated.finger.fid,
-                    msg->data.authenticated.finger.gid);
-            if (msg->data.authenticated.finger.fid != 0) {
-                const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
-                instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
+                    msg.data.authenticated.finger.fid,
+                    msg.data.authenticated.finger.gid);
+            if (msg.data.authenticated.finger.fid != 0) {
+                const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg.data.authenticated.hat);
+                instance->notifyKeystore(hat, sizeof(msg.data.authenticated.hat));
             }
-            callback->onAuthenticated(device,
-                    msg->data.authenticated.finger.fid,
-                    msg->data.authenticated.finger.gid);
+            callback->onAuthenticated(0,
+                    msg.data.authenticated.finger.fid,
+                    msg.data.authenticated.finger.gid);
             break;
-        case FINGERPRINT_TEMPLATE_ENROLLING:
+        case Type::TEMPLATE_ENROLLING:
             ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
-                    msg->data.enroll.finger.fid,
-                    msg->data.enroll.finger.gid,
-                    msg->data.enroll.samples_remaining);
-            callback->onEnrollResult(device,
-                    msg->data.enroll.finger.fid,
-                    msg->data.enroll.finger.gid,
-                    msg->data.enroll.samples_remaining);
+                    msg.data.enroll.finger.fid,
+                    msg.data.enroll.finger.gid,
+                    msg.data.enroll.samplesRemaining);
+            callback->onEnrollResult(0,
+                    msg.data.enroll.finger.fid,
+                    msg.data.enroll.finger.gid,
+                    msg.data.enroll.samplesRemaining);
             break;
-        case FINGERPRINT_TEMPLATE_REMOVED:
+        case Type::TEMPLATE_REMOVED:
             ALOGD("onRemove(fid=%d, gid=%d)",
-                    msg->data.removed.finger.fid,
-                    msg->data.removed.finger.gid);
-            callback->onRemoved(device,
-                    msg->data.removed.finger.fid,
-                    msg->data.removed.finger.gid);
+                    msg.data.removed.finger.fid,
+                    msg.data.removed.finger.gid);
+            callback->onRemoved(0,
+                    msg.data.removed.finger.fid,
+                    msg.data.removed.finger.gid);
             break;
-        case FINGERPRINT_TEMPLATE_ENUMERATING:
+        case Type::TEMPLATE_ENUMERATING:
             ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
-                    msg->data.enumerated.finger.fid,
-                    msg->data.enumerated.finger.gid,
-                    msg->data.enumerated.remaining_templates);
-            callback->onEnumerate(device,
-                    msg->data.enumerated.finger.fid,
-                    msg->data.enumerated.finger.gid,
-                    msg->data.enumerated.remaining_templates);
+                    msg.data.enumerated.finger.fid,
+                    msg.data.enumerated.finger.gid,
+                    msg.data.enumerated.remainingTemplates);
+            callback->onEnumerate(0,
+                    msg.data.enumerated.finger.fid,
+                    msg.data.enumerated.finger.gid,
+                    msg.data.enumerated.remainingTemplates);
             break;
         default:
-            ALOGE("invalid msg type: %d", msg->type);
+            ALOGE("invalid msg type: %d", msg.type);
             return;
     }
 }
 
 void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
-    if (auth_token != NULL && auth_token_length > 0) {
+    if (auth_token != nullptr && auth_token_length > 0) {
         // TODO: cache service?
         sp < IServiceManager > sm = defaultServiceManager();
         sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
         sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
-        if (service != NULL) {
+        if (service != nullptr) {
             status_t ret = service->addAuthToken(auth_token, auth_token_length);
             if (ret != ResponseCode::NO_ERROR) {
                 ALOGE("Falure sending auth token to KeyStore: %d", ret);
@@ -122,7 +154,7 @@
 }
 
 void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
-    if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
+    if (mCallback != nullptr && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
         IInterface::asBinder(mCallback)->unlinkToDeath(this);
     }
     IInterface::asBinder(callback)->linkToDeath(this);
@@ -132,49 +164,99 @@
 int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
         int32_t timeout) {
     ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
-    if (tokenSize != sizeof(hw_auth_token_t) ) {
-        ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize);
+    if (tokenSize != hw_auth_token_size) {
+        ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zd, expected %zd\n", tokenSize, hw_auth_token_size);
         return -1;
     }
-    const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
-    return mDevice->enroll(mDevice, authToken, groupId, timeout);
+
+    hardware::hidl_array<uint8_t, hw_auth_token_size> hat(token);
+    Return<RequestStatus> ret = gBFP->enroll(hat, groupId, timeout);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 uint64_t FingerprintDaemonProxy::preEnroll() {
-    return mDevice->pre_enroll(mDevice);
+    return gBFP->preEnroll();
 }
 
 int32_t FingerprintDaemonProxy::postEnroll() {
-    return mDevice->post_enroll(mDevice);
+    Return<RequestStatus> ret = gBFP->postEnroll();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int32_t FingerprintDaemonProxy::stopEnrollment() {
     ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
-    return mDevice->cancel(mDevice);
+    Return<RequestStatus> ret = gBFP->cancel();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
     ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
-    return mDevice->authenticate(mDevice, sessionId, groupId);
+    Return<RequestStatus> ret = gBFP->authenticate(sessionId, groupId);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int32_t FingerprintDaemonProxy::stopAuthentication() {
     ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
-    return mDevice->cancel(mDevice);
+    Return<RequestStatus> ret = gBFP->cancel();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
     ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
-    return mDevice->remove(mDevice, groupId, fingerId);
+    Return<RequestStatus> ret = gBFP->remove(groupId, fingerId);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int32_t FingerprintDaemonProxy::enumerate() {
     ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
-    return mDevice->enumerate(mDevice);
+    Return<RequestStatus> ret = gBFP->enumerate();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
-    return mDevice->get_authenticator_id(mDevice);
+    return gBFP->getAuthenticatorId();
 }
 
 int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
@@ -183,74 +265,35 @@
         ALOGE("Bad path length: %zd", pathlen);
         return -1;
     }
-    // Convert to null-terminated string
-    char path_name[PATH_MAX];
-    memcpy(path_name, path, pathlen);
-    path_name[pathlen] = '\0';
-    ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen);
-    return mDevice->set_active_group(mDevice, groupId, path_name);
+    hidl_string pathname;
+    pathname.setToExternal(reinterpret_cast<const char*>(path), pathlen);
+    ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, pathname.c_str(), pathlen);
+    Return<RequestStatus> ret = gBFP->setActiveGroup(groupId, pathname);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Unknown transport error");
+        return -1;
+    }
+
+    RequestStatus status = ret;
+    return to_native(status);
 }
 
 int64_t FingerprintDaemonProxy::openHal() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
-    int err;
-    const hw_module_t *hw_module = NULL;
-    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
-        ALOGE("Can't open fingerprint HW Module, error: %d", err);
-        return 0;
+    if (gBFP == nullptr) {
+        // TODO(b/31632518)
+        gBFP = IBiometricsFingerprint::getService("fingerprint");
+        if(gBFP == nullptr) {
+            ALOGE("Can't get service fingerprint");
+            return 0;
+        }
     }
-    if (NULL == hw_module) {
-        ALOGE("No valid fingerprint module");
-        return 0;
-    }
-
-    mModule = reinterpret_cast<const fingerprint_module_t*>(hw_module);
-
-    if (mModule->common.methods->open == NULL) {
-        ALOGE("No valid open method");
-        return 0;
-    }
-
-    hw_device_t *device = NULL;
-
-    if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) {
-        ALOGE("Can't open fingerprint methods, error: %d", err);
-        return 0;
-    }
-
-    if (kVersion != device->version) {
-        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
-        // return 0; // FIXME
-    }
-
-    mDevice = reinterpret_cast<fingerprint_device_t*>(device);
-    err = mDevice->set_notify(mDevice, hal_notify_callback);
-    if (err < 0) {
-        ALOGE("Failed in call to set_notify(), err=%d", err);
-        return 0;
-    }
-
-    // Sanity check - remove
-    if (mDevice->notify != hal_notify_callback) {
-        ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback);
-    }
-
-    ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
-    return reinterpret_cast<int64_t>(mDevice); // This is just a handle
+    gClientCallback = hardware::HIDL_FETCH_IBiometricsFingerprintClientCallback(nullptr);
+    gBFP->setNotify(gClientCallback);
+    return reinterpret_cast<int64_t>(gBFP.get());
 }
 
 int32_t FingerprintDaemonProxy::closeHal() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");
-    if (mDevice == NULL) {
-        ALOGE("No valid device");
-        return -ENOSYS;
-    }
-    int err;
-    if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
-        ALOGE("Can't close fingerprint module, error: %d", err);
-        return err;
-    }
-    mDevice = NULL;
+    // Obsolete, return 0 for compatibility reasons.
     return 0;
 }
 
@@ -261,8 +304,8 @@
         ALOGE("Can't close fingerprint device, error: %d", err);
     }
     if (IInterface::asBinder(mCallback) == who) {
-        mCallback = NULL;
+        mCallback = nullptr;
     }
 }
 
-}
+} // namespace android
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 145b4c9..715344c 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -22,6 +22,8 @@
 
 namespace android {
 
+using hardware::biometrics::fingerprint::V2_1::RequestStatus;
+
 class FingerprintDaemonProxy : public BnFingerprintDaemon {
     public:
         static FingerprintDaemonProxy* getInstance() {
@@ -45,17 +47,16 @@
         virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
         virtual int64_t openHal();
         virtual int32_t closeHal();
+        static void hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg);
 
     private:
         FingerprintDaemonProxy();
         virtual ~FingerprintDaemonProxy();
         void binderDied(const wp<IBinder>& who);
         void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length);
-        static void hal_notify_callback(const fingerprint_msg_t *msg);
+        int32_t HandleTransportError(const RequestStatus error);
 
         static FingerprintDaemonProxy* sInstance;
-        fingerprint_module_t const* mModule;
-        fingerprint_device_t* mDevice;
         sp<IFingerprintDaemonCallback> mCallback;
 };
 
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 23c36ff..c5cdbfe 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -17,6 +17,8 @@
 #ifndef IFINGERPRINT_DAEMON_H_
 #define IFINGERPRINT_DAEMON_H_
 
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/types.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 
@@ -69,7 +71,7 @@
 
         // DECLARE_META_INTERFACE - C++ client interface not needed
         static const android::String16 descriptor;
-        static void hal_notify_callback(const fingerprint_msg_t *msg);
+        static void hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index b11ce75..f682216 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/swap.h>
@@ -30,19 +31,19 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <ext4.h>
-#include <ext4_crypt_init_extensions.h>
-#include <ext4_sb.h>
-
 #include <cutils/android_reboot.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
+#include <ext4_utils/ext4.h>
+#include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <ext4_utils/ext4_sb.h>
+#include <ext4_utils/ext4_utils.h>
+#include <ext4_utils/wipe.h>
+#include <linux/fs.h>
 #include <linux/loop.h>
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
-
-#include "ext4_utils.h"
-#include "wipe.h"
+#include <private/android_logger.h>
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
@@ -51,12 +52,14 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
-#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
+#define F2FS_FSCK_BIN   "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
+#define TUNE2FS_BIN     "/system/bin/tune2fs"
 
 #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)))
 
@@ -180,6 +183,99 @@
     return;
 }
 
+/* Function to read the primary superblock */
+static int read_super_block(int fd, struct ext4_super_block *sb)
+{
+    off64_t ret;
+
+    ret = lseek64(fd, 1024, SEEK_SET);
+    if (ret < 0)
+        return ret;
+
+    ret = read(fd, sb, sizeof(*sb));
+    if (ret < 0)
+        return ret;
+    if (ret != sizeof(*sb))
+        return ret;
+
+    return 0;
+}
+
+static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_blocks_count_lo);
+}
+
+static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_r_blocks_count_lo);
+}
+
+static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+    /* Check for the types of filesystems we know how to check */
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+        /*
+         * Some system images do not have tune2fs for licensing reasons
+         * Detect these and skip reserve blocks.
+         */
+        if (access(TUNE2FS_BIN, X_OK)) {
+            ERROR("Not running %s on %s (executable not in system image)\n",
+                  TUNE2FS_BIN, blk_device);
+        } else {
+            INFO("Running %s on %s\n", TUNE2FS_BIN, blk_device);
+
+            int status = 0;
+            int ret = 0;
+            unsigned long reserved_blocks = 0;
+            int fd = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+            if (fd >= 0) {
+                struct ext4_super_block sb;
+                ret = read_super_block(fd, &sb);
+                if (ret < 0) {
+                    ERROR("Can't read '%s' super block: %s\n", blk_device, strerror(errno));
+                    goto out;
+                }
+                reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
+                unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
+                if (reserved_threshold < reserved_blocks) {
+                    WARNING("Reserved blocks %lu is too large\n", reserved_blocks);
+                    reserved_blocks = reserved_threshold;
+                }
+
+                if (ext4_r_blocks_count(&sb) == reserved_blocks) {
+                    INFO("Have reserved same blocks\n");
+                    goto out;
+                }
+            } else {
+                ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+                return;
+            }
+
+            char buf[16] = {0};
+            snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
+            char *tune2fs_argv[] = {
+                TUNE2FS_BIN,
+                buf,
+                blk_device,
+            };
+
+            ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), tune2fs_argv,
+                                          &status, true, LOG_KLOG | LOG_FILE,
+                                          true, NULL, NULL, 0);
+
+            if (ret < 0) {
+                /* No need to check for error in fork, we can't really handle it now */
+                ERROR("Failed trying to run %s\n", TUNE2FS_BIN);
+            }
+      out:
+            close(fd);
+        }
+    }
+}
+
 static void remove_trailing_slashes(char *n)
 {
     int len;
@@ -242,7 +338,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;
@@ -262,15 +358,6 @@
     return ret;
 }
 
-static int device_is_debuggable() {
-    int ret = -1;
-    char value[PROP_VALUE_MAX];
-    ret = __system_property_get("ro.debuggable", value);
-    if (ret < 0)
-        return ret;
-    return strcmp(value, "1") ? 0 : 1;
-}
-
 static int device_is_secure() {
     int ret = -1;
     char value[PROP_VALUE_MAX];
@@ -334,6 +421,12 @@
                 check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
                          fstab->recs[i].mount_point);
             }
+
+            if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+                do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                                 &fstab->recs[i]);
+            }
+
             if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
                 *attempted_idx = i;
                 mounted = 1;
@@ -539,7 +632,7 @@
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
-            if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                 ERROR("Could not set up verified partition, skipping!\n");
@@ -661,7 +754,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;
@@ -699,9 +792,13 @@
                      fstab->recs[i].mount_point);
         }
 
+        if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+            do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
+        }
+
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
-            if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                 ERROR("Could not set up verified partition, skipping!\n");
@@ -812,6 +909,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) {
@@ -905,7 +1014,7 @@
 {
     if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
         int rc = fs_mgr_setup_verity(fstab_rec);
-        if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+        if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
             INFO("Verity disabled");
             return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
         } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index 7ee5832..7c3b1ed 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -24,13 +24,13 @@
 #include <cutils/partition_utils.h>
 #include <sys/mount.h>
 
+#include <ext4_utils/ext4_utils.h>
+#include <ext4_utils/ext4.h>
+#include <ext4_utils/make_ext4fs.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
 
-#include "ext4_utils.h"
-#include "ext4.h"
-#include "make_ext4fs.h"
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index f03b2dd..f25d10c 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -31,7 +31,9 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
     unsigned int file_encryption_mode;
 };
 
@@ -72,6 +74,8 @@
     { "recoveryonly",MF_RECOVERYONLY },
     { "swapprio=",   MF_SWAPPRIO },
     { "zramsize=",   MF_ZRAMSIZE },
+    { "max_comp_streams=",   MF_MAX_COMP_STREAMS },
+    { "verifyatboot", MF_VERIFYATBOOT },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
     { "notrim",       MF_NOTRIM },
@@ -79,6 +83,7 @@
     { "slotselect",  MF_SLOTSELECT },
     { "nofail",      MF_NOFAIL },
     { "latemount",   MF_LATEMOUNT },
+    { "reservedsize=", MF_RESERVEDSIZE },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -105,6 +110,20 @@
     return total;
 }
 
+static uint64_t parse_size(const char *arg)
+{
+    char *endptr;
+    uint64_t size = strtoull(arg, &endptr, 10);
+    if (*endptr == 'k' || *endptr == 'K')
+        size *= 1024LL;
+    else if (*endptr == 'm' || *endptr == 'M')
+        size *= 1024LL * 1024LL;
+    else if (*endptr == 'g' || *endptr == 'G')
+        size *= 1024LL * 1024LL * 1024LL;
+
+    return size;
+}
+
 static int parse_flags(char *flags, struct flag_list *fl,
                        struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
@@ -205,6 +224,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);
@@ -212,6 +233,11 @@
                         flag_vals->zram_size = calculate_zram_size(val);
                     else
                         flag_vals->zram_size = val;
+                } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+                    /* The reserved flag is followed by an = and the
+                     * reserved size of the partition.  Get it and return it.
+                     */
+                    flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
                 }
                 break;
             }
@@ -354,7 +380,9 @@
         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;
+        fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
         fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
         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..4632521 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -85,6 +85,9 @@
 #define MF_FORCEFDEORFBE 0x10000
 #define MF_LATEMOUNT    0x20000
 #define MF_NOFAIL       0x40000
+#define MF_VERIFYATBOOT 0x80000
+#define MF_MAX_COMP_STREAMS 0x100000
+#define MF_RESERVEDSIZE 0x200000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 7fe6763..bb61b93 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -32,6 +32,7 @@
 #include <android-base/file.h>
 #include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
+#include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
 #include <openssl/obj_mac.h>
@@ -73,6 +74,8 @@
 #define VERITY_KMSG_RESTART "dm-verity device corrupted"
 #define VERITY_KMSG_BUFSIZE 1024
 
+#define READ_BUF_SIZE 4096
+
 #define __STRINGIFY(x) #x
 #define STRINGIFY(x) __STRINGIFY(x)
 
@@ -205,6 +208,16 @@
     return 0;
 }
 
+static int destroy_verity_device(struct dm_ioctl *io, char *name, int fd)
+{
+    verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_REMOVE, io)) {
+        ERROR("Error removing device mapping (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
 static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
 {
     verity_ioctl_init(io, name, 0);
@@ -341,6 +354,17 @@
     return 0;
 }
 
+static int test_access(char *device) {
+    int tries = 25;
+    while (tries--) {
+        if (!access(device, F_OK) || errno != ENOENT) {
+            return 0;
+        }
+        usleep(40 * 1000);
+    }
+    return -1;
+}
+
 static int check_verity_restart(const char *fname)
 {
     char buffer[VERITY_KMSG_BUFSIZE + 1];
@@ -595,6 +619,30 @@
     return rc;
 }
 
+static int read_partition(const char *path, uint64_t size)
+{
+    char buf[READ_BUF_SIZE];
+    ssize_t size_read;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s: %s\n", path, strerror(errno));
+        return -errno;
+    }
+
+    while (size) {
+        size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
+        if (size_read == -1) {
+            ERROR("Error in reading partition %s: %s\n", path,
+                  strerror(errno));
+            return -errno;
+        }
+        size -= size_read;
+    }
+
+    return 0;
+}
+
 static int compare_last_signature(struct fstab_rec *fstab, int *match)
 {
     char tag[METADATA_TAG_MAX_LENGTH + 1];
@@ -777,7 +825,7 @@
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     const char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
-    char *status;
+    const char *status;
     int fd = -1;
     int i;
     int mode;
@@ -827,9 +875,13 @@
         verity_ioctl_init(io, mount_point, 0);
 
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
-            ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
-                strerror(errno));
-            continue;
+            if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
+                status = "V";
+            } else {
+                ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
+                      strerror(errno));
+                continue;
+            }
         }
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
@@ -893,6 +945,7 @@
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
+    bool verified_at_boot = false;
 
     if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
             FEC_DEFAULT_ROOTS) < 0) {
@@ -1026,10 +1079,31 @@
     // mark the underlying block device as read-only
     fs_mgr_set_blk_ro(fstab->blk_device);
 
+    // Verify the entire partition in one go
+    // If there is an error, allow it to mount as a normal verity partition.
+    if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
+        INFO("Verifying partition %s at boot\n", fstab->blk_device);
+        int err = read_partition(verity_blk_name, verity.data_size);
+        if (!err) {
+            INFO("Verified verity partition %s at boot\n", fstab->blk_device);
+            verified_at_boot = true;
+        }
+    }
+
     // assign the new verity block device as the block device
-    free(fstab->blk_device);
-    fstab->blk_device = verity_blk_name;
-    verity_blk_name = 0;
+    if (!verified_at_boot) {
+        free(fstab->blk_device);
+        fstab->blk_device = verity_blk_name;
+        verity_blk_name = 0;
+    } else if (destroy_verity_device(io, mount_point, fd) < 0) {
+        ERROR("Failed to remove verity device %s\n", mount_point);
+        goto out;
+    }
+
+    // make sure we've set everything up properly
+    if (test_access(fstab->blk_device) < 0) {
+        goto out;
+    }
 
     retval = FS_MGR_SETUP_VERITY_SUCCESS;
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b43847c..8ecc93c 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -73,7 +73,9 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
     unsigned int file_encryption_mode;
 };
 
@@ -97,7 +99,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/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 3f78955..0dfd9d8 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -33,7 +33,12 @@
 	libbase \
 	libutils \
 	libcrypto \
-	libkeystore_binder
+	libkeystore_binder \
+	libhidlbase \
+	libhidltransport \
+	libhwbinder \
+	android.hardware.gatekeeper@1.0 \
+
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := external/scrypt/lib/crypto
 LOCAL_INIT_RC := gatekeeperd.rc
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 4107f55..d2c119d 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -39,6 +39,15 @@
 #include "SoftGateKeeperDevice.h"
 #include "IUserManager.h"
 
+#include <hidl/HidlSupport.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+using android::sp;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using android::hardware::Return;
+
 namespace android {
 
 static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
@@ -47,28 +56,22 @@
 class GateKeeperProxy : public BnGateKeeperService {
 public:
     GateKeeperProxy() {
-        int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
-        device = NULL;
+        hw_device = IGatekeeper::getService("gatekeeper");
 
-        if (ret < 0) {
+        if (hw_device == nullptr) {
             ALOGW("falling back to software GateKeeper");
             soft_device.reset(new SoftGateKeeperDevice());
-        } else {
-            ret = gatekeeper_open(module, &device);
-            if (ret < 0)
-                LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
         }
 
         if (mark_cold_boot()) {
             ALOGI("cold boot: clearing state");
-            if (device != NULL && device->delete_all_users != NULL) {
-                device->delete_all_users(device);
+            if (hw_device != nullptr) {
+                hw_device->deleteAllUsers([](const GatekeeperResponse &){});
             }
         }
     }
 
     virtual ~GateKeeperProxy() {
-        if (device) gatekeeper_close(device);
     }
 
     void store_sid(uint32_t uid, uint64_t sid) {
@@ -141,7 +144,7 @@
         if (desired_password_length == 0) return -EINVAL;
 
         int ret;
-        if (device) {
+        if (hw_device != nullptr) {
             const gatekeeper::password_handle_t *handle =
                     reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
 
@@ -154,10 +157,37 @@
                 current_password_length = 0;
             }
 
-            ret = device->enroll(device, uid, current_password_handle, current_password_handle_length,
-                    current_password, current_password_length,
-                    desired_password, desired_password_length,
-                    enrolled_password_handle, enrolled_password_handle_length);
+            android::hardware::hidl_vec<uint8_t> curPwdHandle;
+            curPwdHandle.setToExternal(const_cast<uint8_t*>(current_password_handle),
+                                       current_password_handle_length);
+            android::hardware::hidl_vec<uint8_t> curPwd;
+            curPwd.setToExternal(const_cast<uint8_t*>(current_password),
+                                 current_password_length);
+            android::hardware::hidl_vec<uint8_t> newPwd;
+            newPwd.setToExternal(const_cast<uint8_t*>(desired_password),
+                                 desired_password_length);
+
+            Return<void> hwRes = hw_device->enroll(uid, curPwdHandle, curPwd, newPwd,
+                              [&ret, enrolled_password_handle, enrolled_password_handle_length]
+                                   (const GatekeeperResponse &rsp) {
+                ret = static_cast<int>(rsp.code); // propagate errors
+                if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+                    if (enrolled_password_handle != nullptr &&
+                        enrolled_password_handle_length != nullptr) {
+                        *enrolled_password_handle = new uint8_t[rsp.data.size()];
+                        *enrolled_password_handle_length = rsp.data.size();
+                        memcpy(*enrolled_password_handle, rsp.data.data(),
+                               *enrolled_password_handle_length);
+                    }
+                    ret = 0; // all success states are reported as 0
+                } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) {
+                    ret = rsp.timeout;
+                }
+            });
+            if (!hwRes.getStatus().isOk()) {
+                ALOGE("enroll transaction failed\n");
+                ret = -1;
+            }
         } else {
             ret = soft_device->enroll(uid,
                     current_password_handle, current_password_handle_length,
@@ -207,16 +237,40 @@
             return -EINVAL;
 
         int ret;
-        if (device) {
+        if (hw_device != nullptr) {
             const gatekeeper::password_handle_t *handle =
                     reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);
             // handle version 0 does not have hardware backed flag, and thus cannot be upgraded to
             // a HAL if there was none before
             if (handle->version == 0 || handle->hardware_backed) {
-                ret = device->verify(device, uid, challenge,
-                    enrolled_password_handle, enrolled_password_handle_length,
-                    provided_password, provided_password_length, auth_token, auth_token_length,
-                    request_reenroll);
+                android::hardware::hidl_vec<uint8_t> curPwdHandle;
+                curPwdHandle.setToExternal(const_cast<uint8_t*>(enrolled_password_handle),
+                                           enrolled_password_handle_length);
+                android::hardware::hidl_vec<uint8_t> enteredPwd;
+                enteredPwd.setToExternal(const_cast<uint8_t*>(provided_password),
+                                         provided_password_length);
+                Return<void> hwRes = hw_device->verify(uid, challenge, curPwdHandle, enteredPwd,
+                                        [&ret, request_reenroll, auth_token, auth_token_length]
+                                             (const GatekeeperResponse &rsp) {
+                    ret = static_cast<int>(rsp.code); // propagate errors
+                    if (auth_token != nullptr && auth_token_length != nullptr &&
+                        rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+                        *auth_token = new uint8_t[rsp.data.size()];
+                        *auth_token_length = rsp.data.size();
+                        memcpy(*auth_token, rsp.data.data(), *auth_token_length);
+                        if (request_reenroll != nullptr) {
+                            *request_reenroll = (rsp.code == GatekeeperStatusCode::STATUS_REENROLL);
+                        }
+                        ret = 0; // all success states are reported as 0
+                    } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
+                               rsp.timeout > 0) {
+                        ret = rsp.timeout;
+                    }
+                });
+                if (!hwRes.getStatus().isOk()) {
+                    ALOGE("verify transaction failed\n");
+                    ret = -1;
+                }
             } else {
                 // upgrade scenario, a HAL has been added to this device where there was none before
                 SoftGateKeeperDevice soft_dev;
@@ -288,8 +342,8 @@
         }
         clear_sid(uid);
 
-        if (device != NULL && device->delete_user != NULL) {
-            device->delete_user(device, uid);
+        if (hw_device != nullptr) {
+            hw_device->deleteUser(uid, [] (const GatekeeperResponse &){});
         }
     }
 
@@ -301,7 +355,7 @@
             return PERMISSION_DENIED;
         }
 
-        if (device == NULL) {
+        if (hw_device == NULL) {
             const char *result = "Device not available";
             write(fd, result, strlen(result) + 1);
         } else {
@@ -313,9 +367,8 @@
     }
 
 private:
-    gatekeeper_device_t *device;
+    sp<IGatekeeper> hw_device;
     UniquePtr<SoftGateKeeperDevice> soft_device;
-    const hw_module_t *module;
 };
 }// namespace android
 
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 7c5e35b..8b59964 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,16 +3,6 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := healthd_board_default.cpp
-LOCAL_MODULE := libhealthd.default
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libbinder
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
 LOCAL_SRC_FILES := BatteryMonitor.cpp
 LOCAL_MODULE := libbatterymonitor
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
@@ -23,20 +13,45 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := \
     healthd_mode_android.cpp \
-    healthd_mode_charger.cpp \
-    AnimationParser.cpp \
-    BatteryPropertiesRegistrar.cpp \
+    BatteryPropertiesRegistrar.cpp
 
-LOCAL_MODULE := libhealthd_internal
-LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_MODULE := libhealthd_android
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
     $(LOCAL_PATH) \
-    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/include
 
 LOCAL_STATIC_LIBRARIES := \
     libbatterymonitor \
     libbatteryservice \
-    libbinder \
+    libutils \
+    libbase \
+    libcutils \
+    liblog \
+    libc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Werror
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_SRC_FILES := \
+    healthd_mode_charger.cpp \
+    AnimationParser.cpp
+
+LOCAL_MODULE := libhealthd_charger
+LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
     libminui \
     libpng \
     libz \
@@ -47,11 +62,14 @@
     libm \
     libc \
 
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
 include $(BUILD_STATIC_LIBRARY)
 
-
+### charger ###
 include $(CLEAR_VARS)
-
 ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
 LOCAL_CHARGER_NO_UI := true
 endif
@@ -60,72 +78,57 @@
 endif
 
 LOCAL_SRC_FILES := \
-	healthd.cpp \
-	healthd_mode_android.cpp \
-	BatteryPropertiesRegistrar.cpp \
+    healthd_common.cpp \
+    charger.cpp \
 
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_SRC_FILES += healthd_mode_charger.cpp
-endif
-
-LOCAL_MODULE := healthd
+LOCAL_MODULE := charger
 LOCAL_MODULE_TAGS := optional
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
-LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
+LOCAL_CFLAGS := -Werror
 ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 LOCAL_CFLAGS += -DCHARGER_NO_UI
 endif
-
-LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
-    libhealthd_internal \
-    libbatterymonitor \
-    libbatteryservice \
-    libbinder \
-    libbase \
-
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_STATIC_LIBRARIES += \
-   libminui \
-   libpng \
-   libz \
-
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+endif
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
 endif
 
-
-LOCAL_STATIC_LIBRARIES += \
+LOCAL_STATIC_LIBRARIES := \
+    libhealthd_charger \
+    libbatterymonitor \
+    libbase \
     libutils \
     libcutils \
     liblog \
     libm \
     libc \
 
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_STATIC_LIBRARIES += \
+    libminui \
+    libpng \
+    libz \
+
+endif
+
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
 LOCAL_STATIC_LIBRARIES += libsuspend
 endif
 
 LOCAL_HAL_STATIC_LIBRARIES := libhealthd
 
-# Symlink /charger to /sbin/healthd
+# Symlink /charger to /sbin/charger
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
-    && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+    && ln -sf /sbin/charger $(TARGET_ROOT_OUT)/charger
 
 include $(BUILD_EXECUTABLE)
 
-
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 define _add-charger-image
 include $$(CLEAR_VARS)
@@ -153,3 +156,41 @@
 _add-charger-image :=
 _img_modules :=
 endif # LOCAL_CHARGER_NO_UI
+
+### healthd ###
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    healthd_common.cpp \
+    healthd.cpp \
+
+LOCAL_MODULE := healthd
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+endif
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    libhealthd_android \
+    libbatterymonitor \
+    libbatteryservice \
+    android.hardware.health@1.0-convert \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libbase \
+    libutils \
+    libcutils \
+    liblog \
+    libm \
+    libc \
+    libhidlbase \
+    libhidltransport \
+    android.hardware.health@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index f81e7d9..0c90a54 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -29,6 +29,7 @@
 #include <memory>
 
 #include <android-base/file.h>
+#include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
@@ -182,7 +183,7 @@
     int value = 0;
 
     if (readFromFile(path, &buf) > 0)
-        value = std::stoi(buf.c_str(), NULL, 0);
+        android::base::ParseInt(buf, &value);
 
     return value;
 }
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
new file mode 100644
index 0000000..5a8fe1a
--- /dev/null
+++ b/healthd/charger.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "charger"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/klog.h>
+
+using namespace android;
+
+// main healthd loop
+extern int healthd_main(void);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops healthd_nops = {
+    .init = healthd_mode_nop_init,
+    .preparetowait = healthd_mode_nop_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_nop_battery_update,
+};
+
+#ifdef CHARGER_NO_UI
+static struct healthd_mode_ops charger_ops = healthd_nops;
+#else
+static struct healthd_mode_ops charger_ops = {
+    .init = healthd_mode_charger_init,
+    .preparetowait = healthd_mode_charger_preparetowait,
+    .heartbeat = healthd_mode_charger_heartbeat,
+    .battery_update = healthd_mode_charger_battery_update,
+};
+#endif
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+    return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties* /*props*/) {
+}
+
+int main(int argc, char **argv) {
+    int ch;
+
+    healthd_mode_ops = &charger_ops;
+
+    while ((ch = getopt(argc, argv, "cr")) != -1) {
+        switch (ch) {
+            case 'c':
+                // -c is now a noop
+                break;
+            case 'r':
+                // force nops for recovery
+                healthd_mode_ops = &healthd_nops;
+                break;
+            case '?':
+            default:
+                KLOG_ERROR(LOG_TAG, "Unrecognized charger option: %c\n",
+                        optopt);
+                exit(1);
+        }
+    }
+
+    return healthd_main();
+}
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 20a6bf6..cae6c4c 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -18,355 +18,106 @@
 #define KLOG_LEVEL 6
 
 #include <healthd/healthd.h>
-#include <healthd/BatteryMonitor.h>
 
-#include <errno.h>
-#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <unistd.h>
-#include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <utils/Errors.h>
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <android/hardware/health/1.0/types.h>
+#include <hal_conversion.h>
 
 using namespace android;
 
-// Periodic chores intervals in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+using IHealth = ::android::hardware::health::V1_0::IHealth;
+using Result = ::android::hardware::health::V1_0::Result;
+using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
+using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
 
-static struct healthd_config healthd_config = {
-    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
-    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
-    .batteryStatusPath = String8(String8::kEmptyString),
-    .batteryHealthPath = String8(String8::kEmptyString),
-    .batteryPresentPath = String8(String8::kEmptyString),
-    .batteryCapacityPath = String8(String8::kEmptyString),
-    .batteryVoltagePath = String8(String8::kEmptyString),
-    .batteryTemperaturePath = String8(String8::kEmptyString),
-    .batteryTechnologyPath = String8(String8::kEmptyString),
-    .batteryCurrentNowPath = String8(String8::kEmptyString),
-    .batteryCurrentAvgPath = String8(String8::kEmptyString),
-    .batteryChargeCounterPath = String8(String8::kEmptyString),
-    .batteryFullChargePath = String8(String8::kEmptyString),
-    .batteryCycleCountPath = String8(String8::kEmptyString),
-    .energyCounter = NULL,
-    .boot_min_cap = 0,
-    .screen_on = NULL,
-};
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
 
-static int eventct;
-static int epollfd;
+// device specific hal interface;
+static sp<IHealth> gHealth;
 
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-// epoll_create() parameter is actually unused
-#define MAX_EPOLL_EVENTS 40
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-static BatteryMonitor* gBatteryMonitor;
-
-struct healthd_mode_ops *healthd_mode_ops;
+// main healthd loop
+extern int healthd_main(void);
 
 // Android mode
-
 extern void healthd_mode_android_init(struct healthd_config *config);
 extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_heartbeat(void);
 extern void healthd_mode_android_battery_update(
     struct android::BatteryProperties *props);
 
-// Charger mode
-
-extern void healthd_mode_charger_init(struct healthd_config *config);
-extern int healthd_mode_charger_preparetowait(void);
-extern void healthd_mode_charger_heartbeat(void);
-extern void healthd_mode_charger_battery_update(
-    struct android::BatteryProperties *props);
-
-// NOPs for modes that need no special action
-
-static void healthd_mode_nop_init(struct healthd_config *config);
-static int healthd_mode_nop_preparetowait(void);
-static void healthd_mode_nop_heartbeat(void);
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties *props);
-
 static struct healthd_mode_ops android_ops = {
     .init = healthd_mode_android_init,
     .preparetowait = healthd_mode_android_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
+    .heartbeat = healthd_mode_android_heartbeat,
     .battery_update = healthd_mode_android_battery_update,
 };
 
-static struct healthd_mode_ops charger_ops = {
-#ifdef CHARGER_NO_UI
-    .init = healthd_mode_nop_init,
-    .preparetowait = healthd_mode_nop_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
-    .battery_update = healthd_mode_nop_battery_update,
-#else
-    .init = healthd_mode_charger_init,
-    .preparetowait = healthd_mode_charger_preparetowait,
-    .heartbeat = healthd_mode_charger_heartbeat,
-    .battery_update = healthd_mode_charger_battery_update,
-#endif
-};
+// default energy counter property redirect to talk to device
+// HAL
+static int healthd_board_get_energy_counter(int64_t *energy) {
 
-static struct healthd_mode_ops recovery_ops = {
-    .init = healthd_mode_nop_init,
-    .preparetowait = healthd_mode_nop_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
-    .battery_update = healthd_mode_nop_battery_update,
-};
-
-static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
-}
-
-static int healthd_mode_nop_preparetowait(void) {
-    return -1;
-}
-
-static void healthd_mode_nop_heartbeat(void) {
-}
-
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties* /*props*/) {
-}
-
-int healthd_register_event(int fd, void (*handler)(uint32_t)) {
-    struct epoll_event ev;
-
-    ev.events = EPOLLIN | EPOLLWAKEUP;
-    ev.data.ptr = (void *)handler;
-    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "epoll_ctl failed; errno=%d\n", errno);
-        return -1;
+    if (gHealth == nullptr) {
+        return NAME_NOT_FOUND;
     }
 
-    eventct++;
-    return 0;
+    Result result = Result::NOT_SUPPORTED;
+    gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) {
+                result = ret;
+                *energy = energyOut;
+            });
+
+    return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
 }
 
-static void wakealarm_set_interval(int interval) {
-    struct itimerspec itval;
+void healthd_board_init(struct healthd_config *config) {
 
-    if (wakealarm_fd == -1)
-            return;
+    // Initialize the board HAL - Equivalent of healthd_board_init(config)
+    // in charger/recovery mode.
 
-    wakealarm_wake_interval = interval;
-
-    if (interval == -1)
-        interval = 0;
-
-    itval.it_interval.tv_sec = interval;
-    itval.it_interval.tv_nsec = 0;
-    itval.it_value.tv_sec = interval;
-    itval.it_value.tv_nsec = 0;
-
-    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
-        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-status_t healthd_get_property(int id, struct BatteryProperty *val) {
-    return gBatteryMonitor->getProperty(id, val);
-}
-
-void healthd_battery_update(void) {
-    // Fast wake interval when on charger (watch for overheat);
-    // slow wake interval when on battery (watch for drained battery).
-
-   int new_wake_interval = gBatteryMonitor->update() ?
-       healthd_config.periodic_chores_interval_fast :
-           healthd_config.periodic_chores_interval_slow;
-
-    if (new_wake_interval != wakealarm_wake_interval)
-            wakealarm_set_interval(new_wake_interval);
-
-    // During awake periods poll at fast rate.  If wake alarm is set at fast
-    // rate then just use the alarm; if wake alarm is set at slow rate then
-    // poll at fast rate while awake and let alarm wake up at slow rate when
-    // asleep.
-
-    if (healthd_config.periodic_chores_interval_fast == -1)
-        awake_poll_interval = -1;
-    else
-        awake_poll_interval =
-            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
-                -1 : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-void healthd_dump_battery_state(int fd) {
-    gBatteryMonitor->dumpState(fd);
-    fsync(fd);
-}
-
-static void periodic_chores() {
-    healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
-    char msg[UEVENT_MSG_LEN+2];
-    char *cp;
-    int n;
-
-    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
-    if (n <= 0)
-        return;
-    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
-        return;
-
-    msg[n] = '\0';
-    msg[n+1] = '\0';
-    cp = msg;
-
-    while (*cp) {
-        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
-            healthd_battery_update();
-            break;
-        }
-
-        /* advance to after the next \0 */
-        while (*cp++)
-            ;
-    }
-}
-
-static void uevent_init(void) {
-    uevent_fd = uevent_open_socket(64*1024, true);
-
-    if (uevent_fd < 0) {
-        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+    gHealth = IHealth::getService("health");
+    if (gHealth == nullptr) {
+        KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n");
         return;
     }
 
-    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    if (healthd_register_event(uevent_fd, uevent_event))
-        KLOG_ERROR(LOG_TAG,
-                   "register for uevent events failed\n");
+    HealthConfig halConfig;
+    convertToHealthConfig(config, halConfig);
+    gHealth->init(halConfig, [=] (const auto &halConfigOut) {
+            convertFromHealthConfig(halConfigOut, config);
+            // always redirect energy counter queries
+            config->energyCounter = healthd_board_get_energy_counter;
+            });
 }
 
-static void wakealarm_event(uint32_t /*epevents*/) {
-    unsigned long long wakeups;
+int healthd_board_battery_update(struct android::BatteryProperties *props) {
+    int logthis = 0;
 
-    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
-        return;
+    if (gHealth == nullptr) {
+        return logthis;
     }
 
-    periodic_chores();
+    HealthInfo info;
+    convertToHealthInfo(props, info);
+    gHealth->update(info,
+            [=, &logthis] (int32_t ret, const auto &infoOut) {
+                logthis = ret;
+                convertFromHealthInfo(infoOut, props);
+            });
+
+    return logthis;
 }
 
-static void wakealarm_init(void) {
-    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
-    if (wakealarm_fd == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
-        return;
-    }
+int main(int /*argc*/, char ** /*argv*/) {
 
-    if (healthd_register_event(wakealarm_fd, wakealarm_event))
-        KLOG_ERROR(LOG_TAG,
-                   "Registration of wakealarm event failed\n");
-
-    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
-    while (1) {
-        struct epoll_event events[eventct];
-        int nevents;
-        int timeout = awake_poll_interval;
-        int mode_timeout;
-
-        mode_timeout = healthd_mode_ops->preparetowait();
-        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
-            timeout = mode_timeout;
-        nevents = epoll_wait(epollfd, events, eventct, timeout);
-
-        if (nevents == -1) {
-            if (errno == EINTR)
-                continue;
-            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
-            break;
-        }
-
-        for (int n = 0; n < nevents; ++n) {
-            if (events[n].data.ptr)
-                (*(void (*)(int))events[n].data.ptr)(events[n].events);
-        }
-
-        if (!nevents)
-            periodic_chores();
-
-        healthd_mode_ops->heartbeat();
-    }
-
-    return;
-}
-
-static int healthd_init() {
-    epollfd = epoll_create(MAX_EPOLL_EVENTS);
-    if (epollfd == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "epoll_create failed; errno=%d\n",
-                   errno);
-        return -1;
-    }
-
-    healthd_board_init(&healthd_config);
-    healthd_mode_ops->init(&healthd_config);
-    wakealarm_init();
-    uevent_init();
-    gBatteryMonitor = new BatteryMonitor();
-    gBatteryMonitor->init(&healthd_config);
-    return 0;
-}
-
-int main(int argc, char **argv) {
-    int ch;
-    int ret;
-
-    klog_set_level(KLOG_LEVEL);
     healthd_mode_ops = &android_ops;
 
-    if (!strcmp(basename(argv[0]), "charger")) {
-        healthd_mode_ops = &charger_ops;
-    } else {
-        while ((ch = getopt(argc, argv, "cr")) != -1) {
-            switch (ch) {
-            case 'c':
-                healthd_mode_ops = &charger_ops;
-                break;
-            case 'r':
-                healthd_mode_ops = &recovery_ops;
-                break;
-            case '?':
-            default:
-                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
-                           optopt);
-                exit(1);
-            }
-        }
-    }
-
-    ret = healthd_init();
-    if (ret) {
-        KLOG_ERROR("Initialization failed, exiting\n");
-        exit(2);
-    }
-
-    healthd_mainloop();
-    KLOG_ERROR("Main loop terminated, exiting\n");
-    return 3;
+    return healthd_main();
 }
diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp
deleted file mode 100644
index eb55773..0000000
--- a/healthd/healthd_board_default.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 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 <healthd/healthd.h>
-
-void healthd_board_init(struct healthd_config*)
-{
-    // use defaults
-}
-
-
-int healthd_board_battery_update(struct android::BatteryProperties*)
-{
-    // return 0 to log periodic polled battery status to kernel log
-    return 0;
-}
diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp
new file mode 100644
index 0000000..6599919
--- /dev/null
+++ b/healthd/healthd_common.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "healthd-common"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+#include <healthd/BatteryMonitor.h>
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+#endif
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+#endif
+
+static struct healthd_config healthd_config = {
+    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+    .batteryStatusPath = String8(String8::kEmptyString),
+    .batteryHealthPath = String8(String8::kEmptyString),
+    .batteryPresentPath = String8(String8::kEmptyString),
+    .batteryCapacityPath = String8(String8::kEmptyString),
+    .batteryVoltagePath = String8(String8::kEmptyString),
+    .batteryTemperaturePath = String8(String8::kEmptyString),
+    .batteryTechnologyPath = String8(String8::kEmptyString),
+    .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryCurrentAvgPath = String8(String8::kEmptyString),
+    .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .batteryFullChargePath = String8(String8::kEmptyString),
+    .batteryCycleCountPath = String8(String8::kEmptyString),
+    .energyCounter = NULL,
+    .boot_min_cap = 0,
+    .screen_on = NULL,
+};
+
+static int eventct;
+static int epollfd;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
+static int uevent_fd;
+static int wakealarm_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+static BatteryMonitor* gBatteryMonitor;
+
+struct healthd_mode_ops *healthd_mode_ops;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN;
+
+    if (wakeup == EVENT_WAKEUP_FD)
+        ev.events |= EPOLLWAKEUP;
+
+    ev.data.ptr = (void *)handler;
+    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    eventct++;
+    return 0;
+}
+
+static void wakealarm_set_interval(int interval) {
+    struct itimerspec itval;
+
+    if (wakealarm_fd == -1)
+            return;
+
+    wakealarm_wake_interval = interval;
+
+    if (interval == -1)
+        interval = 0;
+
+    itval.it_interval.tv_sec = interval;
+    itval.it_interval.tv_nsec = 0;
+    itval.it_value.tv_sec = interval;
+    itval.it_value.tv_nsec = 0;
+
+    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+    return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
+    // Fast wake interval when on charger (watch for overheat);
+    // slow wake interval when on battery (watch for drained battery).
+
+   int new_wake_interval = gBatteryMonitor->update() ?
+       healthd_config.periodic_chores_interval_fast :
+           healthd_config.periodic_chores_interval_slow;
+
+    if (new_wake_interval != wakealarm_wake_interval)
+            wakealarm_set_interval(new_wake_interval);
+
+    // During awake periods poll at fast rate.  If wake alarm is set at fast
+    // rate then just use the alarm; if wake alarm is set at slow rate then
+    // poll at fast rate while awake and let alarm wake up at slow rate when
+    // asleep.
+
+    if (healthd_config.periodic_chores_interval_fast == -1)
+        awake_poll_interval = -1;
+    else
+        awake_poll_interval =
+            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
+                -1 : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+void healthd_dump_battery_state(int fd) {
+    gBatteryMonitor->dumpState(fd);
+    fsync(fd);
+}
+
+static void periodic_chores() {
+    healthd_battery_update();
+}
+
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
+    char msg[UEVENT_MSG_LEN+2];
+    char *cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+    if (n <= 0)
+        return;
+    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n+1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+            healthd_battery_update();
+            break;
+        }
+
+        /* advance to after the next \0 */
+        while (*cp++)
+            ;
+    }
+}
+
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64*1024, true);
+
+    if (uevent_fd < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG,
+                   "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
+static void wakealarm_init(void) {
+    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+    if (wakealarm_fd == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+        return;
+    }
+
+    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG,
+                   "Registration of wakealarm event failed\n");
+
+    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void healthd_mainloop(void) {
+    int nevents = 0;
+    while (1) {
+        struct epoll_event events[eventct];
+        int timeout = awake_poll_interval;
+        int mode_timeout;
+
+        /* Don't wait for first timer timeout to run periodic chores */
+        if (!nevents)
+            periodic_chores();
+
+        healthd_mode_ops->heartbeat();
+
+        mode_timeout = healthd_mode_ops->preparetowait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+            timeout = mode_timeout;
+        nevents = epoll_wait(epollfd, events, eventct, timeout);
+        if (nevents == -1) {
+            if (errno == EINTR)
+                continue;
+            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr)
+                (*(void (*)(int))events[n].data.ptr)(events[n].events);
+        }
+    }
+
+    return;
+}
+
+static int healthd_init() {
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_create failed; errno=%d\n",
+                   errno);
+        return -1;
+    }
+
+    healthd_board_init(&healthd_config);
+    healthd_mode_ops->init(&healthd_config);
+    wakealarm_init();
+    uevent_init();
+    gBatteryMonitor = new BatteryMonitor();
+    gBatteryMonitor->init(&healthd_config);
+    return 0;
+}
+
+int healthd_main() {
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+
+    if (!healthd_mode_ops) {
+        KLOG_ERROR("healthd ops not set, exiting\n");
+        exit(1);
+    }
+
+    ret = healthd_init();
+    if (ret) {
+        KLOG_ERROR("Initialization failed, exiting\n");
+        exit(2);
+    }
+
+    healthd_mainloop();
+    KLOG_ERROR("Main loop terminated, exiting\n");
+    return 3;
+}
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
index 323ef52..c612313 100644
--- a/healthd/healthd_mode_android.cpp
+++ b/healthd/healthd_mode_android.cpp
@@ -42,6 +42,9 @@
     return -1;
 }
 
+void healthd_mode_android_heartbeat(void) {
+}
+
 static void binder_event(uint32_t /*epevents*/) {
     IPCThreadState::self()->handlePolledCommands();
 }
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 36c4664..ec3de34 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -341,14 +341,19 @@
 
 static void draw_percent(const animation& anim)
 {
-    if (anim.cur_level <= 0 || anim.cur_status != BATTERY_STATUS_CHARGING) return;
+    int cur_level = anim.cur_level;
+    if (anim.cur_status == BATTERY_STATUS_FULL) {
+        cur_level = 100;
+    }
+
+    if (cur_level <= 0) return;
 
     const animation::text_field& field = anim.text_percent;
     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
         return;
     }
 
-    std::string str = base::StringPrintf("%d%%", anim.cur_level);
+    std::string str = base::StringPrintf("%d%%", cur_level);
 
     int x, y;
     determine_xy(field, str.size(), &x, &y);
@@ -839,7 +844,7 @@
     ret = ev_init(input_callback, charger);
     if (!ret) {
         epollfd = ev_get_epollfd();
-        healthd_register_event(epollfd, charger_event_handler);
+        healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
     }
 
     struct animation* anim = init_animation();
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 34ea55f..17efbd6 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -73,9 +73,14 @@
     bool (*screen_on)(android::BatteryProperties *props);
 };
 
+enum EventWakeup {
+    EVENT_NO_WAKEUP_FD,
+    EVENT_WAKEUP_FD,
+};
+
 // Global helper functions
 
-int healthd_register_event(int fd, void (*handler)(uint32_t));
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
 void healthd_battery_update();
 android::status_t healthd_get_property(int id,
     struct android::BatteryProperty *val);
diff --git a/include/android/log.h b/include/android/log.h
index 5f20f8c..5673357 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -67,25 +67,55 @@
  * NOTE: These functions MUST be implemented by /system/lib/liblog.so
  */
 
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
 #include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/uio.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /*
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings.  See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
+ */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
+/*
+ * LOG_TAG is the local tag used for the following simplified
+ * logging macros.  You must set this preprocessor definition,
+ * or more tenuously supply a variable definition, before using
+ * the macros.
+ */
+
+/*
+ * Normally we strip the effects of ALOGV (VERBOSE messages),
+ * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
+ * release builds be defining NDEBUG.  You can modify this (for
+ * example with "#define LOG_NDEBUG 0" at the top of your source
+ * file) to change that behavior.
+ */
+
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
  * Android log priority values, in ascending priority order.
  */
+#ifndef __android_LogPriority_defined
+#define __android_LogPriority_defined
 typedef enum android_LogPriority {
     ANDROID_LOG_UNKNOWN = 0,
     ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
@@ -97,21 +127,20 @@
     ANDROID_LOG_FATAL,
     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 } android_LogPriority;
-
-/*
- * Release any logger resources (a new log write will immediately re-acquire)
- */
-void __android_log_close();
+#endif
 
 /*
  * Send a simple string to the log.
  */
-int __android_log_write(int prio, const char *tag, const char *text);
+int __android_log_write(int prio, const char* tag, const char* text);
+
+#define android_writeLog(prio, tag, text) \
+    __android_log_write(prio, tag, text)
 
 /*
  * Send a formatted string to the log, used like printf(fmt,...)
  */
-int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+int __android_log_print(int prio, const char* tag,  const char* fmt, ...)
 #if defined(__GNUC__)
 #ifdef __USE_MINGW_ANSI_STDIO
 #if __USE_MINGW_ANSI_STDIO
@@ -125,19 +154,53 @@
 #endif
     ;
 
+#define android_printLog(prio, tag, ...) \
+    __android_log_print(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+    android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
 /*
  * A variant of __android_log_print() that takes a va_list to list
  * additional parameters.
  */
-int __android_log_vprint(int prio, const char *tag,
-                         const char *fmt, va_list ap);
+int __android_log_vprint(int prio, const char* tag,
+                         const char* fmt, va_list ap)
+#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 0)))
+#else
+    __attribute__ ((format(printf, 3, 0)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 0)))
+#endif
+#endif
+    ;
+
+#define android_vprintLog(prio, cond, tag, ...) \
+    __android_log_vprint(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
 
 /*
  * Log an assertion failure and abort the process to have a chance
  * to inspect it if a debugger is attached. This uses the FATAL priority.
  */
-void __android_log_assert(const char *cond, const char *tag,
-                          const char *fmt, ...)
+void __android_log_assert(const char* cond, const char* tag,
+                          const char* fmt, ...)
 #if defined(__GNUC__)
     __attribute__ ((__noreturn__))
 #ifdef __USE_MINGW_ANSI_STDIO
@@ -152,77 +215,91 @@
 #endif
     ;
 
-//
-// C/C++ logging functions.  See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND.  These calls have mutex-protected data structures
-// and so are NOT reentrant.  Do not use LOG in a signal handler.
-//
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
 
-// This file uses ", ## __VA_ARGS__" zero-argument token pasting to
-// work around issues with debug-only syntax errors in assertions
-// that are missing format strings.  See commit
-// 19299904343daf191267564fe32e6cd5c165cd42
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#endif
+/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...)     second
 
-int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_btwrite(int32_t tag, char type, const void *payload,
-                          size_t len);
-int __android_log_bswrite(int32_t tag, const char *payload);
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...)               , ## __VA_ARGS__
 
-int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_security_bswrite(int32_t tag, const char *payload);
-
-// ---------------------------------------------------------------------
+#define android_printAssert(cond, tag, ...) \
+    __android_log_assert(cond, tag, \
+        __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
 
 /*
- * Normally we strip ALOGV (VERBOSE messages) from release builds.
- * You can modify this (for example with "#define LOG_NDEBUG 0"
- * at the top of your source file) to change that behavior.
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
  */
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
 #else
-#define LOG_NDEBUG 0
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
 #endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
 #endif
 
 /*
- * This is the local tag used for the following simplified
- * logging macros.  You can change this preprocessor definition
- * before using the other macros to change the tag.
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current LOG_TAG.
  */
-#ifndef LOG_TAG
-#define LOG_TAG NULL
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
 #endif
 
-// ---------------------------------------------------------------------
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
+/* --------------------------------------------------------------------- */
 
 /*
- *      -DLINT_RLOG in sources that you want to enforce that all logging
- * goes to the radio log buffer. If any logging goes to any of the other
- * log buffers, there will be a compile or link error to highlight the
- * problem. This is not a replacement for a full audit of the code since
- * this only catches compiled code, not ifdef'd debug code. Options to
- * defining this, either temporarily to do a spot check, or permanently
- * to enforce, in all the communications trees; We have hopes to ensure
- * that by supplying just the radio log buffer that the communications
- * teams will have their one-stop shop for triaging issues.
+ * C/C++ logging functions.  See the logging documentation for API details.
+ *
+ * We'd like these to be available from C code (in case we import some from
+ * somewhere), so this has a C interface.
+ *
+ * The output will be correct when the log file is shared between multiple
+ * threads and/or multiple processes so long as the operating system
+ * supports O_APPEND.  These calls have mutex-protected data structures
+ * and so are NOT reentrant.  Do not use LOG in a signal handler.
  */
-#ifndef LINT_RLOG
+
+/* --------------------------------------------------------------------- */
 
 /*
  * Simplified macro to send a verbose log message using the current LOG_TAG.
@@ -303,7 +380,7 @@
     : (void)0 )
 #endif
 
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
 
 /*
  * Conditional based on whether the current LOG_TAG is enabled at
@@ -349,236 +426,7 @@
 #define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
 #endif
 
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose system log message using the current LOG_TAG.
- */
-#ifndef SLOGV
-#define __SLOGV(...) \
-    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
-#else
-#define SLOGV(...) __SLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef SLOGV_IF
-#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...)   ((void)0)
-#else
-#define SLOGV_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug system log message using the current LOG_TAG.
- */
-#ifndef SLOGD
-#define SLOGD(...) \
-    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info system log message using the current LOG_TAG.
- */
-#ifndef SLOGI
-#define SLOGI(...) \
-    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning system log message using the current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) \
-    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error system log message using the current LOG_TAG.
- */
-#ifndef SLOGE
-#define SLOGE(...) \
-    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-#endif /* !LINT_RLOG */
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose radio log message using the current LOG_TAG.
- */
-#ifndef RLOGV
-#define __RLOGV(...) \
-    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
-#else
-#define RLOGV(...) __RLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...)   ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using the current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) \
-    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info radio log message using the current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) \
-    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using the current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) \
-    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error radio log message using the current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) \
-    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-
-// ---------------------------------------------------------------------
-
-/*
- * Log a fatal error.  If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds.  Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
-    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds.  Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
-//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
-#endif
-
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
 
 /*
  * Basic log message macro.
@@ -594,22 +442,6 @@
 #endif
 
 /*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
-    android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
-    android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/*
  * Conditional given a desired logging priority and tag.
  */
 #ifndef IF_ALOG
@@ -617,181 +449,7 @@
     if (android_testLog(ANDROID_##priority, tag))
 #endif
 
-// ---------------------------------------------------------------------
-
-/*
- * Event logging.
- */
-
-/*
- * Event log entry types.
- */
-typedef enum {
-    /* Special markers for android_log_list_element type */
-    EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
-    EVENT_TYPE_UNKNOWN   = '?',  /* protocol error       */
-
-    /* must match with declaration in java/android/android/util/EventLog.java */
-    EVENT_TYPE_INT       = 0,    /* uint32_t */
-    EVENT_TYPE_LONG      = 1,    /* uint64_t */
-    EVENT_TYPE_STRING    = 2,
-    EVENT_TYPE_LIST      = 3,
-    EVENT_TYPE_FLOAT     = 4,
-} AndroidEventLogType;
-#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
-#define typeof_AndroidEventLogType unsigned char
-
-#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) {                                       \
-        int intBuf = _value;                                                \
-        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
-            sizeof(intBuf));                                                \
-    }
-#endif
-#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) {                                      \
-        long long longBuf = _value;                                         \
-        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
-            sizeof(longBuf));                                               \
-    }
-#endif
-#ifndef LOG_EVENT_FLOAT
-#define LOG_EVENT_FLOAT(_tag, _value) {                                     \
-        float floatBuf = _value;                                            \
-        (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf,        \
-            sizeof(floatBuf));                                              \
-    }
-#endif
-#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value)                                      \
-        (void) __android_log_bswrite(_tag, _value);
-#endif
-
-typedef enum log_id {
-    LOG_ID_MIN = 0,
-
-#ifndef LINT_RLOG
-    LOG_ID_MAIN = 0,
-#endif
-    LOG_ID_RADIO = 1,
-#ifndef LINT_RLOG
-    LOG_ID_EVENTS = 2,
-    LOG_ID_SYSTEM = 3,
-    LOG_ID_CRASH = 4,
-    LOG_ID_SECURITY = 5,
-    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
-#endif
-
-    LOG_ID_MAX
-} log_id_t;
-#define sizeof_log_id_t sizeof(typeof_log_id_t)
-#define typeof_log_id_t unsigned char
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-typedef struct android_log_context_internal *android_log_context;
-
-/*
- * Elements returned when reading a list of events.
- */
-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;
-
-/*
- * 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);
-
-/*
- * ===========================================================================
- *
- * The stuff in the rest of this file should not be used directly.
- */
-
-#define android_printLog(prio, tag, ...) \
-    __android_log_print(prio, tag, __VA_ARGS__)
-
-#define android_vprintLog(prio, cond, tag, ...) \
-    __android_log_vprint(prio, tag, __VA_ARGS__)
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
- */
-
-/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...)     second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...)               , ## __VA_ARGS__
-
-#define android_printAssert(cond, tag, ...) \
-    __android_log_assert(cond, tag, \
-        __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
-
-#define android_writeLog(prio, tag, text) \
-    __android_log_write(prio, tag, text)
-
-#define android_bWriteLog(tag, payload, len) \
-    __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
-    __android_log_btwrite(tag, type, payload, len)
-
-#define android_errorWriteLog(tag, subTag) \
-    __android_log_error_write(tag, subTag, -1, NULL, 0)
-
-#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
-    __android_log_error_write(tag, subTag, uid, data, dataLen)
+/* --------------------------------------------------------------------- */
 
 /*
  *    IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
@@ -801,6 +459,35 @@
  *        IF_ALOG as a convenient means to reimplement their policy
  *        over Android.
  */
+
+#ifndef __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 24 /* > Nougat */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+
+/*
+ * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
+ * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+ * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
+ * any other value.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE > 1
+#include <sys/types.h>
+
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len,
+                                  int default_prio);
+
 #if LOG_NDEBUG /* Production */
 #define android_testLog(prio, tag) \
     (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
@@ -811,29 +498,23 @@
                                    ANDROID_LOG_VERBOSE) != 0)
 #endif
 
-/*
- * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
- * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
- * any other value.
- */
-int __android_log_is_loggable(int prio, const char *tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char *tag, size_t len, int default_prio);
+#else
 
-int __android_log_security(); /* Device Owner is present */
-
-int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
-                              uint32_t dataLen);
-
-/*
- * Send a simple string to the log.
- */
-int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 4, 5)))
+#if LOG_NDEBUG /* Production */
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+#else
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
 #endif
-    ;
+
+#endif
+
+#else /* __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
+
+#define android_testLog(prio, tag) (1)
+
+#endif /* !__ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
 
 #if defined(__clang__)
 #pragma clang diagnostic pop
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index b80045f..df48dfe 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -19,7 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#ifdef USE_MINGW
+#ifdef _WIN32
 // MINGW does not define these constants.
 #define PROT_NONE 0
 #define PROT_READ 0x1
diff --git a/include/cutils/android_get_control_file.h b/include/cutils/android_get_control_file.h
new file mode 100644
index 0000000..ed8fbf8
--- /dev/null
+++ b/include/cutils/android_get_control_file.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H
+#define __CUTILS_ANDROID_GET_CONTROL_FILE_H
+
+#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */
diff --git a/include/cutils/log.h b/include/cutils/log.h
index ffb8268..0e0248e 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -1 +1 @@
-#include <android/log.h>
+#include <log/log.h>
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 31695cb..7d6a988 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -17,10 +17,17 @@
 #ifndef NATIVE_HANDLE_H_
 #define NATIVE_HANDLE_H_
 
+#include <stdalign.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* Declare a char array for use with native_handle_init */
+#define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
+    alignas(native_handle_t) char name[                            \
+      sizeof(native_handle_t) + sizeof(int) * (maxFds + maxInts)]
+
 typedef struct native_handle
 {
     int version;        /* sizeof(native_handle_t) */
@@ -46,6 +53,14 @@
  */
 int native_handle_close(const native_handle_t* h);
 
+/*
+ * native_handle_init
+ *
+ * Initializes a native_handle_t from storage.  storage must be declared with
+ * NATIVE_HANDLE_DECLARE_STORAGE.  numFds and numInts must not respectively
+ * exceed maxFds and maxInts used to declare the storage.
+ */
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts);
 
 /*
  * native_handle_create
@@ -57,6 +72,15 @@
 native_handle_t* native_handle_create(int numFds, int numInts);
 
 /*
+ * native_handle_clone
+ *
+ * creates a native_handle_t and initializes it from another native_handle_t.
+ * Must be destroyed with native_handle_delete().
+ *
+ */
+native_handle_t* native_handle_clone(const native_handle_t* handle);
+
+/*
  * native_handle_delete
  * 
  * frees a native_handle_t allocated with native_handle_create().
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index a93c8ea..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)
@@ -84,11 +85,11 @@
  *
  * These functions return INVALID_SOCKET (-1) on failure for all platforms.
  */
-int socket_loopback_client(int port, int type);
 cutils_socket_t socket_network_client(const char* host, int port, int type);
 int socket_network_client_timeout(const char* host, int port, int type,
                                   int timeout, int* getaddrinfo_error);
 int socket_loopback_server(int port, int type);
+int socket_loopback_server6(int port, int type);
 int socket_local_server(const char* name, int namespaceId, int type);
 int socket_local_server_bind(int s, const char* name, int namespaceId);
 int socket_local_client_connect(int fd, const char *name, int namespaceId,
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 69774ba..22e62ec 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -48,7 +48,15 @@
  * Look up a tag by index.  Returns the tag string & string length, or NULL if
  * not found.  Returned string is not guaranteed to be nul terminated.
  */
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag);
+const char* android_lookupEventTag_len(const EventTagMap* map,
+                                       size_t* len, unsigned int tag);
+
+/*
+ * Look up a format by index. Returns the format string & string length,
+ * or NULL if not found. Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventFormat_len(const EventTagMap* map,
+                                          size_t* len, unsigned int tag);
 
 #ifdef __cplusplus
 }
diff --git a/include/log/log.h b/include/log/log.h
index ffb8268..d6f0eb5 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -1 +1,823 @@
+/*
+ * Copyright (C) 2005-2014 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_LOG_H
+#define _LIBS_LOG_LOG_H
+
+/* Too many in the ecosystem assume these are included */
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+#include <stdint.h>  /* uint16_t, int32_t */
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>    /* clock_gettime */
+#include <unistd.h>
+
 #include <android/log.h>
+#include <log/uio.h> /* helper to define iovec for portability */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * LOG_TAG is the local tag used for the following simplified
+ * logging macros.  You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings.  See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
+ */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
+#endif
+    ;
+
+/*
+ * Simplified macro to send a verbose system log message using current LOG_TAG.
+ */
+#ifndef SLOGV
+#define __SLOGV(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
+#else
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...)   ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Simplified macro to send a verbose radio log message using current LOG_TAG.
+ */
+#ifndef RLOGV
+#define __RLOGV(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
+#else
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...)   ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using  current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using  current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Event logging.
+ */
+
+/*
+ * The following should not be used directly.
+ */
+
+int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void* payload,
+                          size_t len);
+int __android_log_bswrite(int32_t tag, const char* payload);
+
+#define android_bWriteLog(tag, payload, len) \
+    __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+    __android_log_btwrite(tag, type, payload, len)
+
+/*
+ * Event log entry types.
+ */
+#ifndef __AndroidEventLogType_defined
+#define __AndroidEventLogType_defined
+typedef enum {
+    /* Special markers for android_log_list_element type */
+    EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
+    EVENT_TYPE_UNKNOWN   = '?',  /* protocol error       */
+
+    /* must match with declaration in java/android/android/util/EventLog.java */
+    EVENT_TYPE_INT       = 0,    /* int32_t */
+    EVENT_TYPE_LONG      = 1,    /* int64_t */
+    EVENT_TYPE_STRING    = 2,
+    EVENT_TYPE_LIST      = 3,
+    EVENT_TYPE_FLOAT     = 4,
+} AndroidEventLogType;
+#endif
+#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
+#define typeof_AndroidEventLogType unsigned char
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) {                                       \
+        int intBuf = _value;                                                \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
+            sizeof(intBuf));                                                \
+    }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) {                                      \
+        long long longBuf = _value;                                         \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
+            sizeof(longBuf));                                               \
+    }
+#endif
+#ifndef LOG_EVENT_FLOAT
+#define LOG_EVENT_FLOAT(_tag, _value) {                                     \
+        float floatBuf = _value;                                            \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf,        \
+            sizeof(floatBuf));                                              \
+    }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value)                                      \
+        (void) __android_log_bswrite(_tag, _value);
+#endif
+
+#ifndef log_id_t_defined
+#define log_id_t_defined
+typedef enum log_id {
+    LOG_ID_MIN = 0,
+
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
+    LOG_ID_SECURITY = 5,
+    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+
+    LOG_ID_MAX
+} log_id_t;
+#endif
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Native log reading interface section. See logcat for sample code.
+ *
+ * The preferred API is an exec of logcat. Likely uses of this interface
+ * are if native code suffers from exec or filtration being too costly,
+ * access to raw information, or parsing is an issue.
+ */
+
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_defined
+#define __struct_logger_entry_defined
+struct logger_entry {
+    uint16_t    len;    /* length of the payload */
+    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
+    int32_t     pid;    /* generating process's pid */
+    int32_t     tid;    /* generating process's tid */
+    int32_t     sec;    /* seconds since Epoch */
+    int32_t     nsec;   /* nanoseconds */
+#ifndef __cplusplus
+    char        msg[0]; /* the entry's payload */
+#endif
+};
+#endif
+
+/*
+ * The userspace structure for version 2 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v2_defined
+#define __struct_logger_entry_v2_defined
+struct logger_entry_v2 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    euid;      /* effective UID of logger */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
+
+/*
+ * The userspace structure for version 3 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v3_defined
+#define __struct_logger_entry_v3_defined
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
+
+/*
+ * The userspace structure for version 4 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v4_defined
+#define __struct_logger_entry_v4_defined
+struct logger_entry_v4 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
+    int32_t     pid;       /* generating process's pid */
+    uint32_t    tid;       /* generating process's tid */
+    uint32_t    sec;       /* seconds since Epoch */
+    uint32_t    nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
+    uint32_t    uid;       /* generating process's uid */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+};
+#endif
+
+/* struct log_time is a wire-format variant of struct timespec */
+#define NS_PER_SEC 1000000000ULL
+
+#ifndef __struct_log_time_defined
+#define __struct_log_time_defined
+#ifdef __cplusplus
+
+/*
+ * NB: we did NOT define a copy constructor. This will result in structure
+ * no longer being compatible with pass-by-value which is desired
+ * efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+ */
+struct log_time {
+public:
+    uint32_t tv_sec; /* good to Feb 5 2106 */
+    uint32_t tv_nsec;
+
+    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+    static const uint32_t tv_nsec_max = 999999999UL;
+
+    log_time(const timespec& T)
+    {
+        tv_sec = static_cast<uint32_t>(T.tv_sec);
+        tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+    }
+    log_time(uint32_t sec, uint32_t nsec)
+    {
+        tv_sec = sec;
+        tv_nsec = nsec;
+    }
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+#define __struct_log_time_private_defined
+    static const timespec EPOCH;
+#endif
+    log_time()
+    {
+    }
+#ifdef __linux__
+    log_time(clockid_t id)
+    {
+        timespec T;
+        clock_gettime(id, &T);
+        tv_sec = static_cast<uint32_t>(T.tv_sec);
+        tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+    }
+#endif
+    log_time(const char* T)
+    {
+        const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
+        tv_sec = c[0] |
+                 (static_cast<uint32_t>(c[1]) << 8) |
+                 (static_cast<uint32_t>(c[2]) << 16) |
+                 (static_cast<uint32_t>(c[3]) << 24);
+        tv_nsec = c[4] |
+                  (static_cast<uint32_t>(c[5]) << 8) |
+                  (static_cast<uint32_t>(c[6]) << 16) |
+                  (static_cast<uint32_t>(c[7]) << 24);
+    }
+
+    /* timespec */
+    bool operator== (const timespec& T) const
+    {
+        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+    }
+    bool operator!= (const timespec& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const timespec& T) const
+    {
+        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator>= (const timespec& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const timespec& T) const
+    {
+        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator<= (const timespec& T) const
+    {
+        return !(*this > T);
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    log_time operator-= (const timespec& T);
+    log_time operator- (const timespec& T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+    log_time operator+= (const timespec& T);
+    log_time operator+ (const timespec& T) const
+    {
+        log_time local(*this);
+        return local += T;
+    }
+#endif
+
+    /* log_time */
+    bool operator== (const log_time& T) const
+    {
+        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+    }
+    bool operator!= (const log_time& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_time& T) const
+    {
+        return (tv_sec < T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+    }
+    bool operator>= (const log_time& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_time& T) const
+    {
+        return (tv_sec > T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+    }
+    bool operator<= (const log_time& T) const
+    {
+        return !(*this > T);
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    log_time operator-= (const log_time& T);
+    log_time operator- (const log_time& T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+    log_time operator+= (const log_time& T);
+    log_time operator+ (const log_time& T) const
+    {
+        log_time local(*this);
+        return local += T;
+    }
+#endif
+
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    static const char default_format[];
+
+    /* Add %#q for the fraction of a second to the standard library functions */
+    char* strptime(const char* s, const char* format = default_format);
+#endif
+} __attribute__((__packed__));
+
+#else
+
+typedef struct log_time {
+    uint32_t tv_sec;
+    uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
+#endif
+#endif
+
+/*
+ * The maximum size of the log entry payload that can be
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
+ */
+#define LOGGER_ENTRY_MAX_PAYLOAD 4068
+
+/*
+ * The maximum size of a log entry which can be read from the
+ * kernel logger driver. An attempt to read less than this amount
+ * may result in read() returning EINVAL.
+ */
+#define LOGGER_ENTRY_MAX_LEN    (5*1024)
+
+#ifndef __struct_log_msg_defined
+#define __struct_log_msg_defined
+struct log_msg {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+        struct logger_entry_v4 entry;
+        struct logger_entry_v4 entry_v4;
+        struct logger_entry_v3 entry_v3;
+        struct logger_entry_v2 entry_v2;
+        struct logger_entry    entry_v1;
+    } __attribute__((aligned(4)));
+#ifdef __cplusplus
+    /* Matching log_time operators */
+    bool operator== (const log_msg& T) const
+    {
+        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+    }
+    bool operator!= (const log_msg& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_msg& T) const
+    {
+        return (entry.sec < T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec < T.entry.nsec));
+    }
+    bool operator>= (const log_msg& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_msg& T) const
+    {
+        return (entry.sec > T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec > T.entry.nsec));
+    }
+    bool operator<= (const log_msg& T) const
+    {
+        return !(*this > T);
+    }
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+    }
+
+    /* packet methods */
+    log_id_t id()
+    {
+        return static_cast<log_id_t>(entry.lid);
+    }
+    char* msg()
+    {
+        unsigned short hdr_size = entry.hdr_size;
+        if (!hdr_size) {
+            hdr_size = sizeof(entry_v1);
+        }
+        if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
+            return NULL;
+        }
+        return reinterpret_cast<char*>(buf) + hdr_size;
+    }
+    unsigned int len()
+    {
+        return (entry.hdr_size ?
+                    entry.hdr_size :
+                    static_cast<uint16_t>(sizeof(entry_v1))) +
+               entry.len;
+    }
+#endif
+};
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_READER_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 2
+#elif __ANDROID_API__ > 19 /* > KitKat */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger* logger);
+
+int android_logger_clear(struct logger* logger);
+long android_logger_get_log_size(struct logger* logger);
+int android_logger_set_log_size(struct logger* logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger* logger);
+int android_logger_get_log_version(struct logger* logger);
+
+struct logger_list;
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+ssize_t android_logger_get_statistics(struct logger_list* logger_list,
+                                      char* buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
+                                      char* buf, size_t len);
+int android_logger_set_prune_list(struct logger_list* logger_list,
+                                  char* buf, size_t len);
+#endif
+
+#define ANDROID_LOG_RDONLY   O_RDONLY
+#define ANDROID_LOG_WRONLY   O_WRONLY
+#define ANDROID_LOG_RDWR     O_RDWR
+#define ANDROID_LOG_ACCMODE  O_ACCMODE
+#define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 2
+#define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
+#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
+#endif
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+#define ANDROID_LOG_PSTORE   0x80000000
+#endif
+
+struct logger_list* android_logger_list_alloc(int mode,
+                                              unsigned int tail,
+                                              pid_t pid);
+struct logger_list* android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid);
+void android_logger_list_free(struct logger_list* logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list* logger_list,
+                             struct log_msg* log_msg);
+
+/* Multiple log_id_t opens */
+struct logger* android_logger_open(struct logger_list* logger_list,
+                                   log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list* android_logger_list_open(log_id_t id,
+                                             int mode,
+                                             unsigned int tail,
+                                             pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+#endif /* __ANDROID_USE_LIBLOG_READER_INTERFACE */
+
+#ifdef __linux__
+
+#ifndef __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+clockid_t android_log_clockid();
+#endif
+
+#endif /* __linux__ */
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char* logName);
+const char* android_log_id_to_name(log_id_t log_id);
+
+/* --------------------------------------------------------------------- */
+
+#ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
+
+#define android_errorWriteLog(tag, subTag) \
+    __android_log_error_write(tag, subTag, -1, NULL, 0)
+
+#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
+    __android_log_error_write(tag, subTag, uid, data, dataLen)
+
+int __android_log_error_write(int tag, const char* subTag, int32_t uid,
+                              const char* data, uint32_t dataLen);
+
+#endif /* __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE */
+
+/* --------------------------------------------------------------------- */
+
+#ifndef __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
+#elif __ANDROID_API__ > 18 /* > JellyBean */
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
+/*
+ * Release any logger resources (a new log write will immediately re-acquire)
+ *
+ * May be used to clean up File descriptors after a Fork, the resources are
+ * all O_CLOEXEC so wil self clean on exec().
+ */
+void __android_log_close();
+#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOG_H */
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/log/logd.h b/include/log/logd.h
index ffb8268..0e0248e 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -1 +1 @@
-#include <android/log.h>
+#include <log/log.h>
diff --git a/include/log/logger.h b/include/log/logger.h
index 46587fb..0e0248e 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -1,462 +1 @@
-/*
-**
-** Copyright 2007-2014, The Android Open Source Project
-**
-** This file is dual licensed.  It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _LIBS_LOG_LOGGER_H
-#define _LIBS_LOG_LOGGER_H
-
-#include <stdint.h>
-#include <time.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <android/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The userspace structure for version 1 of the logger_entry ABI.
- * This structure is returned to userspace by the kernel logger
- * driver unless an upgrade to a newer ABI version is requested.
- */
-struct logger_entry {
-    uint16_t    len;    /* length of the payload */
-    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
-    int32_t     pid;    /* generating process's pid */
-    int32_t     tid;    /* generating process's tid */
-    int32_t     sec;    /* seconds since Epoch */
-    int32_t     nsec;   /* nanoseconds */
-    char        msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-/*
- * The userspace structure for version 2 of the logger_entry ABI.
- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2; or used with the user space log daemon.
- */
-struct logger_entry_v2 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
-    int32_t     pid;       /* generating process's pid */
-    int32_t     tid;       /* generating process's tid */
-    int32_t     sec;       /* seconds since Epoch */
-    int32_t     nsec;      /* nanoseconds */
-    uint32_t    euid;      /* effective UID of logger */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v3 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
-    int32_t     pid;       /* generating process's pid */
-    int32_t     tid;       /* generating process's tid */
-    int32_t     sec;       /* seconds since Epoch */
-    int32_t     nsec;      /* nanoseconds */
-    uint32_t    lid;       /* log id of the payload */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v4 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
-    int32_t     pid;       /* generating process's pid */
-    uint32_t    tid;       /* generating process's tid */
-    uint32_t    sec;       /* seconds since Epoch */
-    uint32_t    nsec;      /* nanoseconds */
-    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
-    uint32_t    uid;       /* generating process's uid */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-/* struct log_time is a wire-format variant of struct timespec */
-#define NS_PER_SEC 1000000000ULL
-
-#ifdef __cplusplus
-
-// NB: do NOT define a copy constructor. This will result in structure
-// no longer being compatible with pass-by-value which is desired
-// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
-struct log_time {
-public:
-    uint32_t tv_sec; // good to Feb 5 2106
-    uint32_t tv_nsec;
-
-    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
-    static const uint32_t tv_nsec_max = 999999999UL;
-
-    log_time(const timespec &T)
-    {
-        tv_sec = T.tv_sec;
-        tv_nsec = T.tv_nsec;
-    }
-    log_time(uint32_t sec, uint32_t nsec)
-    {
-        tv_sec = sec;
-        tv_nsec = nsec;
-    }
-    static const timespec EPOCH;
-    log_time()
-    {
-    }
-#ifdef __linux__
-    log_time(clockid_t id)
-    {
-        timespec T;
-        clock_gettime(id, &T);
-        tv_sec = T.tv_sec;
-        tv_nsec = T.tv_nsec;
-    }
-#endif
-    log_time(const char *T)
-    {
-        const uint8_t *c = (const uint8_t *) T;
-        tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
-        tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
-    }
-
-    // timespec
-    bool operator== (const timespec &T) const
-    {
-        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
-            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
-    }
-    bool operator!= (const timespec &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const timespec &T) const
-    {
-        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
-            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
-                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
-    }
-    bool operator>= (const timespec &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const timespec &T) const
-    {
-        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
-            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
-                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
-    }
-    bool operator<= (const timespec &T) const
-    {
-        return !(*this > T);
-    }
-    log_time operator-= (const timespec &T);
-    log_time operator- (const timespec &T) const
-    {
-        log_time local(*this);
-        return local -= T;
-    }
-    log_time operator+= (const timespec &T);
-    log_time operator+ (const timespec &T) const
-    {
-        log_time local(*this);
-        return local += T;
-    }
-
-    // log_time
-    bool operator== (const log_time &T) const
-    {
-        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
-    }
-    bool operator!= (const log_time &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const log_time &T) const
-    {
-        return (tv_sec < T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
-    }
-    bool operator>= (const log_time &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const log_time &T) const
-    {
-        return (tv_sec > T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
-    }
-    bool operator<= (const log_time &T) const
-    {
-        return !(*this > T);
-    }
-    log_time operator-= (const log_time &T);
-    log_time operator- (const log_time &T) const
-    {
-        log_time local(*this);
-        return local -= T;
-    }
-    log_time operator+= (const log_time &T);
-    log_time operator+ (const log_time &T) const
-    {
-        log_time local(*this);
-        return local += T;
-    }
-
-    uint64_t nsec() const
-    {
-        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
-    }
-
-    static const char default_format[];
-
-    // Add %#q for the fraction of a second to the standard library functions
-    char *strptime(const char *s, const char *format = default_format);
-} __attribute__((__packed__));
-
-#else
-
-typedef struct log_time {
-    uint32_t tv_sec;
-    uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif
-
-/*
- * The maximum size of the log entry payload that can be
- * written to the logger. An attempt to write more than
- * this amount will result in a truncated log entry.
- */
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068
-
-/*
- * The maximum size of a log entry which can be read from the
- * kernel logger driver. An attempt to read less than this amount
- * may result in read() returning EINVAL.
- */
-#define LOGGER_ENTRY_MAX_LEN    (5*1024)
-
-struct log_msg {
-    union {
-        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-        struct logger_entry_v4 entry;
-        struct logger_entry_v4 entry_v4;
-        struct logger_entry_v3 entry_v3;
-        struct logger_entry_v2 entry_v2;
-        struct logger_entry    entry_v1;
-    } __attribute__((aligned(4)));
-#ifdef __cplusplus
-    /* Matching log_time operators */
-    bool operator== (const log_msg &T) const
-    {
-        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
-    }
-    bool operator!= (const log_msg &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const log_msg &T) const
-    {
-        return (entry.sec < T.entry.sec)
-            || ((entry.sec == T.entry.sec)
-             && (entry.nsec < T.entry.nsec));
-    }
-    bool operator>= (const log_msg &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const log_msg &T) const
-    {
-        return (entry.sec > T.entry.sec)
-            || ((entry.sec == T.entry.sec)
-             && (entry.nsec > T.entry.nsec));
-    }
-    bool operator<= (const log_msg &T) const
-    {
-        return !(*this > T);
-    }
-    uint64_t nsec() const
-    {
-        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
-    }
-
-    /* packet methods */
-    log_id_t id()
-    {
-        return (log_id_t) entry.lid;
-    }
-    char *msg()
-    {
-        unsigned short hdr_size = entry.hdr_size;
-        if (!hdr_size) {
-            hdr_size = sizeof(entry_v1);
-        }
-        if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
-            return NULL;
-        }
-        return (char *) buf + hdr_size;
-    }
-    unsigned int len()
-    {
-        return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
-    }
-#endif
-};
-
-struct logger;
-
-log_id_t android_logger_get_id(struct logger *logger);
-
-int android_logger_clear(struct logger *logger);
-long android_logger_get_log_size(struct logger *logger);
-int android_logger_set_log_size(struct logger *logger, unsigned long size);
-long android_logger_get_log_readable_size(struct logger *logger);
-int android_logger_get_log_version(struct logger *logger);
-
-struct logger_list;
-
-ssize_t android_logger_get_statistics(struct logger_list *logger_list,
-                                      char *buf, size_t len);
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
-                                      char *buf, size_t len);
-int android_logger_set_prune_list(struct logger_list *logger_list,
-                                  char *buf, size_t len);
-
-#define ANDROID_LOG_RDONLY   O_RDONLY
-#define ANDROID_LOG_WRONLY   O_WRONLY
-#define ANDROID_LOG_RDWR     O_RDWR
-#define ANDROID_LOG_ACCMODE  O_ACCMODE
-#define ANDROID_LOG_NONBLOCK O_NONBLOCK
-#define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
-#define ANDROID_LOG_PSTORE   0x80000000
-
-struct logger_list *android_logger_list_alloc(int mode,
-                                              unsigned int tail,
-                                              pid_t pid);
-struct logger_list *android_logger_list_alloc_time(int mode,
-                                                   log_time start,
-                                                   pid_t pid);
-void android_logger_list_free(struct logger_list *logger_list);
-/* In the purest sense, the following two are orthogonal interfaces */
-int android_logger_list_read(struct logger_list *logger_list,
-                             struct log_msg *log_msg);
-
-/* Multiple log_id_t opens */
-struct logger *android_logger_open(struct logger_list *logger_list,
-                                   log_id_t id);
-#define android_logger_close android_logger_free
-/* Single log_id_t open */
-struct logger_list *android_logger_list_open(log_id_t id,
-                                             int mode,
-                                             unsigned int tail,
-                                             pid_t pid);
-#define android_logger_list_close android_logger_list_free
-
-#ifdef __linux__
-clockid_t android_log_clockid();
-#endif
-
-/*
- * log_id_t helpers
- */
-log_id_t android_name_to_log_id(const char *logName);
-const char *android_log_id_to_name(log_id_t log_id);
-
-#ifdef __cplusplus
-// android_log_context C++ helpers
-class android_log_event_context {
-    android_log_context ctx;
-    int ret;
-
-public:
-    explicit android_log_event_context(int tag) : ret(0) {
-        ctx = create_android_logger(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 error() 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, 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, 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;
-    }
-    android_log_event_context& operator <<(std::string& value) {
-        int retval = android_log_write_string8_len(ctx,
-                                                   value.data(),
-                                                   value.length());
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    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) {
-        int retval = android_log_write_list(ctx, id);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-
-    android_log_list_element read() { return android_log_read_next(ctx); }
-    android_log_list_element peak() { return android_log_peek_next(ctx); }
-
-};
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBS_LOG_LOGGER_H */
+#include <log/log.h>
diff --git a/include/log/logprint.h b/include/log/logprint.h
index f70633d..3509e7f 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -21,7 +21,6 @@
 
 #include <android/log.h>
 #include <log/event_tag_map.h>
-#include <log/logger.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,6 +46,7 @@
     FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */
     FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
     FORMAT_MODIFIER_UID,       /* Adds uid */
+    FORMAT_MODIFIER_DESCRIPT,  /* Adds descriptive */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -58,24 +58,24 @@
     int32_t uid;
     int32_t pid;
     int32_t tid;
-    const char * tag;
+    const char* tag;
     size_t tagLen;
     size_t messageLen;
-    const char * message;
+    const char* message;
 } AndroidLogEntry;
 
-AndroidLogFormat *android_log_format_new();
+AndroidLogFormat* android_log_format_new();
 
-void android_log_format_free(AndroidLogFormat *p_format);
+void android_log_format_free(AndroidLogFormat* p_format);
 
 /* currently returns 0 if format is a modifier, 1 if not */
-int android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat* p_format,
         AndroidLogPrintFormat format);
 
 /**
  * Returns FORMAT_OFF on invalid string
  */
-AndroidLogPrintFormat android_log_formatFromString(const char *s);
+AndroidLogPrintFormat android_log_formatFromString(const char* s);
 
 /**
  * filterExpression: a single filter expression
@@ -87,9 +87,8 @@
  *
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format,
-        const char *filterExpression);
-
+int android_log_addFilterRule(AndroidLogFormat* p_format,
+        const char* filterExpression);
 
 /**
  * filterString: a whitespace-separated set of filter expressions
@@ -101,17 +100,15 @@
  *
  */
 
-int android_log_addFilterString(AndroidLogFormat *p_format,
-        const char *filterString);
-
+int android_log_addFilterString(AndroidLogFormat* p_format,
+        const char* filterString);
 
 /**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
 int android_log_shouldPrintLine (
-        AndroidLogFormat *p_format, const char *tag, android_LogPriority pri);
-
+        AndroidLogFormat* p_format, const char* tag, android_LogPriority pri);
 
 /**
  * Splits a wire-format buffer into an AndroidLogEntry
@@ -120,8 +117,8 @@
  * Returns 0 on success and -1 on invalid wire format (entry will be
  * in unspecified state)
  */
-int android_log_processLogBuffer(struct logger_entry *buf,
-                                 AndroidLogEntry *entry);
+int android_log_processLogBuffer(struct logger_entry* buf,
+                                 AndroidLogEntry* entry);
 
 /**
  * Like android_log_processLogBuffer, but for binary logs.
@@ -129,11 +126,10 @@
  * If "map" is non-NULL, it will be used to convert the log tag number
  * into a string.
  */
-int android_log_processBinaryLogBuffer(struct logger_entry *buf,
-    AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
+int android_log_processBinaryLogBuffer(struct logger_entry* buf,
+    AndroidLogEntry* entry, const EventTagMap* map, char* messageBuf,
     int messageBufLen);
 
-
 /**
  * Formats a log message into a buffer
  *
@@ -142,13 +138,12 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (
-    AndroidLogFormat *p_format,
-    char *defaultBuffer,
+char* android_log_formatLogLine (
+    AndroidLogFormat* p_format,
+    char* defaultBuffer,
     size_t defaultBufferSize,
-    const AndroidLogEntry *p_line,
-    size_t *p_outLength);
-
+    const AndroidLogEntry* p_line,
+    size_t* p_outLength);
 
 /**
  * Either print or do not print log line, based on filter
@@ -157,14 +152,12 @@
  *
  */
 int android_log_printLogLine(
-    AndroidLogFormat *p_format,
+    AndroidLogFormat* p_format,
     int fd,
-    const AndroidLogEntry *entry);
-
+    const AndroidLogEntry* entry);
 
 #ifdef __cplusplus
 }
 #endif
 
-
 #endif /*_LOGPRINT_H*/
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 18300bc..45266de 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -62,12 +62,19 @@
 bool NativeBridgeInitialized();
 
 // Load a shared library that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
 void* NativeBridgeLoadLibrary(const char* libpath, int flag);
 
 // Get a native bridge trampoline for specified native method.
 void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
 
-// True if native library is valid and is for an ABI that is supported by native bridge.
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// The *libpath* must point to a library.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsPathSupported() instead in namespace scenario.
 bool NativeBridgeIsSupported(const char* libpath);
 
 // Returns the version number of the native bridge. This information is available after a
@@ -91,6 +98,48 @@
 // This functionality is exposed mainly for testing.
 bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
 
+// Decrements the reference count on the dynamic library handler. If the reference count drops
+// to zero then the dynamic library is unloaded.
+int NativeBridgeUnloadLibrary(void* handle);
+
+// Get last error message of native bridge when fail to load library or search symbol.
+// This is reflection of dlerror() for native bridge.
+const char* NativeBridgeGetError();
+
+struct native_bridge_namespace_t;
+
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
+// libraries of an ABI.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsSupported() instead in non-namespace scenario.
+bool NativeBridgeIsPathSupported(const char* path);
+
+// Initializes public and anonymous namespace at native bridge side.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+                               const char* anon_ns_library_path);
+
+// Create a namespace and pass the key of related namespaces to native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+                                                       const char* ld_library_path,
+                                                       const char* default_library_path,
+                                                       uint64_t type,
+                                                       const char* permitted_when_isolated_path,
+                                                       native_bridge_namespace_t* parent_ns);
+
+// Load a shared library with namespace key that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
+
 // Native bridge interfaces to runtime.
 struct NativeBridgeCallbacks {
   // Version number of the interface.
@@ -114,6 +163,9 @@
   //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
   // Returns:
   //   The opaque handle of the shared library if sucessful, otherwise NULL
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use loadLibraryExt instead in namespace scenario.
   void* (*loadLibrary)(const char* libpath, int flag);
 
   // Get a native bridge trampoline for specified native method. The trampoline has same
@@ -133,6 +185,9 @@
   //   libpath [IN] path to the shared library
   // Returns:
   //   TRUE if library is supported by native bridge, FALSE otherwise
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use isPathSupported instead in namespace scenario.
   bool (*isSupported)(const char* libpath);
 
   // Provide environment values required by the app running with native bridge according to the
@@ -169,6 +224,88 @@
   //     runtime.
   //     Otherwise, a pointer to the signal handler.
   NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
+
+  // Added callbacks in version 3.
+
+  // Decrements the reference count on the dynamic library handler. If the reference count drops
+  // to zero then the dynamic library is unloaded.
+  //
+  // Parameters:
+  //     handle [IN] the handler of a dynamic library.
+  //
+  // Returns:
+  //   0 on success, and nonzero on error.
+  int (*unloadLibrary)(void* handle);
+
+  // Dump the last failure message of native bridge when fail to load library or search symbol.
+  //
+  // Parameters:
+  //
+  // Returns:
+  //   A string describing the most recent error that occurred when load library
+  //   or lookup symbol via native bridge.
+  const char* (*getError)();
+
+  // Check whether library paths are supported by native bridge.
+  //
+  // Parameters:
+  //   library_path [IN] search paths for native libraries (directories separated by ':')
+  // Returns:
+  //   TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use isSupported instead in non-namespace scenario.
+  bool (*isPathSupported)(const char* library_path);
+
+  // Initializes anonymous namespace at native bridge side and pass the key of
+  // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+  //
+  // Parameters:
+  //     public_ns_sonames [IN] the name of "public" libraries.
+  //     anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+  // Returns:
+  //     true if the pass is ok.
+  //     Otherwise, false.
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Should not use in non-namespace scenario.
+  bool (*initNamespace)(const char* public_ns_sonames,
+                        const char* anon_ns_library_path);
+
+
+  // Create a namespace and pass the key of releated namespaces to native bridge.
+  //
+  // Parameters:
+  //     name [IN] the name of the namespace.
+  //     ld_library_path [IN] the first set of library search paths of the namespace.
+  //     default_library_path [IN] the second set of library search path of the namespace.
+  //     type [IN] the attribute of the namespace.
+  //     permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+  //     parent_ns [IN] the pointer of the parent namespace to be inherited from.
+  // Returns:
+  //     native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Should not use in non-namespace scenario.
+  native_bridge_namespace_t* (*createNamespace)(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                native_bridge_namespace_t* parent_ns);
+
+  // Load a shared library within a namespace.
+  //
+  // Parameters:
+  //   libpath [IN] path to the shared library
+  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+  //   ns [IN] the pointer of the namespace in which the library should be loaded.
+  // Returns:
+  //   The opaque handle of the shared library if sucessful, otherwise NULL
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use loadLibrary instead in non-namespace scenario.
+  void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
 };
 
 // Runtime interfaces to native bridge.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 167a6d9..c364317 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -95,6 +95,7 @@
 #define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
 #define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
 #define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
+#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
@@ -208,6 +209,7 @@
     { "dns",           AID_DNS, },
     { "dns_tether",    AID_DNS_TETHER, },
     { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
+    { "vehicle_network", AID_VEHICLE_NETWORK, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index b6a20c3..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -21,11 +21,18 @@
 
 /* Android private interfaces */
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <android/log.h>
-#include <log/logger.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'
 
@@ -109,8 +116,8 @@
 ssize_t __android_log_pmsg_file_write(
         log_id_t logId,
         char prio,
-        const char *filename,
-        const char *buf, size_t len);
+        const char* filename,
+        const char* buf, size_t len);
 
 #define LOG_ID_ANY      ((log_id_t)-1)
 #define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
@@ -119,12 +126,66 @@
 typedef ssize_t (*__android_log_pmsg_file_read_fn)(
         log_id_t logId,
         char prio,
-        const char *filename,
-        const char *buf, size_t len, void *arg);
+        const char* filename,
+        const char* buf, size_t len, void* arg);
 
 ssize_t __android_log_pmsg_file_read(
-        log_id_t logId, char prio, const char *prefix,
-        __android_log_pmsg_file_read_fn fn, void *arg);
+        log_id_t logId, char prio, const char* prefix,
+        __android_log_pmsg_file_read_fn fn, void* arg);
+
+int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_security_bswrite(int32_t tag, const char* payload);
+int __android_log_security(); /* Device Owner is present */
+
+int __android_log_is_debuggable();
+
+#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
+#define BOOL_DEFAULT_FALSE       0x0     /* false if property not present   */
+#define BOOL_DEFAULT_TRUE        0x1     /* true if property not present    */
+#define BOOL_DEFAULT_FLAG_PERSIST    0x2 /* <key>, persist.<key>, ro.<key>  */
+#define BOOL_DEFAULT_FLAG_ENG        0x4 /* off for user                    */
+#define BOOL_DEFAULT_FLAG_SVELTE     0x8 /* off for low_ram                 */
+bool __android_logger_property_get_bool(const char* key, int flag);
+
+#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+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)
 }
diff --git a/include/system/graphics-base.h b/include/system/graphics-base.h
new file mode 100644
index 0000000..b86d031
--- /dev/null
+++ b/include/system/graphics-base.h
@@ -0,0 +1,133 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+#ifndef HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+    HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+    HAL_PIXEL_FORMAT_RGB_888 = 3,
+    HAL_PIXEL_FORMAT_RGB_565 = 4,
+    HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+    HAL_PIXEL_FORMAT_RGBA_FP16 = 16, // 0x10
+    HAL_PIXEL_FORMAT_RGBX_FP16 = 17, // 0x11
+    HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659
+    HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859
+    HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159
+    HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20
+    HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25
+    HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26
+    HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24
+    HAL_PIXEL_FORMAT_BLOB = 33, // 0x21
+    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22
+    HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23
+    HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
+    HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
+    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
+    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
+    HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10
+    HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11
+    HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14
+} android_pixel_format_t;
+
+typedef enum {
+    HAL_TRANSFORM_FLIP_H = 1, // 0x01
+    HAL_TRANSFORM_FLIP_V = 2, // 0x02
+    HAL_TRANSFORM_ROT_90 = 4, // 0x04
+    HAL_TRANSFORM_ROT_180 = 3, // 0x03
+    HAL_TRANSFORM_ROT_270 = 7, // 0x07
+} android_transform_t;
+
+typedef enum {
+    HAL_DATASPACE_UNKNOWN = 0, // 0x0
+    HAL_DATASPACE_ARBITRARY = 1, // 0x1
+    HAL_DATASPACE_STANDARD_SHIFT = 16,
+    HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT)
+    HAL_DATASPACE_TRANSFER_SHIFT = 22,
+    HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT)
+    HAL_DATASPACE_RANGE_SHIFT = 27,
+    HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT)
+    HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200
+    HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_V0_SCRGB_LINEAR = 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED)
+    HAL_DATASPACE_SRGB = 513, // 0x201
+    HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
+    HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED)
+    HAL_DATASPACE_JFIF = 257, // 0x101
+    HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+    HAL_DATASPACE_BT601_625 = 258, // 0x102
+    HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_BT601_525 = 259, // 0x103
+    HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_BT709 = 260, // 0x104
+    HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL)
+    HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL)
+    HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+    HAL_DATASPACE_DEPTH = 4096, // 0x1000
+} android_dataspace_t;
+
+typedef enum {
+    HAL_COLOR_MODE_NATIVE = 0,
+    HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+    HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+    HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+    HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+    HAL_COLOR_MODE_STANDARD_BT709 = 5,
+    HAL_COLOR_MODE_DCI_P3 = 6,
+    HAL_COLOR_MODE_SRGB = 7,
+    HAL_COLOR_MODE_ADOBE_RGB = 8,
+} android_color_mode_t;
+
+typedef enum {
+    HAL_COLOR_TRANSFORM_IDENTITY = 0,
+    HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+    HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+    HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+    HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+    HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+    HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+} android_color_transform_t;
+
+typedef enum {
+    HAL_HDR_DOLBY_VISION = 1,
+    HAL_HDR_HDR10 = 2,
+    HAL_HDR_HLG = 3,
+} android_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // HIDL_GENERATED_android_hardware_graphics_common_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ae10fa0..449b8c7 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -20,10 +20,30 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/*
+ * Some of the enums are now defined in HIDL in hardware/interfaces and are
+ * generated.
+ */
+#include "graphics-base.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
+#define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
+#define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
+typedef android_pixel_format_t android_pixel_format;
+typedef android_transform_t android_transform;
+typedef android_dataspace_t android_dataspace;
+typedef android_color_mode_t android_color_mode;
+typedef android_color_transform_t android_color_transform;
+typedef android_hdr_t android_hdr;
+
 /*
  * If the HAL needs to create service threads to handle graphics related
  * tasks, these threads need to run at HAL_PRIORITY_URGENT_DISPLAY priority
@@ -38,411 +58,6 @@
 
 #define HAL_PRIORITY_URGENT_DISPLAY     (-8)
 
-/**
- * pixel format definitions
- */
-
-typedef enum android_pixel_format {
-    /*
-     * "linear" color pixel formats:
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     *
-     * The color space determines, for example, if the formats are linear or
-     * gamma-corrected; or whether any special operations are performed when
-     * reading or writing into a buffer in one of these formats.
-     */
-    HAL_PIXEL_FORMAT_RGBA_8888          = 1,
-    HAL_PIXEL_FORMAT_RGBX_8888          = 2,
-    HAL_PIXEL_FORMAT_RGB_888            = 3,
-    HAL_PIXEL_FORMAT_RGB_565            = 4,
-    HAL_PIXEL_FORMAT_BGRA_8888          = 5,
-
-    /*
-     * 0x100 - 0x1FF
-     *
-     * This range is reserved for pixel formats that are specific to the HAL
-     * implementation.  Implementations can use any value in this range to
-     * communicate video pixel formats between their HAL modules.  These formats
-     * must not have an alpha channel.  Additionally, an EGLimage created from a
-     * gralloc buffer of one of these formats must be supported for use with the
-     * GL_OES_EGL_image_external OpenGL ES extension.
-     */
-
-    /*
-     * Android YUV format:
-     *
-     * This format is exposed outside of the HAL to software decoders and
-     * applications.  EGLImageKHR must support it in conjunction with the
-     * OES_EGL_image_external extension.
-     *
-     * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
-     * by (W/2) x (H/2) Cr and Cb planes.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     *
-     *   y_size = stride * height
-     *   c_stride = ALIGN(stride/2, 16)
-     *   c_size = c_stride * height/2
-     *   size = y_size + c_size * 2
-     *   cr_offset = y_size
-     *   cb_offset = y_size + c_size
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
-
-
-    /*
-     * Android Y8 format:
-     *
-     * This format is exposed outside of the HAL to the framework.
-     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
-     * and no other HW_ flags will be used.
-     *
-     * Y8 is a YUV planar format comprised of a WxH Y plane,
-     * with each pixel being represented by 8 bits.
-     *
-     * It is equivalent to just the Y plane from YV12.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     *
-     *   size = stride * height
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_Y8     = 0x20203859,
-
-    /*
-     * Android Y16 format:
-     *
-     * This format is exposed outside of the HAL to the framework.
-     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
-     * and no other HW_ flags will be used.
-     *
-     * Y16 is a YUV planar format comprised of a WxH Y plane,
-     * with each pixel being represented by 16 bits.
-     *
-     * It is just like Y8, but has double the bits per pixel (little endian).
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     * - strides are specified in pixels, not in bytes
-     *
-     *   size = stride * height * 2
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer, except that dataSpace field
-     * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
-     * image where each sample is a distance value measured by a depth camera,
-     * plus an associated confidence value.
-     */
-    HAL_PIXEL_FORMAT_Y16    = 0x20363159,
-
-    /*
-     * Android RAW sensor format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW16 is a single-channel, 16-bit, little endian format, typically
-     * representing raw Bayer-pattern images from an image sensor, with minimal
-     * processing.
-     *
-     * The exact pixel layout of the data in the buffer is sensor-dependent, and
-     * needs to be queried from the camera device.
-     *
-     * Generally, not all 16 bits are used; more common values are 10 or 12
-     * bits. If not all bits are used, the lower-order bits are filled first.
-     * All parameters to interpret the raw data (black and white points,
-     * color space, etc) must be queried from the camera device.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     * - strides are specified in pixels, not in bytes
-     *
-     *   size = stride * height * 2
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW16 = 0x20,
-
-    /*
-     * Android RAW10 format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
-     * unprocessed format, usually representing raw Bayer-pattern images coming from
-     * an image sensor.
-     *
-     * In an image buffer with this format, starting from the first pixel of each
-     * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
-     * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
-     * contains the 2 least significant bits of the 4 pixels, the exact layout data
-     * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
-     * bit of the ith pixel):
-     *
-     *          bit 7                                     bit 0
-     *          =====|=====|=====|=====|=====|=====|=====|=====|
-     * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
-     *          ===============================================
-     *
-     * This format assumes
-     * - a width multiple of 4 pixels
-     * - an even height
-     * - a vertical stride equal to the height
-     * - strides are specified in bytes, not in pixels
-     *
-     *   size = stride * height
-     *
-     * When stride is equal to width * (10 / 8), there will be no padding bytes at
-     * the end of each row, the entire image data is densely packed. When stride is
-     * larger than width * (10 / 8), padding bytes will be present at the end of each
-     * row (including the last row).
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW10 = 0x25,
-
-    /*
-     * Android RAW12 format:
-     *
-     * This format is exposed outside of camera HAL to applications.
-     *
-     * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
-     * unprocessed format, usually representing raw Bayer-pattern images coming from
-     * an image sensor.
-     *
-     * In an image buffer with this format, starting from the first pixel of each
-     * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
-     * and second byte contains the top 8 bits of first and second pixel. The third
-     * byte contains the 4 least significant bits of the two pixels, the exact layout
-     * data for each two consecutive pixels is illustrated below (Pi[j] stands for
-     * the jth bit of the ith pixel):
-     *
-     *           bit 7                                            bit 0
-     *          ======|======|======|======|======|======|======|======|
-     * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
-     *         |------|------|------|------|------|------|------|------|
-     * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
-     *         |------|------|------|------|------|------|------|------|
-     * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
-     *          =======================================================
-     *
-     * This format assumes:
-     * - a width multiple of 4 pixels
-     * - an even height
-     * - a vertical stride equal to the height
-     * - strides are specified in bytes, not in pixels
-     *
-     *   size = stride * height
-     *
-     * When stride is equal to width * (12 / 8), there will be no padding bytes at
-     * the end of each row, the entire image data is densely packed. When stride is
-     * larger than width * (12 / 8), padding bytes will be present at the end of
-     * each row (including the last row).
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW12 = 0x26,
-
-    /*
-     * Android opaque RAW format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
-     * image sensor. The actual structure of buffers of this format is
-     * implementation-dependent.
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
-
-    /*
-     * Android binary blob graphics buffer format:
-     *
-     * This format is used to carry task-specific data which does not have a
-     * standard image structure. The details of the format are left to the two
-     * endpoints.
-     *
-     * A typical use case is for transporting JPEG-compressed images from the
-     * Camera HAL to the framework or to applications.
-     *
-     * Buffers of this format must have a height of 1, and width equal to their
-     * size in bytes.
-     *
-     * When used with ANativeWindow, the mapping of the dataSpace field to
-     * buffer contents for BLOB is as follows:
-     *
-     *  dataSpace value               | Buffer contents
-     * -------------------------------+-----------------------------------------
-     *  HAL_DATASPACE_JFIF            | An encoded JPEG image
-     *  HAL_DATASPACE_DEPTH           | An android_depth_points buffer
-     *  Other                         | Unsupported
-     *
-     */
-    HAL_PIXEL_FORMAT_BLOB = 0x21,
-
-    /*
-     * Android format indicating that the choice of format is entirely up to the
-     * device-specific Gralloc implementation.
-     *
-     * The Gralloc implementation should examine the usage bits passed in when
-     * allocating a buffer with this format, and it should derive the pixel
-     * format from those usage flags.  This format will never be used with any
-     * of the GRALLOC_USAGE_SW_* usage flags.
-     *
-     * If a buffer of this format is to be used as an OpenGL ES texture, the
-     * framework will assume that sampling the texture will always return an
-     * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
-
-    /*
-     * Android flexible YCbCr 4:2:0 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * struct android_ycbcr (below) is the the struct used to describe it.
-     *
-     * This format must be accepted by the gralloc module when
-     * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
-     *
-     * This format is locked for use by gralloc's (*lock_ycbcr) method, and
-     * locking with the (*lock) method will return an error.
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
-
-    /*
-     * Android flexible YCbCr 4:2:2 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27,
-
-    /*
-     * Android flexible YCbCr 4:4:4 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28,
-
-    /*
-     * Android flexible RGB 888 formats
-     *
-     * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called RGB, it can be
-     * used to describe formats with either color ordering and optional
-     * padding, as well as whole planar layout.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29,
-
-    /*
-     * Android flexible RGBA 8888 formats
-     *
-     * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called RGBA, it can be
-     * used to describe formats with any of the component orderings, as
-     * well as whole planar layout.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A,
-
-    /* Legacy formats (deprecated), used by ImageFormat.java */
-    HAL_PIXEL_FORMAT_YCbCr_422_SP       = 0x10, // NV16
-    HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11, // NV21
-    HAL_PIXEL_FORMAT_YCbCr_422_I        = 0x14, // YUY2
-} android_pixel_format_t;
-
 /*
  * Structure for describing YCbCr formats for consumption by applications.
  * This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
@@ -622,797 +237,6 @@
 #endif
 };
 
-/**
- * Transformation definitions
- *
- * IMPORTANT NOTE:
- * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}.
- *
- */
-
-typedef enum android_transform {
-    /* flip source image horizontally (around the vertical axis) */
-    HAL_TRANSFORM_FLIP_H    = 0x01,
-    /* flip source image vertically (around the horizontal axis)*/
-    HAL_TRANSFORM_FLIP_V    = 0x02,
-    /* rotate source image 90 degrees clockwise */
-    HAL_TRANSFORM_ROT_90    = 0x04,
-    /* rotate source image 180 degrees */
-    HAL_TRANSFORM_ROT_180   = 0x03,
-    /* rotate source image 270 degrees clockwise */
-    HAL_TRANSFORM_ROT_270   = 0x07,
-    /* don't use. see system/window.h */
-    HAL_TRANSFORM_RESERVED  = 0x08,
-} android_transform_t;
-
-/**
- * Dataspace Definitions
- * ======================
- *
- * Dataspace is the definition of how pixel values should be interpreted.
- *
- * For many formats, this is the colorspace of the image data, which includes
- * primaries (including white point) and the transfer characteristic function,
- * which describes both gamma curve and numeric range (within the bit depth).
- *
- * Other dataspaces include depth measurement data from a depth camera.
- *
- * A dataspace is comprised of a number of fields.
- *
- * Version
- * --------
- * The top 2 bits represent the revision of the field specification. This is
- * currently always 0.
- *
- *
- * bits    31-30 29                      -                          0
- *        +-----+----------------------------------------------------+
- * fields | Rev |            Revision specific fields                |
- *        +-----+----------------------------------------------------+
- *
- * Field layout for version = 0:
- * ----------------------------
- *
- * A dataspace is comprised of the following fields:
- *      Standard
- *      Transfer function
- *      Range
- *
- * bits    31-30 29-27 26 -  22 21 -  16 15             -           0
- *        +-----+-----+--------+--------+----------------------------+
- * fields |  0  |Range|Transfer|Standard|    Legacy and custom       |
- *        +-----+-----+--------+--------+----------------------------+
- *          VV    RRR   TTTTT    SSSSSS    LLLLLLLL       LLLLLLLL
- *
- * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
- * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
- * or a custom value.
- */
-
-typedef enum android_dataspace {
-    /*
-     * Default-assumption data space, when not explicitly specified.
-     *
-     * It is safest to assume the buffer is an image with sRGB primaries and
-     * encoding ranges, but the consumer and/or the producer of the data may
-     * simply be using defaults. No automatic gamma transform should be
-     * expected, except for a possible display gamma transform when drawn to a
-     * screen.
-     */
-    HAL_DATASPACE_UNKNOWN = 0x0,
-
-    /*
-     * Arbitrary dataspace with manually defined characteristics.  Definition
-     * for colorspaces or other meaning must be communicated separately.
-     *
-     * This is used when specifying primaries, transfer characteristics,
-     * etc. separately.
-     *
-     * A typical use case is in video encoding parameters (e.g. for H.264),
-     * where a colorspace can have separately defined primaries, transfer
-     * characteristics, etc.
-     */
-    HAL_DATASPACE_ARBITRARY = 0x1,
-
-    /*
-     * Color-description aspects
-     *
-     * The following aspects define various characteristics of the color
-     * specification. These represent bitfields, so that a data space value
-     * can specify each of them independently.
-     */
-
-    HAL_DATASPACE_STANDARD_SHIFT = 16,
-
-    /*
-     * Standard aspect
-     *
-     * Defines the chromaticity coordinates of the source primaries in terms of
-     * the CIE 1931 definition of x and y specified in ISO 11664-1.
-     */
-    HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT,  // 0x3F
-
-    /*
-     * Chromacity coordinates are unknown or are determined by the application.
-     * Implementations shall use the following suggested standards:
-     *
-     * All YCbCr formats: BT709 if size is 720p or larger (since most video
-     *                    content is letterboxed this corresponds to width is
-     *                    1280 or greater, or height is 720 or greater).
-     *                    BT601_625 if size is smaller than 720p or is JPEG.
-     * All RGB formats:   BT709.
-     *
-     * For all other formats standard is undefined, and implementations should use
-     * an appropriate standard for the data represented.
-     */
-    HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.300   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-     *  for RGB conversion from the one purely determined by the primaries
-     *  to minimize the color shift into RGB space that uses BT.709
-     *  primaries.
-     */
-    HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.310   0.595
-     *  blue            0.155   0.070
-     *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
-     *
-     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-     *  for RGB conversion from the one purely determined by the primaries
-     *  to minimize the color shift into RGB space that uses BT.709
-     *  primaries.
-     */
-    HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.310   0.595
-     *  blue            0.155   0.070
-     *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
-     * for RGB conversion (as in SMPTE 240M).
-     */
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.170   0.797
-     *  blue            0.131   0.046
-     *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.170   0.797
-     *  blue            0.131   0.046
-     *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
-     * for RGB conversion using the linear domain.
-     */
-    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x      y
-     *  green           0.21   0.71
-     *  blue            0.14   0.08
-     *  red             0.67   0.33
-     *  white (C)       0.310  0.316
-     *
-     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.243   0.692
-     *  blue            0.145   0.049
-     *  red             0.681   0.319
-     *  white (C)       0.310   0.316
-     *
-     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    HAL_DATASPACE_TRANSFER_SHIFT = 22,
-
-    /*
-     * Transfer aspect
-     *
-     * Transfer characteristics are the opto-electronic transfer characteristic
-     * at the source as a function of linear optical intensity (luminance).
-     *
-     * For digital signals, E corresponds to the recorded value. Normally, the
-     * transfer function is applied in RGB space to each of the R, G and B
-     * components independently. This may result in color shift that can be
-     * minized by applying the transfer function in Lab space only for the L
-     * component. Implementation may apply the transfer function in RGB space
-     * for all pixel formats if desired.
-     */
-
-    HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT,  // 0x1F
-
-    /*
-     * Transfer characteristics are unknown or are determined by the
-     * application.
-     *
-     * Implementations should use the following transfer functions:
-     *
-     * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
-     * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
-     *
-     * For all other formats transfer function is undefined, and implementations
-     * should use an appropriate standard for the data represented.
-     */
-    HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Transfer characteristic curve:
-     *  E = L
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Transfer characteristic curve:
-     *
-     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
-     *   = 12.92 * L                  for 0 <= L < 0.0031308
-     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *     E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * BT.601 525, BT.601 625, BT.709, BT.2020
-     *
-     * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
-     *    = 4.500 * L                 for 0 <= L < 0.018
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Assumed display gamma 2.2.
-     *
-     * Transfer characteristic curve:
-     *  E = L ^ (1/2.2)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     *  display gamma 2.8.
-     *
-     * Transfer characteristic curve:
-     *  E = L ^ (1/2.8)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * SMPTE ST 2084
-     *
-     * Transfer characteristic curve:
-     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
-     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
-     *  c2 = 32 * 2413 / 4096 = 18.8515625
-     *  c3 = 32 * 2392 / 4096 = 18.6875
-     *  m = 128 * 2523 / 4096 = 78.84375
-     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
-     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
-     *          L = 1 corresponds to 10000 cd/m2
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * ARIB STD-B67 Hybrid Log Gamma
-     *
-     * Transfer characteristic curve:
-     *  E = r * L^0.5                 for 0 <= L <= 1
-     *    = a * ln(L - b) + c         for 1 < L
-     *  a = 0.17883277
-     *  b = 0.28466892
-     *  c = 0.55991073
-     *  r = 0.5
-     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
-     *          to reference white level of 100 cd/m2
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    HAL_DATASPACE_RANGE_SHIFT = 27,
-
-    /*
-     * Range aspect
-     *
-     * Defines the range of values corresponding to the unit range of 0-1.
-     * This is defined for YCbCr only, but can be expanded to RGB space.
-     */
-    HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT,  // 0x7
-
-    /*
-     * Range is unknown or are determined by the application.  Implementations
-     * shall use the following suggested ranges:
-     *
-     * All YCbCr formats: limited range.
-     * All RGB or RGBA formats (including RAW and Bayer): full range.
-     * All Y formats: full range
-     *
-     * For all other formats range is undefined, and implementations should use
-     * an appropriate range for the data represented.
-     */
-    HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Full range uses all values for Y, Cb and Cr from
-     * 0 to 2^b-1, where b is the bit depth of the color format.
-     */
-    HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
-     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
-     * the color format.
-     *
-     * E.g. For 8-bit-depth formats:
-     * Luma (Y) samples should range from 16 to 235, inclusive
-     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
-     *
-     * For 10-bit-depth formats:
-     * Luma (Y) samples should range from 64 to 940, inclusive
-     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
-     */
-    HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Legacy dataspaces
-     */
-
-    /*
-     * sRGB linear encoding:
-     *
-     * The red, green, and blue components are stored in sRGB space, but
-     * are linear, not gamma-encoded.
-     * The RGB primaries and the white point are the same as BT.709.
-     *
-     * The values are encoded using the full range ([0,255] for 8-bit) for all
-     * components.
-     */
-    HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
-
-    HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
-
-
-    /*
-     * sRGB gamma encoding:
-     *
-     * The red, green and blue components are stored in sRGB space, and
-     * converted to linear space when read, using the SRGB transfer function
-     * for each of the R, G and B components. When written, the inverse
-     * transformation is performed.
-     *
-     * The alpha component, if present, is always stored in linear space and
-     * is left unmodified when read or written.
-     *
-     * Use full range and BT.709 standard.
-     */
-    HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
-
-    HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
-
-
-    /*
-     * YCbCr Colorspaces
-     * -----------------
-     *
-     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
-     * of x and y specified by ISO 11664-1.
-     *
-     * Transfer characteristics are the opto-electronic transfer characteristic
-     * at the source as a function of linear optical intensity (luminance).
-     */
-
-    /*
-     * JPEG File Interchange Format (JFIF)
-     *
-     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
-     *
-     * Use full range, BT.601 transfer and BT.601_625 standard.
-     */
-    HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
-
-    HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
-
-    /*
-     * ITU-R Recommendation 601 (BT.601) - 625-line
-     *
-     * Standard-definition television, 625 Lines (PAL)
-     *
-     * Use limited range, BT.601 transfer and BT.601_625 standard.
-     */
-    HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
-
-    HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-
-    /*
-     * ITU-R Recommendation 601 (BT.601) - 525-line
-     *
-     * Standard-definition television, 525 Lines (NTSC)
-     *
-     * Use limited range, BT.601 transfer and BT.601_525 standard.
-     */
-    HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
-
-    HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-    /*
-     * ITU-R Recommendation 709 (BT.709)
-     *
-     * High-definition television
-     *
-     * Use limited range, BT.709 transfer and BT.709 standard.
-     */
-    HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
-
-    HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-    /*
-     * Data spaces for non-color formats
-     */
-
-    /*
-     * The buffer contains depth ranging measurements from a depth camera.
-     * This value is valid with formats:
-     *    HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
-     *       and an associated confidence value. The 3 MSBs of the sample make
-     *       up the confidence value, and the low 13 LSBs of the sample make up
-     *       the depth measurement.
-     *       For the confidence section, 0 means 100% confidence, 1 means 0%
-     *       confidence. The mapping to a linear float confidence value between
-     *       0.f and 1.f can be obtained with
-     *         float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
-     *       The depth measurement can be extracted simply with
-     *         uint16_t range = (depthSample & 0x1FFF);
-     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
-     *       a variable-length float (x,y,z, confidence) coordinate point list.
-     *       The point cloud will be represented with the android_depth_points
-     *       structure.
-     */
-    HAL_DATASPACE_DEPTH = 0x1000
-
-} android_dataspace_t;
-
-/*
- * Color modes that may be supported by a display.
- *
- * Definitions:
- * Rendering intent generally defines the goal in mapping a source (input)
- * color to a destination device color for a given color mode.
- *
- *  It is important to keep in mind three cases where mapping may be applied:
- *  1. The source gamut is much smaller than the destination (display) gamut
- *  2. The source gamut is much larger than the destination gamut (this will
- *  ordinarily be handled using colorimetric rendering, below)
- *  3. The source and destination gamuts are roughly equal, although not
- *  completely overlapping
- *  Also, a common requirement for mappings is that skin tones should be
- *  preserved, or at least remain natural in appearance.
- *
- *  Colorimetric Rendering Intent (All cases):
- *  Colorimetric indicates that colors should be preserved. In the case
- *  that the source gamut lies wholly within the destination gamut or is
- *  about the same (#1, #3), this will simply mean that no manipulations
- *  (no saturation boost, for example) are applied. In the case where some
- *  source colors lie outside the destination gamut (#2, #3), those will
- *  need to be mapped to colors that are within the destination gamut,
- *  while the already in-gamut colors remain unchanged.
- *
- *  Non-colorimetric transforms can take many forms. There are no hard
- *  rules and it's left to the implementation to define.
- *  Two common intents are described below.
- *
- *  Stretched-Gamut Enhancement Intent (Source < Destination):
- *  When the destination gamut is much larger than the source gamut (#1), the
- *  source primaries may be redefined to reflect the full extent of the
- *  destination space, or to reflect an intermediate gamut.
- *  Skin-tone preservation would likely be applied. An example might be sRGB
- *  input displayed on a DCI-P3 capable device, with skin-tone preservation.
- *
- *  Within-Gamut Enhancement Intent (Source >= Destination):
- *  When the device (destination) gamut is not larger than the source gamut
- *  (#2 or #3), but the appearance of a larger gamut is desired, techniques
- *  such as saturation boost may be applied to the source colors. Skin-tone
- *  preservation may be applied. There is no unique method for within-gamut
- *  enhancement; it would be defined within a flexible color mode.
- *
- */
-typedef enum android_color_mode {
-
-  /*
-   * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
-   * White Point: Vendor/OEM defined
-   * Panel Gamma: Vendor/OEM defined (typically 2.2)
-   * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
-   */
-  HAL_COLOR_MODE_NATIVE = 0,
-
-  /*
-   * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
-   * settings that implement the ITU-R Recommendation BT.601
-   * or Rec 601. Using 625 line version
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.290   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-   *  for RGB conversion from the one purely determined by the primaries
-   *  to minimize the color shift into RGB space that uses BT.709
-   *  primaries.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.290   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   *  Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
-   *  for RGB conversion.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.310   0.595
-   *  blue            0.155   0.070
-   *  red             0.630   0.340
-   *  white (D65)     0.3127  0.3290
-   *
-   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-   *  for RGB conversion from the one purely determined by the primaries
-   *  to minimize the color shift into RGB space that uses BT.709
-   *  primaries.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.310   0.595
-   *  blue            0.155   0.070
-   *  red             0.630   0.340
-   *  white (D65)     0.3127  0.3290
-   *
-   *  Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
-   *  for RGB conversion (as in SMPTE 240M).
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
-
-  /*
-   * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
-   * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.300   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
-   * (with [0 to 1] range) value of R, G, or B.
-   *
-   *  if Vnonlinear < 0.081
-   *    Vlinear = Vnonlinear / 4.5
-   *  else
-   *    Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
-   *
-   * HDTV REC709 Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.5 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT709 = 5,
-
-  /*
-   * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
-   * SMPTE EG 432-1 and SMPTE RP 431-2
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.265   0.690
-   *  blue            0.150   0.060
-   *  red             0.680   0.320
-   *  white (D65)     0.3127  0.3290
-   *
-   * Gamma: 2.2
-   */
-  HAL_COLOR_MODE_DCI_P3 = 6,
-
-  /*
-   * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
-   * the sRGB color space. Uses the same primaries as ITU-R Recommendation
-   * BT.709
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.300   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
-   *
-   *  if Vnonlinear ≤ 0.03928
-   *    Vlinear = Vnonlinear / 12.92
-   *  else
-   *    Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
-   *
-   * PC/Internet (sRGB) Gamma Correction (GC):
-   *
-   *  if Vlinear ≤ 0.0031308
-   *    Vnonlinear = 12.92 * Vlinear
-   *  else
-   *    Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
-   */
-  HAL_COLOR_MODE_SRGB = 7,
-
-  /*
-   * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
-   * by Adobe Systems, Inc. in 1998.
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.210   0.710
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * Gamma: 2.2
-   */
-  HAL_COLOR_MODE_ADOBE_RGB = 8
-
-} android_color_mode_t;
-
-/*
- * Color transforms that may be applied by hardware composer to the whole
- * display.
- */
-typedef enum android_color_transform {
-    /* Applies no transform to the output color */
-    HAL_COLOR_TRANSFORM_IDENTITY = 0,
-
-    /* Applies an arbitrary transform defined by a 4x4 affine matrix */
-    HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
-
-    /* Applies a transform that inverts the value or luminance of the color, but
-     * does not modify hue or saturation */
-    HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
-
-    /* Applies a transform that maps all colors to shades of gray */
-    HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
-
-    /* Applies a transform which corrects for protanopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
-
-    /* Applies a transform which corrects for deuteranopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
-
-    /* Applies a transform which corrects for tritanopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
-} android_color_transform_t;
-
-/*
- * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
- */
-typedef enum android_hdr {
-    /* Device supports Dolby Vision HDR */
-    HAL_HDR_DOLBY_VISION = 1,
-
-    /* Device supports HDR10 */
-    HAL_HDR_HDR10 = 2,
-
-    /* Device supports hybrid log-gamma HDR */
-    HAL_HDR_HLG = 3
-} android_hdr_t;
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/system/radio.h b/include/system/radio.h
index d73d3ae..b164fc8 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -81,7 +81,7 @@
 } radio_direction_t;
 
 /* unique handle allocated to a radio module */
-typedef unsigned int radio_handle_t;
+typedef uint32_t radio_handle_t;
 
 /* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
 typedef struct radio_medtadata radio_metadata_t;
@@ -109,10 +109,10 @@
 typedef struct radio_hal_band_config {
     radio_band_t type;
     bool         antenna_connected;
-    unsigned int lower_limit;
-    unsigned int upper_limit;
-    unsigned int num_spacings;
-    unsigned int spacings[RADIO_NUM_SPACINGS_MAX];
+    uint32_t     lower_limit;
+    uint32_t     upper_limit;
+    uint32_t     num_spacings;
+    uint32_t     spacings[RADIO_NUM_SPACINGS_MAX];
     union {
         radio_hal_fm_band_config_t fm;
         radio_hal_am_band_config_t am;
@@ -137,10 +137,10 @@
     char            product[RADIO_STRING_LEN_MAX];  /* product name */
     char            version[RADIO_STRING_LEN_MAX];  /* product version */
     char            serial[RADIO_STRING_LEN_MAX];  /* serial number (for subscription services) */
-    unsigned int    num_tuners;     /* number of tuners controllable independently */
-    unsigned int    num_audio_sources; /* number of audio sources driven simultaneously */
+    uint32_t        num_tuners;     /* number of tuners controllable independently */
+    uint32_t        num_audio_sources; /* number of audio sources driven simultaneously */
     bool            supports_capture; /* the hardware supports capture of audio source audio HAL */
-    unsigned int    num_bands;      /* number of band descriptors */
+    uint32_t        num_bands;      /* number of band descriptors */
     radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
 } radio_hal_properties_t;
 
@@ -153,10 +153,10 @@
     char                product[RADIO_STRING_LEN_MAX];
     char                version[RADIO_STRING_LEN_MAX];
     char                serial[RADIO_STRING_LEN_MAX];
-    unsigned int        num_tuners;
-    unsigned int        num_audio_sources;
+    uint32_t            num_tuners;
+    uint32_t            num_audio_sources;
     bool                supports_capture;
-    unsigned int        num_bands;
+    uint32_t            num_bands;
     radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
 } radio_properties_t;
 
@@ -164,13 +164,14 @@
  * Contains information on currently tuned channel.
  */
 typedef struct radio_program_info {
-    unsigned int     channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
-    unsigned int     sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
+    uint32_t         channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
+    uint32_t         sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
     bool             tuned;     /* tuned to a program or not */
     bool             stereo;    /* program is stereo or not */
     bool             digital;   /* digital program or not (e.g HD Radio program) */
-    unsigned int     signal_strength; /* signal strength from 0 to 100 */
-    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+    uint32_t         signal_strength; /* signal strength from 0 to 100 */
+                                /* non null if meta data are present (e.g PTY, song title ...) */
+    __attribute__((aligned(8))) radio_metadata_t *metadata;
 } radio_program_info_t;
 
 
@@ -195,7 +196,7 @@
 /* Event passed to the framework by the HAL callback */
 typedef struct radio_hal_event {
     radio_event_type_t  type;       /* event type */
-    int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
+    int32_t             status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
     union {
         /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
         bool                    on;
@@ -208,12 +209,13 @@
 /* Used internally by the framework. Same information as in struct radio_hal_event */
 typedef struct radio_event {
     radio_event_type_t  type;
-    int                 status;
+    int32_t             status;
     union {
         bool                    on;
         radio_band_config_t     config;
         radio_program_info_t    info;
-        radio_metadata_t        *metadata; /* offset from start of struct when in shared memory */
+                                /* non null if meta data are present (e.g PTY, song title ...) */
+        __attribute__((aligned(8))) radio_metadata_t *metadata;
     };
 } radio_event_t;
 
diff --git a/include/system/window.h b/include/system/window.h
index f439705..3faf2fb 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -121,8 +121,9 @@
     int stride;
     int format;
     int usage;
+    uintptr_t layerCount;
 
-    void* reserved[2];
+    void* reserved[1];
 
     buffer_handle_t handle;
 
@@ -297,6 +298,13 @@
      * Returns the duration of the last queueBuffer call in microseconds
      */
     NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
+
+    /*
+     * Returns the number of image layers that the ANativeWindow buffer
+     * contains. By default this is 1, unless a buffer is explicitly allocated
+     * to contain multiple layers.
+     */
+    NATIVE_WINDOW_LAYER_COUNT = 16,
 };
 
 /* Valid operations for the (*perform)() hook.
diff --git a/include/utils/Log.h b/include/utils/Log.h
index 6ef3fa3..5276a49 100644
--- a/include/utils/Log.h
+++ b/include/utils/Log.h
@@ -30,7 +30,7 @@
 
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #ifdef __cplusplus
 
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 96dfcca..d57465d 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/TypeHelpers.h>
 #include <utils/Vector.h>
 #include <utils/VectorImpl.h>
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index 6c1931e..28a77b8 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -22,7 +22,7 @@
 
 #include <new>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/TypeHelpers.h>
 #include <utils/VectorImpl.h>
 
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 4f68c3b..54946fc 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -130,6 +130,8 @@
 int32_t OpenArchiveFd(const int fd, const char* debugFileName,
                       ZipArchiveHandle *handle, bool assume_ownership = true);
 
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
+                              ZipArchiveHandle *handle);
 /*
  * Close archive, releasing resources associated with it. This will
  * unmap the central directory of the zipfile and free all internal
@@ -193,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.
  */
@@ -214,6 +217,17 @@
 
 const char* ErrorCodeString(int32_t error_code);
 
+#if !defined(_WIN32)
+typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
+
+/*
+ * Stream the uncompressed data through the supplied function,
+ * passing cookie to it each time it gets called.
+*/
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+        ProcessZipEntryFunction func, void* cookie);
+#endif
+
 __END_DECLS
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/init/Android.mk b/init/Android.mk
index 98bf12d..442a5f3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,6 +45,8 @@
 LOCAL_CPPFLAGS := $(init_cflags)
 LOCAL_SRC_FILES:= \
     action.cpp \
+    capabilities.cpp \
+    descriptors.cpp \
     import_parser.cpp \
     init_parser.cpp \
     log.cpp \
@@ -53,6 +55,7 @@
     util.cpp \
 
 LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_WHOLE_STATIC_LIBRARIES := libcap
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
@@ -74,7 +77,6 @@
 
 LOCAL_MODULE:= init
 LOCAL_C_INCLUDES += \
-    system/extras/ext4_utils \
     system/core/mkbootimg
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -103,7 +105,7 @@
     libz \
     libprocessgroup
 
-# Create symlinks
+# Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
@@ -113,8 +115,8 @@
 include $(BUILD_EXECUTABLE)
 
 
-
-
+# Unit tests.
+# =========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := init_tests
 LOCAL_SRC_FILES := \
@@ -124,8 +126,10 @@
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
     libbase \
+    libselinux \
 
 LOCAL_STATIC_LIBRARIES := libinit
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
+LOCAL_CPPFLAGS := -Wall -Wextra -Werror
 include $(BUILD_NATIVE_TEST)
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/bootchart.cpp b/init/bootchart.cpp
index 467a838..8fb55f0 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -241,6 +241,7 @@
     fclose(log_disks);
     fclose(log_procs);
     acct(NULL);
+    LOG(INFO) << "Bootcharting finished";
 }
 
 void bootchart_sample(int* timeout) {
@@ -253,12 +254,12 @@
     int elapsed_time = current_time - g_last_bootchart_time;
 
     if (elapsed_time >= BOOTCHART_POLLING_MS) {
-        /* count missed samples */
+        // Count missed samples.
         while (elapsed_time >= BOOTCHART_POLLING_MS) {
             elapsed_time -= BOOTCHART_POLLING_MS;
             g_remaining_samples--;
         }
-        /* count may be negative, take a sample anyway */
+        // Count may be negative, take a sample anyway.
         g_last_bootchart_time = current_time;
         if (bootchart_step() < 0 || g_remaining_samples <= 0) {
             bootchart_finish();
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d25e4a8..42ae5e6 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -37,9 +37,10 @@
 #include <unistd.h>
 #include <linux/loop.h>
 #include <linux/module.h>
-#include <ext4_crypt.h>
-#include <ext4_crypt_init_extensions.h>
 
+#include <thread>
+
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
@@ -51,6 +52,8 @@
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
+#include <ext4_utils/ext4_crypt.h>
+#include <ext4_utils/ext4_crypt_init_extensions.h>
 #include <logwrap/logwrap.h>
 
 #include "action.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. */
@@ -304,7 +304,7 @@
     /* mkdir <path> [mode] [owner] [group] */
 
     if (args.size() >= 3) {
-        mode = std::stoul(args[2], 0, 8);
+        mode = std::strtoul(args[2].c_str(), 0, 8);
     }
 
     ret = make_dir(args[1].c_str(), mode);
@@ -449,7 +449,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;
         }
@@ -595,9 +595,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;
@@ -642,10 +642,13 @@
 static int do_setrlimit(const std::vector<std::string>& args) {
     struct rlimit limit;
     int resource;
-    resource = std::stoi(args[1]);
-    limit.rlim_cur = std::stoi(args[2]);
-    limit.rlim_max = std::stoi(args[3]);
-    return setrlimit(resource, &limit);
+    if (android::base::ParseInt(args[1], &resource) &&
+        android::base::ParseUint(args[2], &limit.rlim_cur) &&
+        android::base::ParseUint(args[3], &limit.rlim_max)) {
+        return setrlimit(resource, &limit);
+    }
+    LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
+    return -1;
 }
 
 static int do_start(const std::vector<std::string>& args) {
@@ -705,6 +708,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] << "'";
@@ -714,7 +726,7 @@
     std::string timeout = property_get("ro.build.shutdown_timeout");
     unsigned int delay = 0;
 
-    if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
+    if (android::base::ParseUint(timeout, &delay) && delay > 0) {
         Timer t;
         // Ask all services to terminate.
         ServiceManager::GetInstance().ForEachService(
@@ -742,7 +754,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";
     }
@@ -769,13 +781,11 @@
 }
 
 static int do_sysclktz(const std::vector<std::string>& args) {
-    struct timezone tz;
-
-    memset(&tz, 0, sizeof(tz));
-    tz.tz_minuteswest = std::stoi(args[1]);
-    if (settimeofday(NULL, &tz))
-        return -1;
-    return 0;
+    struct timezone tz = {};
+    if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
+        return 0;
+    }
+    return -1;
 }
 
 static int do_verity_load_state(const std::vector<std::string>& args) {
@@ -900,30 +910,55 @@
 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;
-    }
-    return ret;
-}
+    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}
+    };
 
-static int do_restorecon_recursive(const std::vector<std::string>& args) {
-    int ret = 0;
+    int flag = 0;
 
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        /* The contents of CE paths are encrypted on FBE devices until user
-         * credentials are presented (filenames inside are mangled), so we need
-         * to delay restorecon of those until vold explicitly requests it. */
-        if (restorecon_recursive_skipce(it->c_str()) < 0) {
-            ret = -errno;
+    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) {
+    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) {
     // TODO: support names instead/as well?
-    int log_level = std::stoi(args[1]);
+    int log_level = -1;
+    android::base::ParseInt(args[1], &log_level);
     android::base::LogSeverity severity;
     switch (log_level) {
         case 7: severity = android::base::DEBUG; break;
@@ -954,11 +989,14 @@
 
 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) {
-        return wait_for_file(args[1].c_str(), std::stoi(args[2]));
-    } else
-        return -1;
+        int timeout;
+        if (android::base::ParseInt(args[2], &timeout)) {
+            return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
+        }
+    }
+    return -1;
 }
 
 /*
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
new file mode 100644
index 0000000..4592adc
--- /dev/null
+++ b/init/capabilities.cpp
@@ -0,0 +1,166 @@
+// 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 "capabilities.h"
+
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#include <map>
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+#define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
+
+namespace {
+const std::map<std::string, int> cap_map = {
+    CAP_MAP_ENTRY(CHOWN),
+    CAP_MAP_ENTRY(DAC_OVERRIDE),
+    CAP_MAP_ENTRY(DAC_READ_SEARCH),
+    CAP_MAP_ENTRY(FOWNER),
+    CAP_MAP_ENTRY(FSETID),
+    CAP_MAP_ENTRY(KILL),
+    CAP_MAP_ENTRY(SETGID),
+    CAP_MAP_ENTRY(SETUID),
+    CAP_MAP_ENTRY(SETPCAP),
+    CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+    CAP_MAP_ENTRY(NET_BIND_SERVICE),
+    CAP_MAP_ENTRY(NET_BROADCAST),
+    CAP_MAP_ENTRY(NET_ADMIN),
+    CAP_MAP_ENTRY(NET_RAW),
+    CAP_MAP_ENTRY(IPC_LOCK),
+    CAP_MAP_ENTRY(IPC_OWNER),
+    CAP_MAP_ENTRY(SYS_MODULE),
+    CAP_MAP_ENTRY(SYS_RAWIO),
+    CAP_MAP_ENTRY(SYS_CHROOT),
+    CAP_MAP_ENTRY(SYS_PTRACE),
+    CAP_MAP_ENTRY(SYS_PACCT),
+    CAP_MAP_ENTRY(SYS_ADMIN),
+    CAP_MAP_ENTRY(SYS_BOOT),
+    CAP_MAP_ENTRY(SYS_NICE),
+    CAP_MAP_ENTRY(SYS_RESOURCE),
+    CAP_MAP_ENTRY(SYS_TIME),
+    CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+    CAP_MAP_ENTRY(MKNOD),
+    CAP_MAP_ENTRY(LEASE),
+    CAP_MAP_ENTRY(AUDIT_WRITE),
+    CAP_MAP_ENTRY(AUDIT_CONTROL),
+    CAP_MAP_ENTRY(SETFCAP),
+    CAP_MAP_ENTRY(MAC_OVERRIDE),
+    CAP_MAP_ENTRY(MAC_ADMIN),
+    CAP_MAP_ENTRY(SYSLOG),
+    CAP_MAP_ENTRY(WAKE_ALARM),
+    CAP_MAP_ENTRY(BLOCK_SUSPEND),
+    CAP_MAP_ENTRY(AUDIT_READ),
+};
+
+static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+
+bool DropBoundingSet(const CapSet& to_keep) {
+    for (size_t cap = 0; cap < to_keep.size(); ++cap) {
+        if (to_keep.test(cap)) {
+            // No need to drop this capability.
+            continue;
+        }
+        if (cap_drop_bound(cap) == -1) {
+            PLOG(ERROR) << "cap_drop_bound(" << cap << ") failed";
+            return false;
+        }
+    }
+    return true;
+}
+
+bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+    cap_t caps = cap_init();
+    auto deleter = [](cap_t* p) { cap_free(*p); };
+    std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+
+    cap_clear(caps);
+    cap_value_t value[1];
+    for (size_t cap = 0; cap <= to_keep.size(); ++cap) {
+        if (to_keep.test(cap)) {
+            value[0] = cap;
+            if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+                cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+                PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
+                return false;
+            }
+        }
+    }
+
+    if (add_setpcap) {
+        value[0] = CAP_SETPCAP;
+        if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+            cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+            PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
+            return false;
+        }
+    }
+
+    if (cap_set_proc(caps) != 0) {
+        PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
+        return false;
+    }
+    return true;
+}
+
+bool SetAmbientCaps(const CapSet& to_raise) {
+    for (size_t cap = 0; cap < to_raise.size(); ++cap) {
+        if (to_raise.test(cap)) {
+            if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) != 0) {
+                PLOG(ERROR) << "prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, " << cap << ") failed";
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+}  // namespace anonymous
+
+int LookupCap(const std::string& cap_name) {
+    auto e = cap_map.find(cap_name);
+    if (e != cap_map.end()) {
+        return e->second;
+    } else {
+        return -1;
+    }
+}
+
+bool SetCapsForExec(const CapSet& to_keep) {
+    // Need to keep SETPCAP to drop bounding set below.
+    bool add_setpcap = true;
+    if (!SetProcCaps(to_keep, add_setpcap)) {
+        LOG(ERROR) << "failed to apply initial capset";
+        return false;
+    }
+
+    if (!DropBoundingSet(to_keep)) {
+        return false;
+    }
+
+    // If SETPCAP wasn't specifically requested, drop it now.
+    add_setpcap = false;
+    if (!SetProcCaps(to_keep, add_setpcap)) {
+        LOG(ERROR) << "failed to apply final capset";
+        return false;
+    }
+
+    // Add the capabilities to the ambient set so that they are preserved across
+    // execve(2).
+    // See http://man7.org/linux/man-pages/man7/capabilities.7.html.
+    return SetAmbientCaps(to_keep);
+}
diff --git a/Android.bp b/init/capabilities.h
similarity index 74%
rename from Android.bp
rename to init/capabilities.h
index 949a7fe..368178d 100644
--- a/Android.bp
+++ b/init/capabilities.h
@@ -12,11 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-ndk_headers {
-    name: "liblog_headers",
-    from: "include/android",
-    to: "android",
-    srcs: ["include/android/log.h"],
-}
+#include <linux/capability.h>
 
-optional_subdirs = ["*"]
+#include <bitset>
+#include <string>
+
+using CapSet = std::bitset<CAP_LAST_CAP + 1>;
+
+int LookupCap(const std::string& cap_name);
+bool SetCapsForExec(const CapSet& to_keep);
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
new file mode 100644
index 0000000..429a76e
--- /dev/null
+++ b/init/descriptors.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "descriptors.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sockets.h>
+
+#include "init.h"
+#include "log.h"
+#include "util.h"
+
+DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+                               gid_t gid, int perm, const std::string& context)
+        : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
+}
+
+DescriptorInfo::~DescriptorInfo() {
+}
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
+  return os << "  descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
+}
+
+bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
+  return name_ == other.name_ && type_ == other.type_ && key() == other.key();
+}
+
+void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
+  // Create
+  const std::string& contextStr = context_.empty() ? globalContext : context_;
+  int fd = Create(contextStr);
+  if (fd < 0) return;
+
+  // Publish
+  std::string publishedName = key() + name_;
+  std::for_each(publishedName.begin(), publishedName.end(),
+                [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+  std::string val = android::base::StringPrintf("%d", fd);
+  add_environment(publishedName.c_str(), val.c_str());
+
+  // make sure we don't close on exec
+  fcntl(fd, F_SETFD, 0);
+}
+
+void DescriptorInfo::Clean() const {
+}
+
+SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+                       gid_t gid, int perm, const std::string& context)
+        : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+void SocketInfo::Clean() const {
+  unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
+}
+
+int SocketInfo::Create(const std::string& context) const {
+  int flags = ((type() == "stream" ? SOCK_STREAM :
+                (type() == "dgram" ? SOCK_DGRAM :
+                 SOCK_SEQPACKET)));
+  return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string SocketInfo::key() const {
+  return ANDROID_SOCKET_ENV_PREFIX;
+}
+
+FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
+                   gid_t gid, int perm, const std::string& context)
+        : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+int FileInfo::Create(const std::string& context) const {
+  int flags = ((type() == "r" ? O_RDONLY :
+                (type() == "w" ? (O_WRONLY | O_CREAT) :
+                 (O_RDWR | O_CREAT))));
+  return create_file(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string FileInfo::key() const {
+  return ANDROID_FILE_ENV_PREFIX;
+}
diff --git a/init/descriptors.h b/init/descriptors.h
new file mode 100644
index 0000000..ff276fb
--- /dev/null
+++ b/init/descriptors.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _INIT_DESCRIPTORS_H
+#define _INIT_DESCRIPTORS_H
+
+#include <sys/types.h>
+
+#include <string>
+
+class DescriptorInfo {
+ public:
+  DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+                 gid_t gid, int perm, const std::string& context);
+  virtual ~DescriptorInfo();
+
+  friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
+  bool operator==(const DescriptorInfo& other) const;
+
+  void CreateAndPublish(const std::string& globalContext) const;
+  virtual void Clean() const;
+
+ protected:
+  const std::string& name() const { return name_; }
+  const std::string& type() const { return type_; }
+  uid_t uid() const { return uid_; }
+  gid_t gid() const { return gid_; }
+  int perm() const { return perm_; }
+  const std::string& context() const { return context_; }
+
+ private:
+  std::string name_;
+  std::string type_;
+  uid_t uid_;
+  gid_t gid_;
+  int perm_;
+  std::string context_;
+
+  virtual int Create(const std::string& globalContext) const = 0;
+  virtual const std::string key() const = 0;
+};
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
+
+class SocketInfo : public DescriptorInfo {
+ public:
+  SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+             gid_t gid, int perm, const std::string& context);
+  void Clean() const override;
+ private:
+  virtual int Create(const std::string& context) const override;
+  virtual const std::string key() const override;
+};
+
+class FileInfo : public DescriptorInfo {
+ public:
+  FileInfo(const std::string& name, const std::string& type, uid_t uid,
+           gid_t gid, int perm, const std::string& context);
+ private:
+  virtual int Create(const std::string& context) const override;
+  virtual const std::string key() const override;
+};
+
+#endif
diff --git a/init/devices.cpp b/init/devices.cpp
index bad04ae..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);
     }
 }
 
@@ -294,7 +301,7 @@
             name += 9;
     }
 
-    LOG(INFO) << "adding platform device " << name << " (" << path << ")";
+    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
 
     bus = (platform_node*) calloc(1, sizeof(struct platform_node));
     bus->path = strdup(path);
@@ -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 7a0e114..85065b3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,7 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <fstream>
+#include <inttypes.h>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -50,6 +50,7 @@
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 
+#include <fstream>
 #include <memory>
 
 #include "action.h"
@@ -68,6 +69,8 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::StringPrintf;
+
 struct selabel_handle *sehandle;
 struct selabel_handle *sehandle_prop;
 
@@ -76,7 +79,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];
 
@@ -133,11 +136,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) {
@@ -165,7 +167,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;
     }
 
@@ -376,15 +378,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());
     }
 }
 
@@ -422,7 +423,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);
@@ -440,12 +441,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());
     }
 }
@@ -668,12 +669,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);
@@ -687,19 +690,47 @@
         mount("devpts", "/dev/pts", "devpts", 0, NULL);
         #define MAKE_STR(x) __STRING(x)
         mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
+        gid_t groups[] = { AID_READPROC };
+        setgroups(arraysize(groups), groups);
         mount("sysfs", "/sys", "sysfs", 0, NULL);
         mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
         mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
-        early_mount();
+        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);
 
-    LOG(INFO) << "init " << (is_first_stage ? "first stage" : "second stage") << " started!";
+    LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
 
-    if (!is_first_stage) {
+    if (is_first_stage) {
+        // Mount devices defined in android.early.* kernel commandline
+        early_mount();
+
+        // Set up SELinux, loading the SELinux policy.
+        selinux_initialize(true);
+
+        // 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, nullptr };
+        if (execv(path, args) == -1) {
+            PLOG(ERROR) << "execv(\"" << path << "\") failed";
+            security_failure();
+        }
+    } else {
         // Indicate that booting is in progress to background fw loaders, etc.
         close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
@@ -713,24 +744,12 @@
         // Propagate the kernel variables to internal variables
         // used by init as well as the current required properties.
         export_kernel_boot_props();
-    }
 
-    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
-    selinux_initialize(is_first_stage);
+        // Make the time that init started available for bootstat to log.
+        property_set("init.start", getenv("INIT_STARTED_AT"));
 
-    // If we're in the kernel domain, re-exec init to transition to the init domain now
-    // that the SELinux policy has been loaded.
-    if (is_first_stage) {
-        if (restorecon("/init") == -1) {
-            PLOG(ERROR) << "restorecon failed";
-            security_failure();
-        }
-        char* path = argv[0];
-        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
-        if (execv(path, args) == -1) {
-            PLOG(ERROR) << "execv(\"" << path << "\") failed";
-            security_failure();
-        }
+        // Now set up SELinux for second stage.
+        selinux_initialize(false);
     }
 
     // These directories were necessarily created before initial policy load
@@ -740,10 +759,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);
@@ -804,21 +825,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/init_parser.cpp b/init/init_parser.cpp
index 9ec26af..d017390 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -122,14 +122,20 @@
         return false;
     }
     dirent* current_file;
+    std::vector<std::string> files;
     while ((current_file = readdir(config_dir.get()))) {
-        std::string current_path =
-            android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
         // Ignore directories and only process regular files.
         if (current_file->d_type == DT_REG) {
-            if (!ParseConfigFile(current_path)) {
-                LOG(ERROR) << "could not import file '" << current_path << "'";
-            }
+            std::string current_path =
+                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
+            files.emplace_back(current_path);
+        }
+    }
+    // Sort first so we load files in a consistent order (bug 31996208)
+    std::sort(files.begin(), files.end());
+    for (const auto& file : files) {
+        if (!ParseConfigFile(file)) {
+            LOG(ERROR) << "could not import file '" << file << "'";
         }
     }
     return true;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1e569af..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>
 
@@ -141,23 +142,24 @@
     }
 }
 
-static bool is_legal_property_name(const char* name, size_t namelen)
+bool is_legal_property_name(const std::string &name)
 {
-    size_t i;
+    size_t namelen = name.size();
+
     if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
 
-    /* Only allow alphanumeric, plus '.', '-', or '_' */
+    /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
     /* Don't allow ".." to appear in a property name */
-    for (i = 0; i < namelen; i++) {
+    for (size_t i = 0; i < namelen; i++) {
         if (name[i] == '.') {
             // i=0 is guaranteed to never have a dot. See above.
             if (name[i-1] == '.') return false;
             continue;
         }
-        if (name[i] == '_' || name[i] == '-') continue;
+        if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
         if (name[i] >= 'a' && name[i] <= 'z') continue;
         if (name[i] >= 'A' && name[i] <= 'Z') continue;
         if (name[i] >= '0' && name[i] <= '9') continue;
@@ -168,14 +170,13 @@
 }
 
 static int property_set_impl(const char* name, const char* value) {
-    size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
 
-    if (!is_legal_property_name(name, namelen)) return -1;
+    if (!is_legal_property_name(name)) return -1;
     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;
         }
     }
@@ -188,7 +189,7 @@
 
         __system_property_update(pi, value, valuelen);
     } else {
-        int rc = __system_property_add(name, namelen, value, valuelen);
+        int rc = __system_property_add(name, strlen(name), value, valuelen);
         if (rc < 0) {
             return rc;
         }
@@ -272,7 +273,7 @@
         msg.name[PROP_NAME_MAX-1] = 0;
         msg.value[PROP_VALUE_MAX-1] = 0;
 
-        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
+        if (!is_legal_property_name(msg.name)) {
             LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
             close(s);
             return;
diff --git a/init/property_service.h b/init/property_service.h
index dbaed34..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -34,6 +34,7 @@
 extern void start_property_service(void);
 std::string property_get(const char* name);
 extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
 
 
 #endif  /* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index 77e5de2..3cfdc4e 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -141,33 +141,49 @@
   Set the environment variable <name> to <value> in the launched process.
 
 socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
-  Create a unix domain socket named /dev/socket/<name> and pass
-  its fd to the launched process.  <type> must be "dgram", "stream" or "seqpacket".
-  User and group default to 0.
-  'seclabel' is the SELinux security context for the socket.
-  It defaults to the service security context, as specified by seclabel or
-  computed based on the service executable file security context.
+  Create a unix domain socket named /dev/socket/<name> and pass its fd to the
+  launched process.  <type> must be "dgram", "stream" or "seqpacket".  User and
+  group default to 0.  'seclabel' is the SELinux security context for the
+  socket.  It defaults to the service security context, as specified by
+  seclabel or computed based on the service executable file security context.
+  For native executables see libcutils android_get_control_socket().
+
+file <path> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
+  Open/Create a file path and pass its fd to the launched process.  <type> must
+  be "r", "w" or "rw".  User and group default to 0.  'seclabel' is the SELinux
+  security context for the file if it must be created.  It defaults to the
+  service security context, as specified by seclabel or computed based on the
+  service executable file security context.  For native executables see
+  libcutils android_get_control_file().
 
 user <username>
-  Change to username before exec'ing this service.
+  Change to 'username' before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
   As of Android M, processes should use this option even if they
-  require linux capabilities.  Previously, to acquire linux
+  require Linux capabilities.  Previously, to acquire Linux
   capabilities, a process would need to run as root, request the
   capabilities, then drop to its desired uid.  There is a new
   mechanism through fs_config that allows device manufacturers to add
-  linux capabilities to specific binaries on a file system that should
+  Linux capabilities to specific binaries on a file system that should
   be used instead. This mechanism is described on
   http://source.android.com/devices/tech/config/filesystem.html.  When
   using this new mechanism, processes can use the user option to
   select their desired uid without ever running as root.
+  As of Android O, processes can also request capabilities directly in their .rc
+  files. See the "capabilities" option below.
 
 group <groupname> [ <groupname> ]*
-  Change to groupname before exec'ing this service.  Additional
+  Change to 'groupname' before exec'ing this service.  Additional
   groupnames beyond the (required) first one are used to set the
   supplemental groups of the process (via setgroups()).
   Currently defaults to root.  (??? probably should default to nobody)
 
+capabilities <capability> [ <capability> ]*
+  Set capabilities when exec'ing this service. 'capability' should be a Linux
+  capability without the "CAP_" prefix, like "NET_ADMIN" or "SETPCAP". See
+  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+  capabilities.
+
 seclabel <seclabel>
   Change to 'seclabel' before exec'ing this service.
   Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
@@ -427,8 +443,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
@@ -524,10 +548,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 1caf7c6..1f53a1b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,8 @@
 #include "service.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
+#include <linux/securebits.h>
 #include <sched.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
@@ -31,10 +33,10 @@
 #include <selinux/selinux.h>
 
 #include <android-base/file.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
 #include <system/thread_defs.h>
 
 #include <processgroup/processgroup.h>
@@ -46,12 +48,10 @@
 #include "property_service.h"
 #include "util.h"
 
+using android::base::ParseInt;
 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;
@@ -142,14 +142,6 @@
     strs->push_back(nullptr);
 }
 
-SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& socketcon)
-    : name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
-}
-
 ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
 }
 
@@ -160,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");
@@ -169,14 +161,16 @@
 
 Service::Service(const std::string& name, const std::string& classname,
                  unsigned flags, uid_t uid, gid_t gid,
-                 const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+                 const std::vector<gid_t>& supp_gids,
+                 const CapSet& capabilities, unsigned namespace_flags,
                  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),
-      supp_gids_(supp_gids), namespace_flags_(namespace_flags),
-      seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), oom_score_adjust_(-1000), args_(args) {
+      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),
+      oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -194,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) {
@@ -208,21 +208,14 @@
     }
 }
 
-void Service::CreateSockets(const std::string& context) {
-    for (const auto& si : sockets_) {
-        int socket_type = ((si.type == "stream" ? SOCK_STREAM :
-                            (si.type == "dgram" ? SOCK_DGRAM :
-                             SOCK_SEQPACKET)));
-        const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str();
-
-        int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon);
-        if (s >= 0) {
-            PublishSocket(si.name, s);
+void Service::SetProcessAttributes() {
+    // Keep capabilites on uid change.
+    if (capabilities_.any() && uid_) {
+        if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED) != 0) {
+            PLOG(FATAL) << "prtcl(PR_SET_KEEPCAPS) failed for " << name_;
         }
     }
-}
 
-void Service::SetProcessAttributes() {
     // TODO: work out why this fails for `console` then upgrade to FATAL.
     if (setpgid(0, getpid()) == -1) PLOG(ERROR) << "setpgid failed for " << name_;
 
@@ -231,10 +224,8 @@
             PLOG(FATAL) << "setgid failed for " << name_;
         }
     }
-    if (!supp_gids_.empty()) {
-        if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
-            PLOG(FATAL) << "setgroups failed for " << name_;
-        }
+    if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+        PLOG(FATAL) << "setgroups failed for " << name_;
     }
     if (uid_) {
         if (setuid(uid_) != 0) {
@@ -251,6 +242,11 @@
             PLOG(FATAL) << "setpriority failed for " << name_;
         }
     }
+    if (capabilities_.any()) {
+        if (!SetCapsForExec(capabilities_)) {
+            LOG(FATAL) << "cannot set capabilities for " << name_;
+        }
+    }
 }
 
 bool Service::Reap() {
@@ -258,11 +254,9 @@
         KillProcessGroup(SIGKILL);
     }
 
-    // Remove any sockets we may have created.
-    for (const auto& si : sockets_) {
-        std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
-        unlink(tmp.c_str());
-    }
+    // Remove any descriptor resources we may have created.
+    std::for_each(descriptors_.begin(), descriptors_.end(),
+                  std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
 
     if (flags_ & SVC_EXEC) {
         LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
@@ -284,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;
         }
     }
 
@@ -315,9 +308,23 @@
     LOG(INFO) << "service " << name_;
     LOG(INFO) << "  class '" << classname_ << "'";
     LOG(INFO) << "  exec "<< android::base::Join(args_, " ");
-    for (const auto& si : sockets_) {
-        LOG(INFO) << "  socket " << si.name << " " << si.type << " " << std::oct << si.perm;
+    std::for_each(descriptors_.begin(), descriptors_.end(),
+                  [] (const auto& info) { LOG(INFO) << *info; });
+}
+
+bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
+    capabilities_ = 0;
+
+    for (size_t i = 1; i < args.size(); i++) {
+        const std::string& arg = args[i];
+        int cap = LookupCap(arg);
+        if (cap == -1) {
+            *err = StringPrintf("invalid capability '%s'", arg.c_str());
+            return false;
+        }
+        capabilities_[cap] = true;
     }
+    return true;
 }
 
 bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
@@ -351,22 +358,19 @@
 }
 
 bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
-    priority_ = std::stoi(args[1]);
-
-    if (priority_ < ANDROID_PRIORITY_HIGHEST || priority_ > ANDROID_PRIORITY_LOWEST) {
-        priority_ = 0;
+    priority_ = 0;
+    if (!ParseInt(args[1], &priority_,
+                  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;
     }
-
     return true;
 }
 
 bool Service::ParseIoprio(const std::vector<std::string>& args, std::string* err) {
-    ioprio_pri_ = std::stoul(args[2], 0, 8);
-
-    if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
+    if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
         *err = "priority value must be range 0 - 7";
         return false;
     }
@@ -387,7 +391,12 @@
 
 bool Service::ParseKeycodes(const std::vector<std::string>& args, std::string* err) {
     for (std::size_t i = 1; i < args.size(); i++) {
-        keycodes_.emplace_back(std::stoi(args[i]));
+        int code;
+        if (ParseInt(args[i], &code)) {
+            keycodes_.emplace_back(code);
+        } else {
+            LOG(WARNING) << "ignoring invalid keycode: " << args[i];
+        }
     }
     return true;
 }
@@ -420,17 +429,13 @@
 }
 
 bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
-    oom_score_adjust_ = std::stol(args[1], 0, 10);
-
-    if (oom_score_adjust_ < -1000 || oom_score_adjust_ > 1000) {
+    if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) {
         *err = "oom_score_adjust value must be in range -1000 - +1000";
         return false;
     }
-
     return true;
 }
 
-
 bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
     seclabel_ = args[1];
     return true;
@@ -441,20 +446,48 @@
     return true;
 }
 
-/* name type perm [ uid gid context ] */
+template <typename T>
+bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
+    int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
+    uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
+    gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+    std::string context = args.size() > 6 ? args[6] : "";
+
+    auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
+
+    auto old =
+        std::find_if(descriptors_.begin(), descriptors_.end(),
+                     [&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
+
+    if (old != descriptors_.end()) {
+        *err = "duplicate descriptor " + args[1] + " " + args[2];
+        return false;
+    }
+
+    descriptors_.emplace_back(std::move(descriptor));
+    return true;
+}
+
+// name type perm [ uid gid context ]
 bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
     if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
         *err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
         return false;
     }
+    return AddDescriptor<SocketInfo>(args, err);
+}
 
-    int perm = std::stoul(args[3], 0, 8);
-    uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
-    gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
-    std::string socketcon = args.size() > 6 ? args[6] : "";
-
-    sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
-    return true;
+// name type perm [ uid gid context ]
+bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
+    if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
+        *err = "file type must be 'r', 'w' or 'rw'";
+        return false;
+    }
+    if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+        *err = "file name must not be relative";
+        return false;
+    }
+    return AddDescriptor<FileInfo>(args, err);
 }
 
 bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
@@ -478,6 +511,8 @@
 Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
     static const Map option_parsers = {
+        {"capabilities",
+                        {1,     kMax, &Service::ParseCapabilities}},
         {"class",       {1,     1,    &Service::ParseClass}},
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
@@ -494,6 +529,7 @@
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
+        {"file",        {2,     6,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
@@ -520,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
@@ -561,7 +596,7 @@
         }
     }
 
-    LOG(VERBOSE) << "starting service '" << name_ << "'...";
+    LOG(INFO) << "starting service '" << name_ << "'...";
 
     pid_t pid = -1;
     if (namespace_flags_) {
@@ -583,7 +618,8 @@
             add_environment(ei.name.c_str(), ei.value.c_str());
         }
 
-        CreateSockets(scon);
+        std::for_each(descriptors_.begin(), descriptors_.end(),
+                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
 
         std::string pid_str = StringPrintf("%d", getpid());
         for (const auto& file : writepid_files_) {
@@ -633,7 +669,7 @@
         }
     }
 
-    time_started_ = gettime();
+    time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
 
@@ -697,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;
     }
 }
 
@@ -757,15 +794,6 @@
     close(fd);
 }
 
-void Service::PublishSocket(const std::string& name, int fd) const {
-    std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
-    std::string val = StringPrintf("%d", fd);
-    add_environment(key.c_str(), val.c_str());
-
-    /* make sure we don't close-on-exec */
-    fcntl(fd, F_SETFD, 0);
-}
-
 int ServiceManager::exec_count_ = 0;
 
 ServiceManager::ServiceManager() {
@@ -809,6 +837,7 @@
     exec_count_++;
     std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
     unsigned flags = SVC_EXEC | SVC_ONESHOT;
+    CapSet no_capabilities;
     unsigned namespace_flags = 0;
 
     std::string seclabel = "";
@@ -829,9 +858,9 @@
         }
     }
 
-    std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
-                                               supp_gids, namespace_flags,
-                                               seclabel, str_args));
+    std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid, supp_gids,
+                                               no_capabilities, namespace_flags, seclabel,
+                                               str_args));
     if (!svc_p) {
         LOG(ERROR) << "Couldn't allocate service for exec of '" << str_args[0] << "'";
         return nullptr;
@@ -939,13 +968,13 @@
     }
 
     if (WIFEXITED(status)) {
-        LOG(VERBOSE) << name << " exited with status " << WEXITSTATUS(status);
+        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status);
     } else if (WIFSIGNALED(status)) {
-        LOG(VERBOSE) << name << " killed by signal " << WTERMSIG(status);
+        LOG(INFO) << name << " killed by signal " << WTERMSIG(status);
     } else if (WIFSTOPPED(status)) {
-        LOG(VERBOSE) << name << " stopped by signal " << WSTOPSIG(status);
+        LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status);
     } else {
-        LOG(VERBOSE) << name << " state changed";
+        LOG(INFO) << name << " state changed";
     }
 
     if (!svc) {
@@ -996,13 +1025,5 @@
 }
 
 bool ServiceParser::IsValidName(const std::string& name) const {
-    if (name.size() > 16) {
-        return false;
-    }
-    for (const auto& c : name) {
-        if (!isalnum(c) && (c != '_') && (c != '-')) {
-            return false;
-        }
-    }
-    return true;
+    return is_legal_property_name("init.svc." + name);
 }
diff --git a/init/service.h b/init/service.h
index 4a3412c..013e65f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,8 +26,11 @@
 #include <vector>
 
 #include "action.h"
+#include "capabilities.h"
+#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
@@ -47,18 +50,6 @@
 class Action;
 class ServiceManager;
 
-struct SocketInfo {
-    SocketInfo();
-    SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& socketcon);
-    std::string name;
-    std::string type;
-    uid_t uid;
-    gid_t gid;
-    int perm;
-    std::string socketcon;
-};
-
 struct ServiceEnvironmentInfo {
     ServiceEnvironmentInfo();
     ServiceEnvironmentInfo(const std::string& name, const std::string& value);
@@ -73,8 +64,9 @@
 
     Service(const std::string& name, const std::string& classname,
             unsigned flags, uid_t uid, gid_t gid,
-            const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
-            const std::string& seclabel, const std::vector<std::string>& args);
+            const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+            unsigned namespace_flags, const std::string& seclabel,
+            const std::vector<std::string>& args);
 
     bool ParseLine(const std::vector<std::string>& args, std::string* err);
     bool Start();
@@ -84,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;
 
@@ -111,11 +103,10 @@
     void StopOrReset(int how);
     void ZapStdio() const;
     void OpenConsole() const;
-    void PublishSocket(const std::string& name, int fd) const;
     void KillProcessGroup(int signal);
-    void CreateSockets(const std::string& scon);
     void SetProcessAttributes();
 
+    bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
     bool ParseClass(const std::vector<std::string>& args, std::string* err);
     bool ParseConsole(const std::vector<std::string>& args, std::string* err);
     bool ParseCritical(const std::vector<std::string>& args, std::string* err);
@@ -131,27 +122,32 @@
     bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
     bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
     bool ParseSocket(const std::vector<std::string>& args, std::string* err);
+    bool ParseFile(const std::vector<std::string>& args, std::string* err);
     bool ParseUser(const std::vector<std::string>& args, std::string* err);
     bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
 
+    template <typename T>
+    bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
+
     std::string name_;
     std::string classname_;
     std::string console_;
 
     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_;
     std::vector<gid_t> supp_gids_;
+    CapSet capabilities_;
     unsigned namespace_flags_;
 
     std::string seclabel_;
 
-    std::vector<SocketInfo> sockets_;
+    std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
     std::vector<ServiceEnvironmentInfo> envvars_;
 
     Action onrestart_;  // Commands to execute on restart.
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 660a66f..5205ea0 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,32 +14,35 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <pwd.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
 #include <time.h>
-#include <ftw.h>
-#include <pwd.h>
+#include <unistd.h>
 
-#include <selinux/label.h>
 #include <selinux/android.h>
+#include <selinux/label.h>
 
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/socket.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>
-#include <android-base/stringprintf.h>
 
 #include "init.h"
 #include "log.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,15 +151,76 @@
               << ", user " << uid
               << ", group " << gid;
 
-    return fd;
+    return fd.release();
 
 out_unlink:
     unlink(addr.sun_path);
-out_close:
-    close(fd);
     return -1;
 }
 
+/*
+ * create_file - opens and creates a file as dictated in init.rc.
+ * This file is inherited by the daemon. We communicate the file
+ * descriptor's value via the environment variable ANDROID_FILE_<basename>
+ */
+int create_file(const char *path, int flags, mode_t perm, uid_t uid,
+                  gid_t gid, const char *filecon)
+{
+    char *secontext = NULL;
+
+    if (filecon) {
+        if (setsockcreatecon(filecon) == -1) {
+            PLOG(ERROR) << "setsockcreatecon(\"" << filecon << "\") failed";
+            return -1;
+        }
+    } else if (sehandle) {
+        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;
+            }
+        }
+    }
+
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+    int savederrno = errno;
+
+    if (filecon) {
+        setsockcreatecon(NULL);
+        lsetfilecon(path, filecon);
+    } else {
+        setfscreatecon(NULL);
+        freecon(secontext);
+    }
+
+    if (fd < 0) {
+        errno = savederrno;
+        PLOG(ERROR) << "Failed to open/create file '" << path << "'";
+        return -1;
+    }
+
+    if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
+
+    if (lchown(path, uid, gid)) {
+        PLOG(ERROR) << "Failed to lchown file '" << path << "'";
+        return -1;
+    }
+    if (perm != static_cast<mode_t>(-1)) {
+        if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
+            PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
+            return -1;
+        }
+    }
+
+    LOG(INFO) << "Created file '" << path << "'"
+              << ", mode " << std::oct << perm << std::dec
+              << ", user " << uid
+              << ", group " << gid;
+
+    return fd.release();
+}
+
 bool read_file(const char* path, std::string* content) {
     content->clear();
 
@@ -203,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)
@@ -270,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,
@@ -318,20 +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);
-}
-
-int restorecon_recursive_skipce(const char* pathname)
-{
-    return selinux_android_restorecon(pathname,
-            SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIPCE);
+    return selinux_android_restorecon(pathname, flags);
 }
 
 /*
diff --git a/init/util.h b/init/util.h
index b83b9a0..d56da39 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,44 +20,55 @@
 #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,
+                uid_t uid, gid_t gid, const char *filecon);
 
 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_recursive_skipce(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 228954b..e9f164d 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -16,8 +16,19 @@
 
 #include "util.h"
 
+#include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.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>
 
 TEST(util, read_file_ENOENT) {
   std::string s("hello");
@@ -41,3 +52,54 @@
   EXPECT_EQ(UINT_MAX, decode_uid("toot"));
   EXPECT_EQ(123U, decode_uid("123"));
 }
+
+struct selabel_handle *sehandle;
+
+TEST(util, create_file) {
+  if (!sehandle) sehandle = selinux_android_file_context_handle();
+
+  TemporaryFile tf;
+  close(tf.fd);
+  EXPECT_GE(unlink(tf.path), 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);
+
+  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(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(tf.fd, hello, len), len);
+  char buffer[sizeof(hello) + 1];
+  memset(buffer, 0, sizeof(buffer));
+  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(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(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(tf.path), 0);
+}
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
new file mode 100644
index 0000000..f729faf
--- /dev/null
+++ b/libappfuse/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2016 The Android Open Source Project
+
+cc_defaults {
+    name: "libappfuse_defaults",
+    local_include_dirs: ["include"],
+    shared_libs: ["libbase"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    clang: true
+}
+
+cc_library_shared {
+    name: "libappfuse",
+    defaults: ["libappfuse_defaults"],
+    export_include_dirs: ["include"],
+    srcs: [
+        "FuseAppLoop.cc",
+        "FuseBuffer.cc",
+        "FuseBridgeLoop.cc",
+    ]
+}
+
+cc_test {
+    name: "libappfuse_test",
+    defaults: ["libappfuse_defaults"],
+    shared_libs: ["libappfuse"],
+    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
new file mode 100644
index 0000000..2386bf8
--- /dev/null
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -0,0 +1,101 @@
+/*
+ * 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/FuseBridgeLoop.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+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)) {
+      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:
+      case FUSE_GETATTR:
+      case FUSE_OPEN:
+      case FUSE_READ:
+      case FUSE_WRITE:
+      case FUSE_RELEASE:
+      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)) {
+          LOG(ERROR) << "Failed to read a response from the proxy.";
+          return false;
+        }
+        break;
+
+      case FUSE_INIT:
+        buffer.HandleInit();
+        break;
+
+      default:
+        buffer.HandleNotImpl();
+        break;
+    }
+
+    if (!buffer.response.Write(dev_fd)) {
+      LOG(ERROR) << "Failed to write a response to the device.";
+      return false;
+    }
+
+    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
new file mode 100644
index 0000000..3ade31c
--- /dev/null
+++ b/libappfuse/FuseBuffer.cc
@@ -0,0 +1,149 @@
+/*
+ * 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/FuseBuffer.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+namespace android {
+namespace fuse {
+
+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;
+    return false;
+  }
+}
+
+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. result=" << result << " header.len="
+        << header.len;
+    return false;
+  }
+}
+
+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>
+bool FuseMessage<T>::Write(int fd) const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (!CheckHeaderLength()) {
+    return false;
+  }
+  const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
+  return CheckResult(result, "write");
+}
+
+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) {
+  CHECK_LE(error, 0) << "error should be zero or negative.";
+  header.len = sizeof(fuse_out_header) + data_length;
+  header.error = error;
+  header.unique = unique;
+}
+
+void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) {
+  memset(this, 0, sizeof(fuse_out_header) + data_length);
+  ResetHeader(data_length, error, unique);
+}
+
+void FuseBuffer::HandleInit() {
+  const fuse_init_in* const in = &request.init_in;
+
+  // Before writing |out|, we need to copy data from |in|.
+  const uint64_t unique = request.header.unique;
+  const uint32_t minor = in->minor;
+  const uint32_t max_readahead = in->max_readahead;
+
+  // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+  // defined (fuse version 7.6). The structure is the same from 7.6 through
+  // 7.22. Beginning with 7.23, the structure increased in size and added
+  // new parameters.
+  if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+    LOG(ERROR) << "Fuse kernel version mismatch: Kernel version " << in->major
+        << "." << in->minor << " Expected at least " << FUSE_KERNEL_VERSION
+        << ".6";
+    response.Reset(0, -EPERM, unique);
+    return;
+  }
+
+  // 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.
+  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;
+  out->minor = std::min(minor, 15u);
+  out->max_readahead = max_readahead;
+  out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+  out->max_background = 32;
+  out->congestion_threshold = 32;
+  out->max_write = kFuseMaxWrite;
+}
+
+void FuseBuffer::HandleNotImpl() {
+  LOG(VERBOSE) << "NOTIMPL op=" << request.header.opcode << " uniq="
+      << request.header.unique << " nid=" << request.header.nodeid;
+  const uint64_t unique = request.header.unique;
+  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
new file mode 100644
index 0000000..1f71cf2
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -0,0 +1,37 @@
+/*
+ * 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_FUSEBRIDGELOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseBridgeLoopCallback {
+ public:
+  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
new file mode 100644
index 0000000..e7f620c
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -0,0 +1,98 @@
+/*
+ * 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_FUSEBUFFER_H_
+#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+
+#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.
+constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxRead = 128 * 1024;
+constexpr int32_t kFuseSuccess = 0;
+
+template<typename T>
+class FuseMessage {
+ public:
+  bool Read(int fd);
+  bool Write(int fd) const;
+ private:
+  bool CheckHeaderLength() const;
+  bool CheckResult(int result, const char* operation_name) const;
+};
+
+// 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);
+};
+
+// 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);
+};
+
+// To reduce memory usage, FuseBuffer shares the memory region for request and
+// response.
+union FuseBuffer final {
+  FuseRequest request;
+  FuseResponse response;
+
+  void HandleInit();
+  void HandleNotImpl();
+};
+
+}  // 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
new file mode 100644
index 0000000..e74d9e7
--- /dev/null
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -0,0 +1,216 @@
+/*
+ * 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/FuseBridgeLoop.h"
+
+#include <sys/socket.h>
+
+#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 FuseBridgeLoopCallback {
+ public:
+  bool mounted;
+  Callback() : mounted(false) {}
+  void OnMount() override {
+    mounted = true;
+  }
+};
+
+class FuseBridgeLoopTest : public ::testing::Test {
+ protected:
+  base::unique_fd dev_sockets_[2];
+  base::unique_fd proxy_sockets_[2];
+  Callback callback_;
+  std::thread thread_;
+
+  FuseRequest request_;
+  FuseResponse response_;
+
+  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] {
+      StartFuseBridgeLoop(
+          dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
+    });
+  }
+
+  void CheckNotImpl(uint32_t opcode) {
+    SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = opcode;
+    request_.header.len = sizeof(fuse_in_header);
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+    EXPECT_EQ(-ENOSYS, response_.header.error);
+  }
+
+  void CheckProxy(uint32_t opcode) {
+    SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = opcode;
+    request_.header.unique = opcode; // Use opcode as unique.
+    request_.header.len = sizeof(fuse_in_header);
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
+    EXPECT_EQ(opcode, request_.header.opcode);
+    EXPECT_EQ(opcode, request_.header.unique);
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    response_.header.len = sizeof(fuse_out_header);
+    response_.header.unique = opcode;  // Use opcode as unique.
+    response_.header.error = kFuseSuccess;
+    ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+    EXPECT_EQ(opcode, response_.header.unique);
+    EXPECT_EQ(kFuseSuccess, response_.header.error);
+  }
+
+  void SendInitRequest(uint64_t unique) {
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = FUSE_INIT;
+    request_.header.unique = unique;
+    request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
+    request_.init_in.major = FUSE_KERNEL_VERSION;
+    request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+  }
+
+  void Close() {
+    dev_sockets_[0].reset();
+    dev_sockets_[1].reset();
+    proxy_sockets_[0].reset();
+    proxy_sockets_[1].reset();
+    if (thread_.joinable()) {
+      thread_.join();
+    }
+  }
+
+  void TearDown() override {
+    Close();
+  }
+};
+
+} //  namespace
+
+TEST_F(FuseBridgeLoopTest, FuseInit) {
+  SendInitRequest(1u);
+
+  memset(&response_, 0, sizeof(FuseResponse));
+  ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  // Unmount.
+  Close();
+  EXPECT_TRUE(callback_.mounted);
+}
+
+TEST_F(FuseBridgeLoopTest, FuseForget) {
+  memset(&request_, 0, sizeof(FuseRequest));
+  request_.header.opcode = FUSE_FORGET;
+  request_.header.unique = 1u;
+  request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
+  ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+  SendInitRequest(2u);
+
+  memset(&response_, 0, sizeof(FuseResponse));
+  ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+  EXPECT_EQ(2u, response_.header.unique) <<
+      "The loop must not respond to FUSE_FORGET";
+}
+
+TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
+  CheckNotImpl(FUSE_SETATTR);
+  CheckNotImpl(FUSE_READLINK);
+  CheckNotImpl(FUSE_SYMLINK);
+  CheckNotImpl(FUSE_MKNOD);
+  CheckNotImpl(FUSE_MKDIR);
+  CheckNotImpl(FUSE_UNLINK);
+  CheckNotImpl(FUSE_RMDIR);
+  CheckNotImpl(FUSE_RENAME);
+  CheckNotImpl(FUSE_LINK);
+  CheckNotImpl(FUSE_STATFS);
+  CheckNotImpl(FUSE_SETXATTR);
+  CheckNotImpl(FUSE_GETXATTR);
+  CheckNotImpl(FUSE_LISTXATTR);
+  CheckNotImpl(FUSE_REMOVEXATTR);
+  CheckNotImpl(FUSE_FLUSH);
+  CheckNotImpl(FUSE_OPENDIR);
+  CheckNotImpl(FUSE_READDIR);
+  CheckNotImpl(FUSE_RELEASEDIR);
+  CheckNotImpl(FUSE_FSYNCDIR);
+  CheckNotImpl(FUSE_GETLK);
+  CheckNotImpl(FUSE_SETLK);
+  CheckNotImpl(FUSE_SETLKW);
+  CheckNotImpl(FUSE_ACCESS);
+  CheckNotImpl(FUSE_CREATE);
+  CheckNotImpl(FUSE_INTERRUPT);
+  CheckNotImpl(FUSE_BMAP);
+  CheckNotImpl(FUSE_DESTROY);
+  CheckNotImpl(FUSE_IOCTL);
+  CheckNotImpl(FUSE_POLL);
+  CheckNotImpl(FUSE_NOTIFY_REPLY);
+  CheckNotImpl(FUSE_BATCH_FORGET);
+  CheckNotImpl(FUSE_FALLOCATE);
+  CheckNotImpl(FUSE_READDIRPLUS);
+  CheckNotImpl(FUSE_RENAME2);
+  CheckNotImpl(FUSE_LSEEK);
+}
+
+TEST_F(FuseBridgeLoopTest, Proxy) {
+  CheckProxy(FUSE_LOOKUP);
+  CheckProxy(FUSE_GETATTR);
+  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);
+
+  // Ensure the loop exits.
+  Close();
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
new file mode 100644
index 0000000..c822135
--- /dev/null
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -0,0 +1,189 @@
+/*
+ * 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/FuseBuffer.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace fuse {
+
+constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
+
+void OpenTempFile(android::base::unique_fd* fd) {
+  fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+  ASSERT_NE(-1, *fd) << strerror(errno);
+  unlink(kTempFile);
+  ASSERT_NE(-1, *fd) << strerror(errno);
+}
+
+void TestReadInvalidLength(size_t headerSize, size_t write_size) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  char buffer[std::max(headerSize, sizeof(FuseRequest))];
+  FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+  packet->header.len = headerSize;
+  ASSERT_NE(-1, write(fd, packet, write_size)) << strerror(errno);
+
+  lseek(fd, 0, SEEK_SET);
+  EXPECT_FALSE(packet->Read(fd));
+}
+
+void TestWriteInvalidLength(size_t size) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  char buffer[std::max(size, sizeof(FuseRequest))];
+  FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+  packet->header.len = size;
+  EXPECT_FALSE(packet->Write(fd));
+}
+
+// Use FuseRequest as a template instance of FuseMessage.
+
+TEST(FuseMessageTest, ReadAndWrite) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  FuseRequest request;
+  request.header.len = sizeof(FuseRequest);
+  request.header.opcode = 1;
+  request.header.unique = 2;
+  request.header.nodeid = 3;
+  request.header.uid = 4;
+  request.header.gid = 5;
+  request.header.pid = 6;
+  strcpy(request.lookup_name, "test");
+
+  ASSERT_TRUE(request.Write(fd));
+
+  memset(&request, 0, sizeof(FuseRequest));
+  lseek(fd, 0, SEEK_SET);
+
+  ASSERT_TRUE(request.Read(fd));
+  EXPECT_EQ(sizeof(FuseRequest), request.header.len);
+  EXPECT_EQ(1u, request.header.opcode);
+  EXPECT_EQ(2u, request.header.unique);
+  EXPECT_EQ(3u, request.header.nodeid);
+  EXPECT_EQ(4u, request.header.uid);
+  EXPECT_EQ(5u, request.header.gid);
+  EXPECT_EQ(6u, request.header.pid);
+  EXPECT_STREQ("test", request.lookup_name);
+}
+
+TEST(FuseMessageTest, Read_InconsistentLength) {
+  TestReadInvalidLength(sizeof(fuse_in_header), sizeof(fuse_in_header) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooLong) {
+  TestReadInvalidLength(sizeof(FuseRequest) + 1, sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooShort) {
+  TestReadInvalidLength(sizeof(fuse_in_header) - 1, sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseMessageTest, Write_TooLong) {
+  TestWriteInvalidLength(sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Write_TooShort) {
+  TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseResponseTest, Reset) {
+  FuseResponse response;
+  // Write 1 to the first ten bytes.
+  memset(response.read_data, 'a', 10);
+
+  response.Reset(0, -1, 2);
+  EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+  EXPECT_EQ(-1, response.header.error);
+  EXPECT_EQ(2u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+
+  response.Reset(5, -4, 3);
+  EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+  EXPECT_EQ(-4, response.header.error);
+  EXPECT_EQ(3u, response.header.unique);
+  EXPECT_EQ(0, response.read_data[0]);
+  EXPECT_EQ(0, response.read_data[1]);
+  EXPECT_EQ(0, response.read_data[2]);
+  EXPECT_EQ(0, response.read_data[3]);
+  EXPECT_EQ(0, response.read_data[4]);
+  EXPECT_EQ('a', response.read_data[5]);
+}
+
+TEST(FuseResponseTest, ResetHeader) {
+  FuseResponse response;
+  // Write 1 to the first ten bytes.
+  memset(response.read_data, 'a', 10);
+
+  response.ResetHeader(0, -1, 2);
+  EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+  EXPECT_EQ(-1, response.header.error);
+  EXPECT_EQ(2u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+
+  response.ResetHeader(5, -4, 3);
+  EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+  EXPECT_EQ(-4, response.header.error);
+  EXPECT_EQ(3u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+}
+
+TEST(FuseBufferTest, HandleInit) {
+  FuseBuffer buffer;
+  memset(&buffer, 0, sizeof(FuseBuffer));
+
+  buffer.request.header.opcode = FUSE_INIT;
+  buffer.request.init_in.major = FUSE_KERNEL_VERSION;
+  buffer.request.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+
+  buffer.HandleInit();
+
+  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),
+            buffer.response.init_out.major);
+  EXPECT_EQ(15u, buffer.response.init_out.minor);
+  EXPECT_EQ(static_cast<unsigned int>(FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES),
+      buffer.response.init_out.flags);
+  EXPECT_EQ(kFuseMaxWrite, buffer.response.init_out.max_write);
+}
+
+TEST(FuseBufferTest, HandleNotImpl) {
+  FuseBuffer buffer;
+  memset(&buffer, 0, sizeof(FuseBuffer));
+
+  buffer.HandleNotImpl();
+
+  ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
+  EXPECT_EQ(-ENOSYS, buffer.response.header.error);
+}
+
+} // namespace fuse
+} // namespace android
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 93d997b..5c72234 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -21,8 +21,6 @@
         "-Wall",
         "-Werror",
     ],
-    conlyflags: ["-std=gnu99"],
-    cppflags: ["-std=gnu++11"],
 
     clang_cflags: ["-Wno-inline-asm"],
 
@@ -94,6 +92,7 @@
             ],
 
             static_libs: ["libcutils"],
+            host_ldlibs: ["-lrt"],
         },
         android: {
             srcs: libbacktrace_sources,
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 56a3970..bb17325 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -20,12 +20,6 @@
 	-Wall \
 	-Werror \
 
-libbacktrace_common_conlyflags := \
-	-std=gnu99 \
-
-libbacktrace_common_cppflags := \
-	-std=gnu++11 \
-
 libbacktrace_common_c_includes := \
 	external/libunwind/include/tdep \
 
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 19ea1e3..4496375 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "backtrace-map"
+
 #include <ctype.h>
 #include <inttypes.h>
 #include <stdint.h>
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index c2b68bc..a05a6d8 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -719,7 +719,7 @@
   auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
   if (!binary_or_err) {
     BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
-              binary_or_err.getError().message().c_str());
+              llvm::toString(binary_or_err.takeError()).c_str());
     return nothing;
   }
   return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index ca7bd31..f2560e6 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -24,7 +24,6 @@
         "-Wall",
         "-Wextra",
         "-Werror",
-        "-std=c99",
     ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
diff --git a/libcrypto_utils/tests/Android.mk b/libcrypto_utils/tests/Android.mk
index bdaef71..ef3d0cf 100644
--- a/libcrypto_utils/tests/Android.mk
+++ b/libcrypto_utils/tests/Android.mk
@@ -19,6 +19,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcrypto_utils_test
 LOCAL_SRC_FILES := android_pubkey_test.cpp
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c++11
+LOCAL_CFLAGS := -Wall -Werror -Wextra
 LOCAL_SHARED_LIBRARIES := libcrypto_utils libcrypto
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8624d13..39f8aba 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,12 +18,12 @@
 // 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",
     "socket_local_client_unix.c",
     "socket_local_server_unix.c",
-    "socket_loopback_client_unix.c",
     "socket_loopback_server_unix.c",
     "socket_network_client_unix.c",
     "sockets_unix.cpp",
@@ -87,18 +87,8 @@
                 "uevent.c",
             ],
 
-            // TODO: remove liblog as whole static library, once we don't have prebuilt that requires
-            // liblog symbols present in libcutils.
-            whole_static_libs: [
-                "liblog",
-            ],
-
             static_libs: ["libdebuggerd_client"],
             export_static_lib_headers: ["libdebuggerd_client"],
-
-            cflags: [
-                "-std=gnu90",
-            ],
         },
 
         android_arm: {
diff --git a/libcutils/android_get_control_env.h b/libcutils/android_get_control_env.h
new file mode 100644
index 0000000..638c831
--- /dev/null
+++ b/libcutils/android_get_control_env.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
+
+/* To declare library function hidden and internal */
+#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
diff --git a/libcutils/android_get_control_file.cpp b/libcutils/android_get_control_file.cpp
new file mode 100644
index 0000000..780d9f1
--- /dev/null
+++ b/libcutils/android_get_control_file.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/android_get_control_file.h>
+
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
+
+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, "%s%s", prefix, 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;
+
+    // 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) // Alternate lowest overhead
+    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
+#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/%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);
+        return -1;
+    }
+    ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
+    free(proc);
+    int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
+    free(buf);
+    if (ret < 0) return -1;
+    if (cmp != 0) return -1;
+    // It is what we think it is
+#endif
+
+    return fd;
+}
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 86fc880..6c07bed 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dlmalloc-stubs"
+
 #include "android/log.h"
 
 #define UNUSED __attribute__((__unused__))
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 1622ed9..c49233e 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 4e62d74..99f97d1 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -140,18 +140,39 @@
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
 
     /* the following files have enhanced capabilities and ARE included in user builds. */
-    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
-    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+    { 00550, AID_LOGD,      AID_LOGD,      CAP_MASK_LONG(CAP_SYSLOG) |
+                                           CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
+                                           CAP_MASK_LONG(CAP_SETGID),
+                                              "system/bin/logd" },
+    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID),
+                                              "system/bin/run-as" },
+    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
+                                              "system/bin/inputflinger" },
 
     /* Support FIFO scheduling mode in SurfaceFlinger. */
-    { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+    { 00755, AID_SYSTEM,    AID_GRAPHICS,  CAP_MASK_LONG(CAP_SYS_NICE),
+                                              "system/bin/surfaceflinger" },
 
     /* Support hostapd administering a network interface. */
-    { 00755, AID_WIFI,      AID_WIFI,     CAP_MASK_LONG(CAP_NET_ADMIN) |
-                                          CAP_MASK_LONG(CAP_NET_RAW),    "system/bin/hostapd" },
+    { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
+                                           CAP_MASK_LONG(CAP_NET_RAW),
+                                              "system/bin/hostapd" },
 
     /* Support wifi_hal_legacy administering a network interface. */
-    { 00755, AID_WIFI,      AID_WIFI,     CAP_MASK_LONG(CAP_NET_ADMIN) | CAP_MASK_LONG(CAP_NET_RAW),    "system/bin/hw/wifi_hal_legacy" },
+    { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
+                                           CAP_MASK_LONG(CAP_NET_RAW),
+                                              "system/bin/hw/android.hardware.wifi@1.0-service" },
+
+    /* A non-privileged zygote that spawns isolated processes for web rendering. */
+    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID) |
+                                           CAP_MASK_LONG(CAP_SETPCAP),
+                                              "system/bin/webview_zygote32" },
+    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID) |
+                                           CAP_MASK_LONG(CAP_SETPCAP),
+                                              "system/bin/webview_zygote64" },
 
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 061af1b..4bad28a 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 
 static int klog_level = KLOG_DEFAULT_LEVEL;
@@ -37,7 +38,11 @@
 }
 
 static int __open_klog(void) {
-    return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+    static const char kmsg_device[] = "/dev/kmsg";
+
+    int ret = android_get_control_file(kmsg_device);
+    if (ret >= 0) return ret;
+    return TEMP_FAILURE_RETRY(open(kmsg_device, O_WRONLY | O_CLOEXEC));
 }
 
 #define LOG_BUF_MAX 512
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 7f3479d..9f4840a 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -28,6 +28,20 @@
 static const int kMaxNativeFds = 1024;
 static const int kMaxNativeInts = 1024;
 
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts)
+{
+    if ((uintptr_t) storage % alignof(native_handle_t)) {
+        return NULL;
+    }
+
+    native_handle_t* handle = (native_handle_t*) storage;
+    handle->version = sizeof(native_handle_t);
+    handle->numFds = numFds;
+    handle->numInts = numInts;
+
+    return handle;
+}
+
 native_handle_t* native_handle_create(int numFds, int numInts)
 {
     if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
@@ -44,6 +58,27 @@
     return h;
 }
 
+native_handle_t* native_handle_clone(const native_handle_t* handle)
+{
+    native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
+    int i;
+
+    for (i = 0; i < handle->numFds; i++) {
+        clone->data[i] = dup(handle->data[i]);
+        if (clone->data[i] < 0) {
+            clone->numFds = i;
+            native_handle_close(clone);
+            native_handle_delete(clone);
+            return NULL;
+        }
+    }
+
+    memcpy(&clone->data[handle->numFds], &handle->data[handle->numFds],
+            sizeof(int) * handle->numInts);
+
+    return clone;
+}
+
 int native_handle_delete(native_handle_t* h)
 {
     if (h) {
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index d436b45..5c5f3a5 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <cutils/sched_policy.h>
 
 #define UNUSED __attribute__((__unused__))
diff --git a/libcutils/socket_loopback_client_unix.c b/libcutils/socket_loopback_client_unix.c
deleted file mode 100644
index e14cffb..0000000
--- a/libcutils/socket_loopback_client_unix.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-** Copyright 2006, 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 <errno.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#endif
-
-#include <cutils/sockets.h>
-
-/* Connect to port on the loopback IP interface. type is
- * SOCK_STREAM or SOCK_DGRAM. 
- * return is a file descriptor or -1 on error
- */
-int socket_loopback_client(int port, int type)
-{
-    struct sockaddr_in addr;
-    int s;
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        close(s);
-        return -1;
-    }
-
-    return s;
-
-}
-
diff --git a/libcutils/socket_loopback_server_unix.c b/libcutils/socket_loopback_server_unix.c
index b600e34..7b92fd6 100644
--- a/libcutils/socket_loopback_server_unix.c
+++ b/libcutils/socket_loopback_server_unix.c
@@ -31,24 +31,18 @@
 
 #include <cutils/sockets.h>
 
-/* open listen() port on loopback interface */
-int socket_loopback_server(int port, int type)
+static int _socket_loopback_server(int family, int type, struct sockaddr * addr, size_t size)
 {
-    struct sockaddr_in addr;
     int s, n;
 
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
+    s = socket(family, type, 0);
+    if(s < 0)
+        return -1;
 
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if(bind(s, addr, size) < 0) {
         close(s);
         return -1;
     }
@@ -60,10 +54,35 @@
 
         if (ret < 0) {
             close(s);
-            return -1; 
+            return -1;
         }
     }
 
     return s;
 }
 
+/* open listen() port on loopback IPv6 interface */
+int socket_loopback_server6(int port, int type)
+{
+    struct sockaddr_in6 addr;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(port);
+    addr.sin6_addr = in6addr_loopback;
+
+    return _socket_loopback_server(AF_INET6, type, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+    struct sockaddr_in addr;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    return _socket_loopback_server(AF_INET, type, (struct sockaddr *) &addr, sizeof(addr));
+}
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index bba63ac..23a447b 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -31,10 +31,6 @@
 
 #include <cutils/sockets.h>
 
-#if !defined(_WIN32)
-#include <netinet/in.h>
-#endif
-
 int socket_get_local_port(cutils_socket_t sock) {
     sockaddr_storage addr;
     socklen_t addr_size = sizeof(addr);
@@ -45,24 +41,3 @@
     }
     return -1;
 }
-
-int android_get_control_socket(const char* name) {
-    char key[64];
-    snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
-
-    const char* val = getenv(key);
-    if (!val) {
-        return -1;
-    }
-
-    errno = 0;
-    long ret = strtol(val, NULL, 10);
-    if (errno) {
-        return -1;
-    }
-    if (ret < 0 || ret > INT_MAX) {
-        return -1;
-    }
-
-    return static_cast<int>(ret);
-}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index e51a1c7..5a14a5c 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -14,11 +14,27 @@
  * limitations under the License.
  */
 
+#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>
@@ -76,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 06d0e28..72e2eac 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -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/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0f682a2..0441fb6 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,10 +18,12 @@
 // IPv6 capabilities. These tests assume that no UDP packets are lost, which
 // should be the case for loopback communication, but is not guaranteed.
 
-#include <cutils/sockets.h>
-
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #include <time.h>
 
+#include <cutils/sockets.h>
 #include <gtest/gtest.h>
 
 // Makes sure the passed sockets are valid, sends data between them, and closes
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index dcd9582..113f423 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -26,10 +26,10 @@
 #include <string.h>
 #include <sys/types.h>
 
-#include <android/log.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <cutils/trace.h>
+#include <private/android_logger.h>
 
 /**
  * Maximum size of a message that can be logged to the trace buffer.
@@ -86,16 +86,9 @@
 // Determine whether application-level tracing is enabled for this process.
 static bool atrace_is_app_tracing_enabled()
 {
-    bool sys_debuggable = false;
-    char value[PROPERTY_VALUE_MAX];
+    bool sys_debuggable = __android_log_is_debuggable();
     bool result = false;
 
-    // Check whether the system is debuggable.
-    property_get("ro.debuggable", value, "0");
-    if (value[0] == '1') {
-        sys_debuggable = true;
-    }
-
     if (sys_debuggable || atrace_is_debuggable) {
         // Check whether tracing is enabled for this process.
         FILE * file = fopen("/proc/self/cmdline", "re");
diff --git a/libion/ion.c b/libion/ion.c
index 424776a..2db8845 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -27,13 +27,14 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <android/log.h>
 #include <ion/ion.h>
 
 int ion_open()
 {
-    int fd = open("/dev/ion", O_RDWR);
+    int fd = open("/dev/ion", O_RDONLY);
     if (fd < 0)
         ALOGE("open /dev/ion failed!\n");
     return fd;
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
index 0be52bf..eb3f7b6 100644
--- a/libion/tests/device_test.cpp
+++ b/libion/tests/device_test.cpp
@@ -46,7 +46,7 @@
 void Device::SetUp()
 {
     IonAllHeapsTest::SetUp();
-    m_deviceFd = open("/dev/ion-test", O_RDWR);
+    m_deviceFd = open("/dev/ion-test", O_RDONLY);
     ASSERT_GE(m_deviceFd, 0);
 }
 
diff --git a/liblog/Android.bp b/liblog/Android.bp
index c59dde9..16aa4fa 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -91,6 +91,22 @@
     compile_multilib: "both",
 }
 
+// system/core/android/log.h needs some work before it can be included in the
+// NDK. It defines a *lot* of macros that previously were usable names in NDK
+// sources that used android/log.h. As an example, the following file defines
+// LOG_TAG as a variable, but the variable name gets macro replaced if we use
+// the current android/log.h.
+// https://android.googlesource.com/platform/external/deqp/+/4adc1515f867b26c19c2f7498e9de93a230a234d/framework/platform/android/tcuTestLogParserJNI.cpp#41
+//
+// For now, we keep a copy of the old NDK android/log.h in legacy-ndk-includes.
+ndk_headers {
+    name: "liblog_headers",
+    from: "legacy-ndk-includes",
+    to: "android",
+    srcs: ["legacy-ndk-includes/log.h"],
+    license: "NOTICE",
+}
+
 ndk_library {
     name: "liblog.ndk",
     symbol_file: "liblog.map.txt",
diff --git a/liblog/README b/liblog/README
index eefa80f..610338c 100644
--- a/liblog/README
+++ b/liblog/README
@@ -1,12 +1,18 @@
-LIBLOG(3)               Android NDK Programming Manual               LIBLOG(3)
+LIBLOG(3)          Android Internal NDK Programming Manual           LIBLOG(3)
 
 
 
 NAME
-       liblog - Android NDK logger interfaces
+       liblog - Android Internal NDK logger interfaces
 
 SYNOPSIS
-       #include <android/log.h>
+       /*
+        * Please limit to 24 characters for runtime is loggable,
+        * 16 characters for persist is loggable, and logcat pretty
+        * alignment with limit of 7 characters.
+        */
+       #define LOG_TAG "yourtag"
+       #include <log/log.h>
 
        ALOG(android_priority, tag, format, ...)
        IF_ALOG(android_priority, tag)
@@ -56,9 +62,7 @@
        LOG_EVENT_INT(tag, value)
        LOG_EVENT_LONG(tag, value)
 
-       Link with -llog
-
-       #include <log/logger.h>
+       clockid_t android_log_clockid()
 
        log_id_t android_logger_get_id(struct logger *logger)
        int android_logger_clear(struct logger *logger)
@@ -66,21 +70,44 @@
        int android_logger_get_log_readable_size(struct logger *logger)
        int android_logger_get_log_version(struct logger *logger)
 
-       struct  logger_list  *android_logger_list_alloc(int  mode, unsigned int
-       tail, pid_t pid)
-       struct  logger  *android_logger_open(struct  logger_list  *logger_list,
-       log_id_t id)
-       struct  logger_list  *android_logger_list_open(log_id_t  id,  int mode,
-       unsigned int tail, pid_t pid)
-
-       int android_logger_list_read(struct  logger_list  *logger_list,  struct
-       log_msg *log_msg
-
+       struct logger_list *android_logger_list_alloc(int mode,
+                                                     unsigned int tail,
+                                                     pid_t pid)
+       struct logger *android_logger_open(struct logger_list *logger_list,
+                                          log_id_t id)
+       struct logger_list *android_logger_list_open(log_id_t id, int mode,
+                                                    unsigned int tail,
+                                                    pid_t pid)
+       int android_logger_list_read(struct logger_list *logger_list,
+                                    struct log_msg *log_msg)
        void android_logger_list_free(struct logger_list *logger_list)
 
        log_id_t android_name_to_log_id(const char *logName)
        const char *android_log_id_to_name(log_id_t log_id)
 
+       android_log_context create_android_logger(uint32_t tag)
+
+       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)
+
+       int android_log_write_list(android_log_context ctx,
+                                  log_id_t id = LOG_ID_EVENTS)
+
+       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)
+
+       int android_log_destroy(android_log_context *ctx)
+
        Link with -llog
 
 DESCRIPTION
@@ -163,8 +190,8 @@
        library retries on EINTR, -EINTR should never be returned.
 
 SEE ALSO
-       syslogd(8)
+       syslogd(8), klogd, auditd(8)
 
 
 
-                                  24 Jan 2014                        LIBLOG(3)
+                                  17 Oct 2016                        LIBLOG(3)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 6705fb2..e8e0335 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
@@ -37,6 +38,8 @@
     uint32_t tagIndex;
     char*    tagStr;
     size_t   tagLen;
+    char*    fmtStr;
+    size_t   fmtLen;
 } EventTag;
 
 /*
@@ -70,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;
     }
 
@@ -84,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;
     }
 
@@ -100,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;
     }
 
@@ -175,6 +179,39 @@
     return NULL;
 }
 
+/*
+ * Look up an entry in the map.
+ *
+ * The entries are sorted by tag number, so we can do a binary search.
+ */
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+    const EventTagMap* map, size_t *len, unsigned int tag)
+{
+    int lo = 0;
+    int hi = map->numTags - 1;
+
+    while (lo <= hi) {
+        int mid = (lo + hi) / 2;
+        int cmp = map->tagArray[mid].tagIndex - tag;
+
+        if (cmp < 0) {
+            /* tag is bigger */
+            lo = mid + 1;
+        } else if (cmp > 0) {
+            /* tag is smaller */
+            hi = mid - 1;
+        } else {
+            /* found */
+            if (len) *len = map->tagArray[mid].fmtLen;
+            return map->tagArray[mid].fmtStr;
+        }
+    }
+
+    errno = ENOENT;
+    if (len) *len = 0;
+    return NULL;
+}
+
 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
                                                      unsigned int tag)
 {
@@ -363,17 +400,21 @@
     }
     tag->tagLen = cp - tag->tagStr;
 
-    if (isspace(*cp)) {
-        /* just ignore the rest of the line till \n
-        TODO: read the tag description that follows the tag name
-        */
-        while (*cp != '\n') ++cp;
-    } else {
+    if (!isspace(*cp)) {
         fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
         errno = EINVAL;
         return -1;
     }
 
+    while (isspace(*cp) && (*cp != '\n')) ++cp;
+    if (*cp != '#') {
+        tag->fmtStr = cp;
+        while ((*cp != '\n') && (*cp != '#')) ++cp;
+        while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
+        tag->fmtLen = cp - tag->fmtStr;
+    }
+
+    while (*cp != '\n') ++cp;
     *pData = cp;
 
     return 0;
@@ -405,12 +446,14 @@
     for (i = 1; i < map->numTags; i++) {
         if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
             fprintf(stderr,
-                "%s: duplicate tag entries (%" PRIu32 ":%.*s and %" PRIu32 ":%.*s)\n",
+                "%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
                 OUT_TAG,
-                map->tagArray[i].tagIndex, (int)map->tagArray[i].tagLen,
-                map->tagArray[i].tagStr,
-                map->tagArray[i - 1].tagIndex, (int)map->tagArray[i - 1].tagLen,
-                map->tagArray[i - 1].tagStr);
+                map->tagArray[i].tagIndex,
+                (int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
+                (int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
+                map->tagArray[i - 1].tagIndex,
+                (int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
+                (int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
             errno = EMLINK;
             return -1;
         }
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 7bd1f83..4939221 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -25,10 +25,14 @@
 #if !defined(_WIN32)
 #include <pthread.h>
 #endif
+#include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include <android/log.h>
+#include <log/uio.h>
 
 #include "fake_log_device.h"
 #include "log_portability.h"
@@ -727,3 +731,8 @@
     int logLevel = def;
     return logLevel >= 0 && prio >= logLevel;
 }
+
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
+{
+    return 1;
+}
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index 47935e3..dab8bc5 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -18,7 +18,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "config_write.h"
 #include "fake_log_device.h"
diff --git a/liblog/legacy-ndk-includes/log.h b/liblog/legacy-ndk-includes/log.h
new file mode 100644
index 0000000..0ea4c29
--- /dev/null
+++ b/liblog/legacy-ndk-includes/log.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 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 _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit) since
+ *   platform release 1.5
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ *   - a priority
+ *   - a log tag
+ *   - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ *  - Sending log messages eats CPU and slow down your application and the
+ *    system.
+ *
+ *  - The circular log buffer is pretty small (<64KB), sending many messages
+ *    might push off other important log messages from the rest of the system.
+ *
+ *  - In release builds, only send log messages to account for exceptional
+ *    conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+    ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+                         const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+			  const char *fmt, ...)    
+#if defined(__GNUC__)
+    __attribute__ ((noreturn))
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 5f19cc1..599dc90 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -1,14 +1,19 @@
 LIBLOG {
   global:
     __android_log_assert;
-    __android_log_btwrite;
-    __android_log_buf_print; # introduced-arm=21 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
-    __android_log_buf_write; # introduced-arm=21 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
-    __android_log_bwrite;
-    __android_log_dev_available;
     __android_log_print;
     __android_log_vprint;
     __android_log_write;
   local:
     *;
 };
+
+LIBLOG_M {
+  global:
+    __android_log_is_loggable;
+};
+
+LIBLOG_O {
+  global:
+    __android_log_is_loggable_len;
+};
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a4244cd..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
-#include <log/logger.h>
+#include <log/log_event_list.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
@@ -320,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) {
@@ -333,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 8c8a9a1..14d6482 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -15,8 +15,10 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 
-#include <android/log.h>
+#include <log/log.h>
+#include <log/log_event_list.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 4af8507..dda09e0 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -16,12 +16,14 @@
 
 #include <ctype.h>
 #include <pthread.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
+#include <unistd.h>
 
-#include <android/log.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
@@ -47,12 +49,16 @@
 }
 
 struct cache {
-    const prop_info *pinfo;
+    const prop_info* pinfo;
     uint32_t serial;
+};
+
+struct cache_char {
+    struct cache cache;
     unsigned char c;
 };
 
-static int check_cache(struct cache *cache)
+static int check_cache(struct cache* cache)
 {
     return cache->pinfo
         && __system_property_serial(cache->pinfo) != cache->serial;
@@ -61,18 +67,18 @@
 #define BOOLEAN_TRUE 0xFF
 #define BOOLEAN_FALSE 0xFE
 
-static void refresh_cache(struct cache *cache, const char *key)
+static void refresh_cache(struct cache_char* cache, const char* key)
 {
     char buf[PROP_VALUE_MAX];
 
-    if (!cache->pinfo) {
-        cache->pinfo = __system_property_find(key);
-        if (!cache->pinfo) {
+    if (!cache->cache.pinfo) {
+        cache->cache.pinfo = __system_property_find(key);
+        if (!cache->cache.pinfo) {
             return;
         }
     }
-    cache->serial = __system_property_serial(cache->pinfo);
-    __system_property_read(cache->pinfo, 0, buf);
+    cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+    __system_property_read(cache->cache.pinfo, 0, buf);
     switch(buf[0]) {
     case 't': case 'T':
         cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
@@ -85,7 +91,7 @@
     }
 }
 
-static int __android_log_level(const char *tag, size_t len, int default_prio)
+static int __android_log_level(const char* tag, size_t len, int default_prio)
 {
     /* sizeof() is used on this array below */
     static const char log_namespace[] = "persist.log.tag.";
@@ -93,8 +99,8 @@
     /* calculate the size of our key temporary buffer */
     const size_t taglen = tag ? len : 0;
     /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
-    char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */
-    char *kp;
+    char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+    char* kp;
     size_t i;
     char c = 0;
     /*
@@ -110,8 +116,8 @@
     static uint32_t global_serial;
     /* some compilers erroneously see uninitialized use. !not_locked */
     uint32_t current_global_serial = 0;
-    static struct cache tag_cache[2];
-    static struct cache global_cache[2];
+    static struct cache_char tag_cache[2];
+    static struct cache_char global_cache[2];
     int change_detected;
     int global_change_detected;
     int not_locked;
@@ -125,12 +131,12 @@
          *  check all known serial numbers to changes.
          */
         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-            if (check_cache(&tag_cache[i])) {
+            if (check_cache(&tag_cache[i].cache)) {
                 change_detected = 1;
             }
         }
         for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
-            if (check_cache(&global_cache[i])) {
+            if (check_cache(&global_cache[i].cache)) {
                 global_change_detected = 1;
             }
         }
@@ -154,7 +160,7 @@
                     || ((len < sizeof(last_tag)) && last_tag[len])) {
                 /* invalidate log.tag.<tag> cache */
                 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-                    tag_cache[i].pinfo = NULL;
+                    tag_cache[i].cache.pinfo = NULL;
                     tag_cache[i].c = '\0';
                 }
                 last_tag[0] = '\0';
@@ -174,11 +180,11 @@
 
         kp = key;
         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-            struct cache *cache = &tag_cache[i];
-            struct cache temp_cache;
+            struct cache_char* cache = &tag_cache[i];
+            struct cache_char temp_cache;
 
             if (not_locked) {
-                temp_cache.pinfo = NULL;
+                temp_cache.cache.pinfo = NULL;
                 temp_cache.c = '\0';
                 cache = &temp_cache;
             }
@@ -212,13 +218,13 @@
 
         kp = key;
         for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
-            struct cache *cache = &global_cache[i];
-            struct cache temp_cache;
+            struct cache_char* cache = &global_cache[i];
+            struct cache_char temp_cache;
 
             if (not_locked) {
                 temp_cache = *cache;
-                if (temp_cache.pinfo != cache->pinfo) { /* check atomic */
-                    temp_cache.pinfo = NULL;
+                if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
+                    temp_cache.cache.pinfo = NULL;
                     temp_cache.c = '\0';
                 }
                 cache = &temp_cache;
@@ -257,7 +263,7 @@
 }
 
 LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
-                                                    const char *tag, size_t len,
+                                                    const char* tag, size_t len,
                                                     int default_prio)
 {
     int logLevel = __android_log_level(tag, len, default_prio);
@@ -265,7 +271,7 @@
 }
 
 LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
-                                                const char *tag,
+                                                const char* tag,
                                                 int default_prio)
 {
     int logLevel = __android_log_level(tag,
@@ -274,21 +280,21 @@
     return logLevel >= 0 && prio >= logLevel;
 }
 
-LIBLOG_HIDDEN int __android_log_is_debuggable()
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
 {
     static uint32_t serial;
-    static struct cache tag_cache;
+    static struct cache_char tag_cache;
     static const char key[] = "ro.debuggable";
     int ret;
 
     if (tag_cache.c) { /* ro property does not change after set */
         ret = tag_cache.c == '1';
     } else if (lock()) {
-        struct cache temp_cache = { NULL, -1, '\0' };
+        struct cache_char temp_cache = { { NULL, -1 }, '\0' };
         refresh_cache(&temp_cache, key);
         ret = temp_cache.c == '1';
     } else {
-        int change_detected = check_cache(&tag_cache);
+        int change_detected = check_cache(&tag_cache.cache);
         uint32_t current_serial = __system_property_area_serial();
         if (current_serial != serial) {
             change_detected = 1;
@@ -310,17 +316,17 @@
  * Since a change is rare, we will accept a trylock failure gracefully.
  * Use a separate lock from is_loggable to keep contention down b/25563384.
  */
-struct cache2 {
+struct cache2_char {
     pthread_mutex_t lock;
     uint32_t serial;
-    const char *key_persist;
-    struct cache cache_persist;
-    const char *key_ro;
-    struct cache cache_ro;
-    unsigned char (*const evaluate)(const struct cache2 *self);
+    const char* key_persist;
+    struct cache_char cache_persist;
+    const char* key_ro;
+    struct cache_char cache_ro;
+    unsigned char (*const evaluate)(const struct cache2_char *self);
 };
 
-static inline unsigned char do_cache2(struct cache2 *self)
+static inline unsigned char do_cache2_char(struct cache2_char *self)
 {
     uint32_t current_serial;
     int change_detected;
@@ -331,8 +337,8 @@
         return self->evaluate(self);
     }
 
-    change_detected = check_cache(&self->cache_persist)
-                   || check_cache(&self->cache_ro);
+    change_detected = check_cache(&self->cache_persist.cache)
+                   || check_cache(&self->cache_ro.cache);
     current_serial = __system_property_area_serial();
     if (current_serial != self->serial) {
         change_detected = 1;
@@ -349,7 +355,7 @@
     return c;
 }
 
-static unsigned char evaluate_persist_ro(const struct cache2 *self)
+static unsigned char evaluate_persist_ro(const struct cache2_char *self)
 {
     unsigned char c = self->cache_persist.c;
 
@@ -366,17 +372,17 @@
  */
 LIBLOG_ABI_PUBLIC clockid_t android_log_clockid()
 {
-    static struct cache2 clockid = {
+    static struct cache2_char clockid = {
         PTHREAD_MUTEX_INITIALIZER,
         0,
         "persist.logd.timestamp",
-        { NULL, -1, '\0' },
+        { { NULL, -1 }, '\0' },
         "ro.logd.timestamp",
-        { NULL, -1, '\0' },
+        { { NULL, -1 }, '\0' },
         evaluate_persist_ro
     };
 
-    return (tolower(do_cache2(&clockid)) == 'm')
+    return (tolower(do_cache2_char(&clockid)) == 'm')
         ? CLOCK_MONOTONIC
         : CLOCK_REALTIME;
 }
@@ -385,7 +391,7 @@
  * Security state generally remains constant, but the DO must be able
  * to turn off logging should it become spammy after an attack is detected.
  */
-static unsigned char evaluate_security(const struct cache2 *self)
+static unsigned char evaluate_security(const struct cache2_char *self)
 {
     unsigned char c = self->cache_ro.c;
 
@@ -394,15 +400,265 @@
 
 LIBLOG_ABI_PUBLIC int __android_log_security()
 {
-    static struct cache2 security = {
+    static struct cache2_char security = {
         PTHREAD_MUTEX_INITIALIZER,
         0,
         "persist.logd.security",
-        { NULL, -1, BOOLEAN_FALSE },
+        { { NULL, -1 }, BOOLEAN_FALSE },
         "ro.device_owner",
-        { NULL, -1, BOOLEAN_FALSE },
+        { { NULL, -1 }, BOOLEAN_FALSE },
         evaluate_security
     };
 
-    return do_cache2(&security);
+    return do_cache2_char(&security);
+}
+
+/*
+ * Interface that represents the logd buffer size determination so that others
+ * need not guess our intentions.
+ */
+
+/* Property helper */
+static bool check_flag(const char* prop, const char* flag) {
+    const char* cp = strcasestr(prop, flag);
+    if (!cp) {
+        return false;
+    }
+    /* We only will document comma (,) */
+    static const char sep[] = ",:;|+ \t\f";
+    if ((cp != prop) && !strchr(sep, cp[-1])) {
+        return false;
+    }
+    cp += strlen(flag);
+    return !*cp || !!strchr(sep, *cp);
+}
+
+/* cache structure */
+struct cache_property {
+    struct cache cache;
+    char property[PROP_VALUE_MAX];
+};
+
+static void refresh_cache_property(struct cache_property* cache, const char* key)
+{
+    if (!cache->cache.pinfo) {
+        cache->cache.pinfo = __system_property_find(key);
+        if (!cache->cache.pinfo) {
+            return;
+        }
+    }
+    cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+    __system_property_read(cache->cache.pinfo, 0, cache->property);
+}
+
+/* get boolean with the logger twist that supports eng adjustments */
+LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key,
+                                                           int flag)
+{
+    struct cache_property property = { { NULL, -1 }, { 0 } };
+    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
+        char newkey[PROP_NAME_MAX];
+        snprintf(newkey, sizeof(newkey), "ro.%s", key);
+        refresh_cache_property(&property, newkey);
+        property.cache.pinfo = NULL;
+        property.cache.serial = -1;
+        snprintf(newkey, sizeof(newkey), "persist.%s", key);
+        refresh_cache_property(&property, newkey);
+        property.cache.pinfo = NULL;
+        property.cache.serial = -1;
+    }
+
+    refresh_cache_property(&property, key);
+
+    if (check_flag(property.property, "true")) {
+        return true;
+    }
+    if (check_flag(property.property, "false")) {
+        return false;
+    }
+    if (check_flag(property.property, "eng")) {
+       flag |= BOOL_DEFAULT_FLAG_ENG;
+    }
+    /* this is really a "not" flag */
+    if (check_flag(property.property, "svelte")) {
+       flag |= BOOL_DEFAULT_FLAG_SVELTE;
+    }
+
+    /* Sanity Check */
+    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
+        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
+        flag |= BOOL_DEFAULT_TRUE;
+    }
+
+    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
+            && __android_logger_property_get_bool("ro.config.low_ram",
+                                 BOOL_DEFAULT_FALSE)) {
+        return false;
+    }
+    if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
+        return false;
+    }
+
+    return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
+}
+
+LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value)
+{
+    static long pages, pagesize;
+    unsigned long maximum;
+
+    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+        return false;
+    }
+
+    if (!pages) {
+        pages = sysconf(_SC_PHYS_PAGES);
+    }
+    if (pages < 1) {
+        return true;
+    }
+
+    if (!pagesize) {
+        pagesize = sysconf(_SC_PAGESIZE);
+        if (pagesize <= 1) {
+            pagesize = PAGE_SIZE;
+        }
+    }
+
+    /* maximum memory impact a somewhat arbitrary ~3% */
+    pages = (pages + 31) / 32;
+    maximum = pages * pagesize;
+
+    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+        return true;
+    }
+
+    return value <= maximum;
+}
+
+struct cache2_property_size {
+    pthread_mutex_t lock;
+    uint32_t serial;
+    const char* key_persist;
+    struct cache_property cache_persist;
+    const char* key_ro;
+    struct cache_property cache_ro;
+    unsigned long (*const evaluate)(const struct cache2_property_size* self);
+};
+
+static inline unsigned long do_cache2_property_size(struct cache2_property_size* self)
+{
+    uint32_t current_serial;
+    int change_detected;
+    unsigned long v;
+
+    if (pthread_mutex_trylock(&self->lock)) {
+        /* We are willing to accept some race in this context */
+        return self->evaluate(self);
+    }
+
+    change_detected = check_cache(&self->cache_persist.cache)
+                   || check_cache(&self->cache_ro.cache);
+    current_serial = __system_property_area_serial();
+    if (current_serial != self->serial) {
+        change_detected = 1;
+    }
+    if (change_detected) {
+        refresh_cache_property(&self->cache_persist, self->key_persist);
+        refresh_cache_property(&self->cache_ro, self->key_ro);
+        self->serial = current_serial;
+    }
+    v = self->evaluate(self);
+
+    pthread_mutex_unlock(&self->lock);
+
+    return v;
+}
+
+static unsigned long property_get_size_from_cache(const struct cache_property* cache)
+{
+    char* cp;
+    unsigned long value = strtoul(cache->property, &cp, 10);
+
+    switch(*cp) {
+    case 'm':
+    case 'M':
+        value *= 1024;
+    /* FALLTHRU */
+    case 'k':
+    case 'K':
+        value *= 1024;
+    /* FALLTHRU */
+    case '\0':
+        break;
+
+    default:
+        value = 0;
+    }
+
+    if (!__android_logger_valid_buffer_size(value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+static unsigned long evaluate_property_get_size(const struct cache2_property_size* self)
+{
+    unsigned long size = property_get_size_from_cache(&self->cache_persist);
+    if (size) {
+        return size;
+    }
+    return property_get_size_from_cache(&self->cache_ro);
+}
+
+LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId)
+{
+    static const char global_tunable[] = "persist.logd.size"; /* Settings App */
+    static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
+    static struct cache2_property_size global = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        global_tunable,
+        { { NULL, -1 }, {} },
+        global_default,
+        { { NULL, -1 }, {} },
+        evaluate_property_get_size
+    };
+    char key_persist[PROP_NAME_MAX];
+    char key_ro[PROP_NAME_MAX];
+    struct cache2_property_size local = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        key_persist,
+        { { NULL, -1 }, {} },
+        key_ro,
+        { { NULL, -1 }, {} },
+        evaluate_property_get_size
+    };
+    unsigned long property_size, default_size;
+
+    default_size =  do_cache2_property_size(&global);
+    if (!default_size) {
+        default_size = __android_logger_property_get_bool("ro.config.low_ram",
+                                                          BOOL_DEFAULT_FALSE)
+            ? LOG_BUFFER_MIN_SIZE /* 64K  */
+            : LOG_BUFFER_SIZE;    /* 256K */
+    }
+
+    snprintf(key_persist, sizeof(key_persist), "%s.%s",
+             global_tunable, android_log_id_to_name(logId));
+    snprintf(key_ro, sizeof(key_ro), "%s.%s",
+             global_default, android_log_id_to_name(logId));
+    property_size = do_cache2_property_size(&local);
+
+    if (!property_size) {
+        property_size = default_size;
+    }
+
+    if (!property_size) {
+        property_size = LOG_BUFFER_SIZE;
+    }
+
+    return property_size;
 }
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index c8bd27d..dfd2d44 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -19,7 +19,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <log/logger.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index 563b5c7..99d7fea 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -31,9 +31,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/sockets.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -482,17 +480,17 @@
     struct sigaction old_sigaction;
     unsigned int old_alarm = 0;
     char buffer[256], *cp, c;
-    int e, ret, remaining;
-
-    int sock = transp->context.sock;
-    if (sock > 0) {
-        return sock;
-    }
+    int e, ret, remaining, sock;
 
     if (!logger_list) {
         return -EINVAL;
     }
 
+    sock = atomic_load(&transp->context.sock);
+    if (sock > 0) {
+        return sock;
+    }
+
     sock = socket_local_client("logdr",
                                ANDROID_SOCKET_NAMESPACE_RESERVED,
                                SOCK_SEQPACKET);
@@ -587,7 +585,11 @@
         return ret;
     }
 
-    return transp->context.sock = sock;
+    ret = atomic_exchange(&transp->context.sock, sock);
+    if ((ret > 0) && (ret != sock)) {
+        close(ret);
+    }
+    return sock;
 }
 
 /* Read from the selected logs */
@@ -662,8 +664,8 @@
 static void logdClose(struct android_log_logger_list *logger_list __unused,
                       struct android_log_transport_context *transp)
 {
-    if (transp->context.sock > 0) {
-        close (transp->context.sock);
-        transp->context.sock = -1;
+    int sock = atomic_exchange(&transp->context.sock, -1);
+    if (sock > 0) {
+        close (sock);
     }
 }
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index e8e392d..8fdfb92 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -31,9 +31,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/sockets.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -65,7 +63,8 @@
 {
     int i, ret = 0;
 
-    if (logdLoggerWrite.context.sock < 0) {
+    i = atomic_load(&logdLoggerWrite.context.sock);
+    if (i < 0) {
         i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
         if (i < 0) {
             ret = -errno;
@@ -80,7 +79,11 @@
                 ret = -errno;
                 close(i);
             } else {
-                logdLoggerWrite.context.sock = i;
+                ret = atomic_exchange(&logdLoggerWrite.context.sock, i);
+                if ((ret >= 0) && (ret != i)) {
+                    close(ret);
+                }
+                ret = 0;
             }
         }
     }
@@ -90,9 +93,9 @@
 
 static void logdClose()
 {
-    if (logdLoggerWrite.context.sock >= 0) {
-        close(logdLoggerWrite.context.sock);
-        logdLoggerWrite.context.sock = -1;
+    int sock = atomic_exchange(&logdLoggerWrite.context.sock, -1);
+    if (sock >= 0) {
+        close(sock);
     }
 }
 
@@ -101,7 +104,7 @@
     if (logId > LOG_ID_SECURITY) {
         return -EINVAL;
     }
-    if (logdLoggerWrite.context.sock < 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
         if (access("/dev/socket/logdw", W_OK) == 0) {
             return 0;
         }
@@ -121,7 +124,7 @@
     static atomic_int_fast32_t dropped;
     static atomic_int_fast32_t droppedSecurity;
 
-    if (logdLoggerWrite.context.sock < 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
         return -EBADF;
     }
 
@@ -160,7 +163,7 @@
     newVec[0].iov_base = (unsigned char *)&header;
     newVec[0].iov_len  = sizeof(header);
 
-    if (logdLoggerWrite.context.sock > 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) > 0) {
         int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
                                                     memory_order_relaxed);
         if (snapshot) {
@@ -174,7 +177,8 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(
+                    atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&droppedSecurity, snapshot,
                                           memory_order_relaxed);
@@ -194,7 +198,8 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(
+                      atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&dropped, snapshot,
                                           memory_order_relaxed);
@@ -223,7 +228,8 @@
      * ENOTCONN occurs if logd dies.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+    ret = TEMP_FAILURE_RETRY(writev(
+            atomic_load(&logdLoggerWrite.context.sock), newVec, i));
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
@@ -236,7 +242,8 @@
                 return ret;
             }
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+            ret = TEMP_FAILURE_RETRY(writev(
+                    atomic_load(&logdLoggerWrite.context.sock), newVec, i));
             if (ret < 0) {
                 ret = -errno;
             }
diff --git a/liblog/logger.h b/liblog/logger.h
index 8fb2b4d..50d1cb4 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -17,12 +17,12 @@
 #ifndef _LIBLOG_LOGGER_H__
 #define _LIBLOG_LOGGER_H__
 
+#include <stdatomic.h>
 #include <stdbool.h>
-#include <log/uio.h>
 
-#include <android/log.h>
 #include <cutils/list.h>
-#include <log/logger.h>
+#include <log/log.h>
+#include <log/uio.h>
 
 #include "log_portability.h"
 
@@ -31,9 +31,10 @@
 /* Union, sock or fd of zero is not allowed unless static initialized */
 union android_log_context {
   void *private;
-  int sock;
-  int fd;
+  atomic_int sock;
+  atomic_int fd;
   struct listnode *node;
+  atomic_uintptr_t atomic_pointer;
 };
 
 struct android_log_transport_write {
@@ -155,7 +156,6 @@
 LIBLOG_HIDDEN void __android_log_lock();
 LIBLOG_HIDDEN int __android_log_trylock();
 LIBLOG_HIDDEN void __android_log_unlock();
-LIBLOG_HIDDEN int __android_log_is_debuggable();
 
 __END_DECLS
 
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index 12e263a..5c4feaf 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -16,8 +16,7 @@
 
 #include <string.h>
 
-#include <android/log.h>
-#include <log/logger.h>
+#include <log/log.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index d979e22..c3cb7ad 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -25,7 +25,6 @@
 
 #include <android/log.h>
 #include <cutils/list.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 
 #include "config_read.h"
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 1e56b27..170c8d1 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -24,9 +24,7 @@
 #include <android/set_abort_message.h>
 #endif
 
-#include <android/log.h>
 #include <log/event_tag_map.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -191,7 +189,7 @@
     __android_log_unlock();
 
 #if defined(__BIONIC__)
-    android_closeEventTagMap(m);
+    if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
 #endif
 
 }
@@ -295,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 2c4e619..da80e36 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,18 +21,18 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <pwd.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <inttypes.h>
 #include <sys/param.h>
 #include <sys/types.h>
 
-#include <android/log.h>
 #include <cutils/list.h>
+#include <log/log.h>
 #include <log/logprint.h>
 
 #include "log_portability.h"
@@ -58,9 +58,16 @@
     bool epoch_output;
     bool monotonic_output;
     bool uid_output;
+    bool descriptive_output;
 };
 
 /*
+ * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
+ * during android_log_processBinaryLogBuffer(), so we break layering.
+ */
+static bool descriptive_output = false;
+
+/*
  *  gnome-terminal color tags
  *    See http://misc.flogisoft.com/bash/tip_colors_and_formatting
  *    for ideas on how to set the forground color of the text for xterm.
@@ -209,6 +216,8 @@
     p_ret->epoch_output = false;
     p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
     p_ret->uid_output = false;
+    p_ret->descriptive_output = false;
+    descriptive_output = false;
 
     return p_ret;
 }
@@ -267,6 +276,10 @@
     case FORMAT_MODIFIER_UID:
         p_format->uid_output = true;
         return 0;
+    case FORMAT_MODIFIER_DESCRIPT:
+        p_format->descriptive_output = true;
+        descriptive_output = true;
+        return 0;
     default:
         break;
     }
@@ -294,6 +307,7 @@
     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
     else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+    else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
     else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
     else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
     else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -301,6 +315,7 @@
     else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
     else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
     else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
+    else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
     else {
         extern char *tzname[2];
         static const char gmt[] = "GMT";
@@ -566,6 +581,19 @@
     return ((uint64_t) high << 32) | (uint64_t) low;
 }
 
+static bool findChar(const char** cp, size_t* len, int c) {
+    while (*len && isspace(**cp)) {
+        ++*cp;
+        --*len;
+    }
+    if (c == INT_MAX) return *len;
+    if (*len && (**cp == c)) {
+        ++*cp;
+        --*len;
+        return true;
+    }
+    return false;
+}
 
 /*
  * Recursively convert binary log data to printable form.
@@ -578,63 +606,151 @@
  *
  * Returns 0 on success, 1 on buffer full, -1 on failure.
  */
+enum objectType {
+    TYPE_OBJECTS      = '1',
+    TYPE_BYTES        = '2',
+    TYPE_MILLISECONDS = '3',
+    TYPE_ALLOCATIONS  = '4',
+    TYPE_ID           = '5',
+    TYPE_PERCENT      = '6'
+};
+
 static int android_log_printBinaryEvent(const unsigned char** pEventData,
-    size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
+    size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
+    const char** fmtStr, size_t* fmtLen)
 {
     const unsigned char* eventData = *pEventData;
     size_t eventDataLen = *pEventDataLen;
     char* outBuf = *pOutBuf;
+    char* outBufSave = outBuf;
     size_t outBufLen = *pOutBufLen;
+    size_t outBufLenSave = outBufLen;
     unsigned char type;
     size_t outCount;
     int result = 0;
+    const char* cp;
+    size_t len;
+    int64_t lval;
 
-    if (eventDataLen < 1)
-        return -1;
+    if (eventDataLen < 1) return -1;
+
     type = *eventData++;
     eventDataLen--;
 
+    cp = NULL;
+    len = 0;
+    if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+        cp = *fmtStr;
+        len = *fmtLen;
+    }
+    /*
+     * event.logtag format specification:
+     *
+     * Optionally, after the tag names can be put a description for the value(s)
+     * of the tag. Description are in the format
+     *    (<name>|data type[|data unit])
+     * Multiple values are separated by commas.
+     *
+     * The data type is a number from the following values:
+     * 1: int
+     * 2: long
+     * 3: string
+     * 4: list
+     * 5: float
+     *
+     * The data unit is a number taken from the following list:
+     * 1: Number of objects
+     * 2: Number of bytes
+     * 3: Number of milliseconds
+     * 4: Number of allocations
+     * 5: Id
+     * 6: Percent
+     * Default value for data of type int/long is 2 (bytes).
+     */
+    if (!cp || !findChar(&cp, &len, '(')) {
+        len = 0;
+    } else {
+        char* outBufLastSpace = NULL;
+
+        findChar(&cp, &len, INT_MAX);
+        while (len && *cp && (*cp != '|') && (*cp != ')')) {
+            if (outBufLen <= 0) {
+                /* halt output */
+                goto no_room;
+            }
+            outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+            *outBuf = *cp;
+            ++outBuf;
+            ++cp;
+            --outBufLen;
+            --len;
+        }
+        if (outBufLastSpace) {
+            outBufLen += outBuf - outBufLastSpace;
+            outBuf = outBufLastSpace;
+        }
+        if (outBufLen <= 0) {
+            /* halt output */
+            goto no_room;
+        }
+        if (outBufSave != outBuf) {
+            *outBuf = '=';
+            ++outBuf;
+            --outBufLen;
+        }
+
+        if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+            static const unsigned char typeTable[] = {
+                EVENT_TYPE_INT,
+                EVENT_TYPE_LONG,
+                EVENT_TYPE_STRING,
+                EVENT_TYPE_LIST,
+                EVENT_TYPE_FLOAT
+            };
+
+            if ((*cp >= '1') &&
+                (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+                (type != typeTable[(size_t)(*cp - '1')])) len = 0;
+
+            if (len) {
+                ++cp;
+                --len;
+            } else {
+                /* reset the format */
+                outBuf = outBufSave;
+                outBufLen = outBufLenSave;
+            }
+        }
+    }
+    lval = 0;
     switch (type) {
     case EVENT_TYPE_INT:
         /* 32-bit signed int */
         {
-            int ival;
+            int32_t ival;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
 
-            outCount = snprintf(outBuf, outBufLen, "%d", ival);
-            if (outCount < outBufLen) {
-                outBuf += outCount;
-                outBufLen -= outCount;
-            } else {
-                /* halt output */
-                goto no_room;
-            }
+            lval = ival;
         }
-        break;
+        goto pr_lval;
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
-        {
-            uint64_t lval;
-
-            if (eventDataLen < 8)
-                return -1;
-            lval = get8LE(eventData);
-            eventData += 8;
-            eventDataLen -= 8;
-
-            outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
-            if (outCount < outBufLen) {
-                outBuf += outCount;
-                outBufLen -= outCount;
-            } else {
-                /* halt output */
-                goto no_room;
-            }
+        if (eventDataLen < 8) return -1;
+        lval = get8LE(eventData);
+        eventData += 8;
+        eventDataLen -= 8;
+    pr_lval:
+        outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+        if (outCount < outBufLen) {
+            outBuf += outCount;
+            outBufLen -= outCount;
+        } else {
+            /* halt output */
+            goto no_room;
         }
         break;
     case EVENT_TYPE_FLOAT:
@@ -643,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;
@@ -665,15 +780,18 @@
         {
             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 */
+                outBuf = outBufSave;
+                outBufLen = outBufLenSave;
+            }
             if (strLen < outBufLen) {
                 memcpy(outBuf, eventData, strLen);
                 outBuf += strLen;
@@ -695,53 +813,122 @@
             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);
-                if (result != 0)
-                    goto bail;
+                        &outBuf, &outBufLen, fmtStr, fmtLen);
+                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:
         fprintf(stderr, "Unknown binary event type %d\n", type);
         return -1;
     }
+    if (cp && len) {
+        if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+            switch (*cp) {
+            case TYPE_OBJECTS:
+                outCount = 0;
+                /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+                break;
+            case TYPE_BYTES:
+                if ((lval != 0) && ((lval % 1024) == 0)) {
+                    /* repaint with multiplier */
+                    static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+                    size_t idx = 0;
+                    outBuf -= outCount;
+                    outBufLen += outCount;
+                    do {
+                        lval /= 1024;
+                        if ((lval % 1024) != 0) break;
+                    } while (++idx < ((sizeof(suffixTable) /
+                                       sizeof(suffixTable[0])) - 1));
+                    outCount = snprintf(outBuf, outBufLen,
+                                        "%" PRId64 "%cB",
+                                        lval, suffixTable[idx]);
+                } else {
+                    outCount = snprintf(outBuf, outBufLen, "B");
+                }
+                break;
+            case TYPE_MILLISECONDS:
+                if (((lval <= -1000) || (1000 <= lval)) &&
+                        (outBufLen || (outBuf[-1] == '0'))) {
+                    /* repaint as (fractional) seconds, possibly saving space */
+                    if (outBufLen) outBuf[0] = outBuf[-1];
+                    outBuf[-1] = outBuf[-2];
+                    outBuf[-2] = outBuf[-3];
+                    outBuf[-3] = '.';
+                    while ((outBufLen == 0) || (*outBuf == '0')) {
+                        --outBuf;
+                        ++outBufLen;
+                    }
+                    if (*outBuf != '.') {
+                       ++outBuf;
+                       --outBufLen;
+                    }
+                    outCount = snprintf(outBuf, outBufLen, "s");
+                } else {
+                    outCount = snprintf(outBuf, outBufLen, "ms");
+                }
+                break;
+            case TYPE_ALLOCATIONS:
+                outCount = 0;
+                /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+                break;
+            case TYPE_ID:
+                outCount = 0;
+                break;
+            case TYPE_PERCENT:
+                outCount = snprintf(outBuf, outBufLen, "%%");
+                break;
+            default: /* ? */
+                outCount = 0;
+                break;
+            }
+            ++cp;
+            --len;
+            if (outCount < outBufLen) {
+                outBuf += outCount;
+                outBufLen -= outCount;
+            } else if (outCount) {
+                /* halt output */
+                goto no_room;
+            }
+        }
+        if (!findChar(&cp, &len, ')')) len = 0;
+        if (!findChar(&cp, &len, ',')) len = 0;
+    }
 
 bail:
     *pEventData = eventData;
     *pEventDataLen = eventDataLen;
     *pOutBuf = outBuf;
     *pOutBufLen = outBufLen;
+    if (cp) {
+        *fmtStr = cp;
+        *fmtLen = len;
+    }
     return result;
 
 no_room:
@@ -764,7 +951,7 @@
         char *messageBuf, int messageBufLen)
 {
     size_t inCount;
-    unsigned int tagIndex;
+    uint32_t tagIndex;
     const unsigned char* eventData;
 
     entry->tv_sec = buf->sec;
@@ -796,8 +983,7 @@
         }
     }
     inCount = buf->len;
-    if (inCount < 4)
-        return -1;
+    if (inCount < 4) return -1;
     tagIndex = get4LE(eventData);
     eventData += 4;
     inCount -= 4;
@@ -817,7 +1003,7 @@
     if (entry->tag == NULL) {
         size_t tagLen;
 
-        tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+        tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
         if (tagLen >= (size_t)messageBufLen) {
             tagLen = messageBufLen - 1;
         }
@@ -830,25 +1016,46 @@
     /*
      * Format the event log data into the buffer.
      */
+    const char* fmtStr = NULL;
+    size_t fmtLen = 0;
+    if (descriptive_output && map) {
+        fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
+    }
+
     char* outBuf = messageBuf;
-    size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
-    int result;
-    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
-                &outRemaining);
+    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;
+        if (buf2->hdr_size) {
+            eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+        }
+        eventData += 4;
+        outBuf = messageBuf;
+        outRemaining = messageBufLen - 1;
+        result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+                                              &outRemaining, NULL, NULL);
+    }
     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' */
@@ -872,7 +1079,7 @@
 
     entry->message = messageBuf;
 
-    return 0;
+    return result;
 }
 
 /*
@@ -1584,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/pmsg_reader.c b/liblog/pmsg_reader.c
index 679c159..a0a69c1 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,8 +151,8 @@
 
     memset(log_msg, 0, sizeof(*log_msg));
 
-    if (transp->context.fd <= 0) {
-        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
+    if (atomic_load(&transp->context.fd) <= 0) {
+        int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
 
         if (fd < 0) {
             return -errno;
@@ -164,13 +164,22 @@
                 return -errno;
             }
         }
-        transp->context.fd = fd;
+        i = atomic_exchange(&transp->context.fd, fd);
+        if ((i > 0) && (i != fd)) {
+            close(i);
+        }
         preread_count = 0;
     }
 
     while(1) {
+        int fd;
+
         if (preread_count < sizeof(buf)) {
-            ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+            fd = atomic_load(&transp->context.fd);
+            if (fd <= 0) {
+                return -EBADF;
+            }
+            ret = TEMP_FAILURE_RETRY(read(fd,
                                           &buf.p.magic + preread_count,
                                           sizeof(buf) - preread_count));
             if (ret < 0) {
@@ -212,9 +221,13 @@
                     log_msg->entry_v4.msg :
                     log_msg->entry_v3.msg;
                 *msg = buf.prio;
-                ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
-                                          msg + sizeof(buf.prio),
-                                          buf.p.len - sizeof(buf)));
+                fd = atomic_load(&transp->context.fd);
+                if (fd <= 0) {
+                    return -EBADF;
+                }
+                ret = TEMP_FAILURE_RETRY(read(fd,
+                                              msg + sizeof(buf.prio),
+                                              buf.p.len - sizeof(buf)));
                 if (ret < 0) {
                     return -errno;
                 }
@@ -239,12 +252,19 @@
             }
         }
 
-        current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
-                                           (off_t)0, SEEK_CUR));
+        fd = atomic_load(&transp->context.fd);
+        if (fd <= 0) {
+            return -EBADF;
+        }
+        current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
         if (current < 0) {
             return -errno;
         }
-        next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+        fd = atomic_load(&transp->context.fd);
+        if (fd <= 0) {
+            return -EBADF;
+        }
+        next = TEMP_FAILURE_RETRY(lseek(fd,
                                         (off_t)(buf.p.len - sizeof(buf)),
                                         SEEK_CUR));
         if (next < 0) {
@@ -258,10 +278,10 @@
 
 static void pmsgClose(struct android_log_logger_list *logger_list __unused,
                       struct android_log_transport_context *transp) {
-    if (transp->context.fd > 0) {
-        close (transp->context.fd);
+    int fd = atomic_exchange(&transp->context.fd, 0);
+    if (fd > 0) {
+        close (fd);
     }
-    transp->context.fd = 0;
 }
 
 LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 06652f3..c1c068e 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -20,14 +20,12 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <time.h>
 
-#include <android/log.h>
-#include <log/logger.h>
-
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -53,18 +51,25 @@
 
 static int pmsgOpen()
 {
-    if (pmsgLoggerWrite.context.fd < 0) {
-        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+    int fd = atomic_load(&pmsgLoggerWrite.context.fd);
+    if (fd < 0) {
+        int i;
+
+        fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+        i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
+        if ((i >= 0) && (i != fd)) {
+            close(i);
+        }
     }
 
-    return pmsgLoggerWrite.context.fd;
+    return fd;
 }
 
 static void pmsgClose()
 {
-    if (pmsgLoggerWrite.context.fd >= 0) {
-        close(pmsgLoggerWrite.context.fd);
-        pmsgLoggerWrite.context.fd = -1;
+    int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
+    if (fd >= 0) {
+        close(fd);
     }
 }
 
@@ -78,7 +83,7 @@
             !__android_log_is_debuggable()) {
         return -EINVAL;
     }
-    if (pmsgLoggerWrite.context.fd < 0) {
+    if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
         if (access("/dev/pmsg0", W_OK) == 0) {
             return 0;
         }
@@ -115,7 +120,7 @@
         }
     }
 
-    if (pmsgLoggerWrite.context.fd < 0) {
+    if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
         return -EBADF;
     }
 
@@ -169,7 +174,8 @@
     }
     pmsgHeader.len += payloadSize;
 
-    ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+    ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd),
+                                    newVec, i));
     if (ret < 0) {
         ret = errno ? -errno : -ENOTCONN;
     }
@@ -206,7 +212,7 @@
         char prio,
         const char *filename,
         const char *buf, size_t len) {
-    int fd;
+    bool weOpened;
     size_t length, packet_len;
     const char *tag;
     char *cp, *slash;
@@ -228,16 +234,6 @@
         return -ENOMEM;
     }
 
-    fd = pmsgLoggerWrite.context.fd;
-    if (fd < 0) {
-        __android_log_lock();
-        fd = pmsgOpen();
-        __android_log_unlock();
-        if (fd < 0) {
-            return -EBADF;
-        }
-    }
-
     tag = cp;
     slash = strrchr(cp, '/');
     if (slash) {
@@ -256,6 +252,7 @@
     vec[1].iov_base = (unsigned char *)tag;
     vec[1].iov_len  = length;
 
+    weOpened = false;
     for (ts.tv_nsec = 0, length = len;
             length;
             ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
@@ -279,15 +276,36 @@
         vec[2].iov_base = (unsigned char *)buf;
         vec[2].iov_len  = transfer;
 
+        if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+            if (!weOpened) { /* Impossible for weOpened = true here */
+                __android_log_lock();
+            }
+            weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
+            if (!weOpened) {
+                __android_log_unlock();
+            } else if (pmsgOpen() < 0) {
+                __android_log_unlock();
+                return -EBADF;
+            }
+        }
+
         ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
 
         if (ret <= 0) {
+            if (weOpened) {
+                pmsgClose();
+                __android_log_unlock();
+            }
             free(cp);
-            return ret;
+            return ret ? ret : (len - length);
         }
         length -= transfer;
         buf += transfer;
     }
+    if (weOpened) {
+        pmsgClose();
+        __android_log_unlock();
+    }
     free(cp);
     return len;
 }
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index a755b98..158987a 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -28,7 +28,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 benchmark_src_files := \
     benchmark_main.cpp \
@@ -54,7 +53,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 test_src_files := \
     liblog_test.cpp
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 3d58147..f05a955 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <errno.h>
 #include <stdio.h>
 
 TEST(libc, __pstore_append) {
@@ -23,6 +24,22 @@
     ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
     static const char message[] = "libc.__pstore_append\n";
     ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
-    ASSERT_EQ(0, fclose(fp));
-    fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+    int fflushReturn = fflush(fp);
+    int fflushErrno = fflushReturn ? errno : 0;
+    ASSERT_EQ(0, fflushReturn);
+    ASSERT_EQ(0, fflushErrno);
+    int fcloseReturn = fclose(fp);
+    int fcloseErrno = fcloseReturn ? errno : 0;
+    ASSERT_EQ(0, fcloseReturn);
+    ASSERT_EQ(0, fcloseErrno);
+    if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
+        fprintf(stderr,
+                "Kernel does not have space allocated to pmsg pstore driver configured\n"
+               );
+    }
+    if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
+        fprintf(stderr,
+                "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
+               );
+    }
 }
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index cd012ce..44045c3 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -20,9 +20,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/sockets.h>
-#include <log/logger.h>
 #include <private/android_logger.h>
 
 #include "benchmark.h"
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index b1dae9e..02a572d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -16,23 +16,24 @@
 
 #include <ctype.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <semaphore.h>
 #include <signal.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <string>
 
-#include <android/log.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
-#include <log/logger.h>
 #include <log/logprint.h>
+#include <log/log_event_list.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -129,6 +130,70 @@
     ASSERT_LT(0, ret);
 }
 
+std::string popenToString(std::string command) {
+    std::string ret;
+
+    FILE* fp = popen(command.c_str(), "r");
+    if (fp) {
+        if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
+        pclose(fp);
+    }
+    return ret;
+}
+
+static bool isPmsgActive() {
+    pid_t pid = getpid();
+
+    std::string myPidFds = popenToString(android::base::StringPrintf(
+                                             "ls -l /proc/%d/fd", pid));
+    if (myPidFds.length() == 0) return true; // guess it is?
+
+    return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
+}
+
+static bool isLogdwActive() {
+    std::string logdwSignature = popenToString(
+        "grep /dev/socket/logdw /proc/net/unix");
+    size_t beginning = logdwSignature.find(" ");
+    if (beginning == std::string::npos) return true;
+    beginning = logdwSignature.find(" ", beginning + 1);
+    if (beginning == std::string::npos) return true;
+    size_t end = logdwSignature.find(" ", beginning + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    std::string allLogdwEndpoints = popenToString(
+        "grep ' 00000002" +
+        logdwSignature.substr(beginning, end - beginning) +
+        " ' /proc/net/unix | " +
+        "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
+    if (allLogdwEndpoints.length() == 0) return true;
+
+    // NB: allLogdwEndpoints has some false positives in it, but those
+    // strangers do not overlap with the simplistic activities inside this
+    // test suite.
+
+    pid_t pid = getpid();
+
+    std::string myPidFds = popenToString(android::base::StringPrintf(
+        "ls -l /proc/%d/fd", pid));
+    if (myPidFds.length() == 0) return true;
+
+    // NB: fgrep with multiple strings is broken in Android
+    for (beginning = 0;
+         (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+         beginning = end + 1) {
+        if (myPidFds.find(allLogdwEndpoints.substr(beginning,
+                                                   end - beginning)) !=
+            std::string::npos) return true;
+    }
+    return false;
+}
+
 TEST(liblog, __android_log_btwrite__android_logger_list_read) {
     struct logger_list *logger_list;
 
@@ -140,10 +205,22 @@
     // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+    bool logdwActiveAfter__android_log_btwrite = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
 
     log_time ts1(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+    pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+    logdwActiveAfter__android_log_btwrite = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     usleep(1000000);
 
     int count = 0;
@@ -252,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);
@@ -2571,16 +2651,59 @@
     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";
 
 TEST(liblog, __android_log_pmsg_file_write) {
+    __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
+            LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+            __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
+    EXPECT_LT(0, return__android_log_pmsg_file_write);
+    if (return__android_log_pmsg_file_write == -ENOMEM) {
+        fprintf(stderr,
+                "Kernel does not have space allocated to pmsg pstore driver configured\n"
+               );
+    } else if (!return__android_log_pmsg_file_write) {
+        fprintf(stderr, "Reboot, ensure file %s matches\n"
+                        "with liblog.__android_log_msg_file_read test\n",
+                        __pmsg_file);
+    }
+    bool pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+    bool logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
+    EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+                                         "TEST__android_log_pmsg_file_write",
+                                         "main"));
+    bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
+    bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
+    EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
     EXPECT_LT(0, __android_log_pmsg_file_write(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
-    fprintf(stderr, "Reboot, ensure file %s matches\n"
-                    "with liblog.__android_log_msg_file_read test\n",
-                    __pmsg_file);
+    pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+    logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
+    EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
 }
 
 ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
@@ -2597,7 +2720,7 @@
             strcmp(max_payload_buf, buf)) {
         fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
     }
-    return !arg ||
+    return arg ||
            (LOG_ID_CRASH != logId) ||
            (ANDROID_LOG_VERBOSE != prio) ||
            !strstr(__pmsg_file, filename) ||
@@ -2608,10 +2731,21 @@
 TEST(liblog, __android_log_pmsg_file_read) {
     signaled = 0;
 
+    __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+
     ssize_t ret = __android_log_pmsg_file_read(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, __pmsg_fn, NULL);
 
+    bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
+    bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
+    EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+
     if (ret == -ENOENT) {
         fprintf(stderr,
             "No pre-boot results of liblog.__android_log_mesg_file_write to "
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 98413dd..68c580a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -2,13 +2,19 @@
 
 cc_library_shared {
     name: "libmemtrack",
-    srcs: ["memtrack.c"],
+    srcs: ["memtrack.cpp"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
     include_dirs: ["hardware/libhardware/include"],
     shared_libs: [
         "libhardware",
         "liblog",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "android.hardware.memtrack@1.0",
     ],
     cflags: [
         "-Wall",
diff --git a/libmemtrack/include/memtrack/memtrack.h b/libmemtrack/include/memtrack/memtrack.h
index 8c0ab89..2134a6f 100644
--- a/libmemtrack/include/memtrack/memtrack.h
+++ b/libmemtrack/include/memtrack/memtrack.h
@@ -35,16 +35,6 @@
 struct memtrack_proc;
 
 /**
- * memtrack_init
- *
- * Must be called once before calling any other functions.  After this function
- * is called, everything else is thread-safe.
- *
- * Returns 0 on success, -errno on error.
- */
-int memtrack_init(void);
-
-/**
  * memtrack_proc_new
  *
  * Return a new handle to hold process memory stats.
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
deleted file mode 100644
index 29cc92c..0000000
--- a/libmemtrack/memtrack.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#define LOG_TAG "memtrack"
-
-#include <memtrack/memtrack.h>
-
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-
-#include <android/log.h>
-#include <hardware/memtrack.h>
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-static const memtrack_module_t *module;
-
-struct memtrack_proc {
-    pid_t pid;
-    struct memtrack_proc_type {
-        enum memtrack_type type;
-        size_t num_records;
-        size_t allocated_records;
-        struct memtrack_record *records;
-    } types[MEMTRACK_NUM_TYPES];
-};
-
-int memtrack_init(void)
-{
-    int err;
-
-    if (module) {
-        return 0;
-    }
-
-    err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
-            (hw_module_t const**)&module);
-    if (err) {
-        ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
-                strerror(-err));
-        return err;
-    }
-
-    return module->init(module);
-}
-
-struct memtrack_proc *memtrack_proc_new(void)
-{
-    if (!module) {
-        return NULL;
-    }
-
-    return calloc(sizeof(struct memtrack_proc), 1);
-}
-
-void memtrack_proc_destroy(struct memtrack_proc *p)
-{
-    enum memtrack_type i;
-
-    if (p) {
-        for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
-            free(p->types[i].records);
-        }
-    }
-    free(p);
-}
-
-static int memtrack_proc_get_type(struct memtrack_proc_type *t,
-            pid_t pid, enum memtrack_type type)
-{
-    size_t num_records = t->num_records;
-    int ret;
-
-retry:
-    ret = module->getMemory(module, pid, type, t->records, &num_records);
-    if (ret) {
-        t->num_records = 0;
-        return ret;
-    }
-    if (num_records > t->allocated_records) {
-        /* Need more records than allocated */
-        free(t->records);
-        t->records = calloc(sizeof(*t->records), num_records);
-        if (!t->records) {
-            return -ENOMEM;
-        }
-        t->allocated_records = num_records;
-        goto retry;
-    }
-    t->num_records = num_records;
-
-    return 0;
-}
-
-/* TODO: sanity checks on return values from HALs:
- *   make sure no records have invalid flags set
- *    - unknown flags
- *    - too many flags of a single category
- *    - missing ACCOUNTED/UNACCOUNTED
- *   make sure there are not overlapping SHARED and SHARED_PSS records
- */
-static int memtrack_proc_sanity_check(struct memtrack_proc *p)
-{
-    (void)p;
-    return 0;
-}
-
-int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
-{
-    enum memtrack_type i;
-
-    if (!module) {
-        return -EINVAL;
-    }
-
-    if (!p) {
-        return -EINVAL;
-    }
-
-    p->pid = pid;
-    for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
-        memtrack_proc_get_type(&p->types[i], pid, i);
-    }
-
-    return memtrack_proc_sanity_check(p);
-}
-
-static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
-            enum memtrack_type types[], size_t num_types,
-            unsigned int flags)
-{
-    ssize_t sum = 0;
-    size_t i;
-    size_t j;
-
-    for (i = 0; i < num_types; i++) {
-        enum memtrack_type type = types[i];
-        for (j = 0; j < p->types[type].num_records; j++) {
-            if ((p->types[type].records[j].flags & flags) == flags) {
-                sum += p->types[type].records[j].size_in_bytes;
-            }
-        }
-    }
-
-    return sum;
-}
-
-ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
-                                        MEMTRACK_TYPE_CAMERA,
-                                        MEMTRACK_TYPE_OTHER };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
-                                        MEMTRACK_TYPE_CAMERA,
-                                        MEMTRACK_TYPE_OTHER };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
diff --git a/libmemtrack/memtrack.cpp b/libmemtrack/memtrack.cpp
new file mode 100644
index 0000000..9b874da
--- /dev/null
+++ b/libmemtrack/memtrack.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+#define LOG_TAG "memtrack"
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+#include <memtrack/memtrack.h>
+
+#include <errno.h>
+#include <malloc.h>
+#include <vector>
+#include <string.h>
+#include <mutex>
+
+using android::hardware::memtrack::V1_0::IMemtrack;
+using android::hardware::memtrack::V1_0::MemtrackType;
+using android::hardware::memtrack::V1_0::MemtrackRecord;
+using android::hardware::memtrack::V1_0::MemtrackFlag;
+using android::hardware::memtrack::V1_0::MemtrackStatus;
+using android::hardware::hidl_vec;
+
+struct memtrack_proc_type {
+    MemtrackType type;
+    std::vector<MemtrackRecord> records;
+};
+
+struct memtrack_proc {
+    pid_t pid;
+    memtrack_proc_type types[static_cast<int>(MemtrackType::NUM_TYPES)];
+};
+
+//TODO(b/31632518)
+static android::sp<IMemtrack> get_instance() {
+    static android::sp<IMemtrack> module = IMemtrack::getService("memtrack");
+    if (module == nullptr) {
+        ALOGE("Couldn't load memtrack module");
+    }
+    return module;
+}
+
+memtrack_proc *memtrack_proc_new(void)
+{
+    return new memtrack_proc();
+}
+
+void memtrack_proc_destroy(memtrack_proc *p)
+{
+    delete(p);
+}
+
+static int memtrack_proc_get_type(memtrack_proc_type *t,
+        pid_t pid, MemtrackType type)
+{
+    int err = 0;
+    android::sp<IMemtrack> memtrack = get_instance();
+    if (memtrack == nullptr)
+        return -1;
+
+    memtrack->getMemory(pid, type,
+        [&t, &err](MemtrackStatus status, hidl_vec<MemtrackRecord> records) {
+            if (status != MemtrackStatus::SUCCESS) {
+                err = -1;
+                t->records.resize(0);
+            }
+            t->records.resize(records.size());
+            for (size_t i = 0; i < records.size(); i++) {
+                t->records[i].sizeInBytes = records[i].sizeInBytes;
+                t->records[i].flags = records[i].flags;
+            }
+    });
+    return err;
+}
+
+/* TODO: sanity checks on return values from HALs:
+ *   make sure no records have invalid flags set
+ *    - unknown flags
+ *    - too many flags of a single category
+ *    - missing ACCOUNTED/UNACCOUNTED
+ *   make sure there are not overlapping SHARED and SHARED_PSS records
+ */
+static int memtrack_proc_sanity_check(memtrack_proc* /*p*/)
+{
+    return 0;
+}
+
+int memtrack_proc_get(memtrack_proc *p, pid_t pid)
+{
+    if (!p) {
+        return -EINVAL;
+    }
+
+    p->pid = pid;
+    for (uint32_t i = 0; i < (uint32_t)MemtrackType::NUM_TYPES; i++) {
+        int ret = memtrack_proc_get_type(&p->types[i], pid, (MemtrackType)i);
+        if (ret != 0)
+           return ret;
+    }
+
+    return memtrack_proc_sanity_check(p);
+}
+
+static ssize_t memtrack_proc_sum(memtrack_proc *p,
+        const std::vector<MemtrackType>& types, uint32_t flags)
+{
+    ssize_t sum = 0;
+
+    for (size_t i = 0; i < types.size(); i++) {
+        memtrack_proc_type type = p->types[static_cast<int>(types[i])];
+        std::vector<MemtrackRecord> records = type.records;
+        for (size_t j = 0; j < records.size(); j++) {
+            if ((records[j].flags & flags) == flags) {
+                sum += records[j].sizeInBytes;
+            }
+        }
+    }
+
+    return sum;
+}
+
+ssize_t memtrack_proc_graphics_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = {MemtrackType::GRAPHICS};
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_graphics_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GRAPHICS };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_gl_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GL };
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_gl_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GL };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_other_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+            MemtrackType::CAMERA, MemtrackType::OTHER };
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_other_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+            MemtrackType::CAMERA, MemtrackType::OTHER };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
index eaadfa7..77c935e 100644
--- a/libmemtrack/memtrack_test.c
+++ b/libmemtrack/memtrack_test.c
@@ -82,12 +82,6 @@
     (void)argc;
     (void)argv;
 
-    ret = memtrack_init();
-    if (ret < 0) {
-        fprintf(stderr, "failed to initialize HAL: %s (%d)\n", strerror(-ret), ret);
-        exit(EXIT_FAILURE);
-    }
-
     ret = pm_kernel_create(&ker);
     if (ret) {
         fprintf(stderr, "Error creating kernel interface -- "
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 85bc421..4662368 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -2,7 +2,6 @@
     name: "libmemunreachable_defaults",
 
     cflags: [
-        "-std=c++14",
         "-Wall",
         "-Wextra",
         "-Werror",
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 598dfcd..5fb56f2 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -12,7 +12,6 @@
         "-Wall",
     ],
     cppflags: [
-        "-std=gnu++11",
         "-fvisibility=protected",
     ],
 
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 9f9c83f..eafc53d 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "nativebridge"
+
 #include "nativebridge/native_bridge.h"
 
 #include <dlfcn.h>
@@ -22,6 +24,7 @@
 #include <stdio.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include <cstring>
 
@@ -77,6 +80,19 @@
 // Current state of the native bridge.
 static NativeBridgeState state = NativeBridgeState::kNotSetup;
 
+// The version of NativeBridge implementation.
+// Different Nativebridge interface needs the service of different version of
+// Nativebridge implementation.
+// Used by isCompatibleWith() which is introduced in v2.
+enum NativeBridgeImplementationVersion {
+    // first version, not used.
+    DEFAULT_VERSION = 1,
+    // The version which signal semantic is introduced.
+    SIGNAL_VERSION = 2,
+    // The version which namespace semantic is introduced.
+    NAMESPACE_VERSION = 3,
+};
+
 // Whether we had an error at some point.
 static bool had_error = false;
 
@@ -97,8 +113,6 @@
 // and hard code the directory name again here.
 static constexpr const char* kCodeCacheDir = "code_cache";
 
-static constexpr uint32_t kLibNativeBridgeVersion = 2;
-
 // Characters allowed in a native bridge filename. The first character must
 // be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
 static bool CharacterAllowed(char c, bool first) {
@@ -149,19 +163,18 @@
   }
 }
 
-static bool VersionCheck(const NativeBridgeCallbacks* cb) {
+// The policy of invoking Nativebridge changed in v3 with/without namespace.
+// Suggest Nativebridge implementation not maintain backward-compatible.
+static bool isCompatibleWith(const uint32_t version) {
   // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
   // version.
-  if (cb == nullptr || cb->version == 0) {
+  if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
     return false;
   }
 
   // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
-  if (cb->version >= 2) {
-    if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
-      // TODO: Scan which version is supported, and fall back to handle it.
-      return false;
-    }
+  if (callbacks->version >= SIGNAL_VERSION) {
+    return callbacks->isCompatibleWith(version);
   }
 
   return true;
@@ -202,7 +215,7 @@
         callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
                                                                    kNativeBridgeInterfaceSymbol));
         if (callbacks != nullptr) {
-          if (VersionCheck(callbacks)) {
+          if (isCompatibleWith(NAMESPACE_VERSION)) {
             // Store the handle for later.
             native_bridge_handle = handle;
           } else {
@@ -517,8 +530,91 @@
 }
 
 NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
-  if (NativeBridgeInitialized() && callbacks->version >= 2) {
-    return callbacks->getSignalHandler(signal);
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(SIGNAL_VERSION)) {
+      return callbacks->getSignalHandler(signal);
+    } else {
+      ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
+    }
+  }
+  return nullptr;
+}
+
+int NativeBridgeUnloadLibrary(void* handle) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->unloadLibrary(handle);
+    } else {
+      ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
+    }
+  }
+  return -1;
+}
+
+const char* NativeBridgeGetError() {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->getError();
+    } else {
+      return "native bridge implementation is not compatible with version 3, cannot get message";
+    }
+  }
+  return "native bridge is not initialized";
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->isPathSupported(path);
+    } else {
+      ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
+    }
+  }
+  return false;
+}
+
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+                               const char* anon_ns_library_path) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+    } else {
+      ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+    }
+  }
+
+  return false;
+}
+
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+                                                       const char* ld_library_path,
+                                                       const char* default_library_path,
+                                                       uint64_t type,
+                                                       const char* permitted_when_isolated_path,
+                                                       native_bridge_namespace_t* parent_ns) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->createNamespace(name,
+                                        ld_library_path,
+                                        default_library_path,
+                                        type,
+                                        permitted_when_isolated_path,
+                                        parent_ns);
+    } else {
+      ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
+    }
+  }
+
+  return nullptr;
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->loadLibraryExt(libpath, flag, ns);
+    } else {
+      ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
+    }
   }
   return nullptr;
 }
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 7265939..4c3e862 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -20,7 +20,13 @@
     PreInitializeNativeBridgeFail2_test.cpp \
     ReSetupNativeBridge_test.cpp \
     UnavailableNativeBridge_test.cpp \
-    ValidNameNativeBridge_test.cpp
+    ValidNameNativeBridge_test.cpp \
+    NativeBridge3UnloadLibrary_test.cpp \
+    NativeBridge3GetError_test.cpp \
+    NativeBridge3IsPathSupported_test.cpp \
+    NativeBridge3InitNamespace_test.cpp \
+    NativeBridge3CreateNamespace_test.cpp \
+    NativeBridge3LoadLibraryExt_test.cpp
 
 
 shared_libraries := \
@@ -31,7 +37,6 @@
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_CLANG := true) \
-    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -41,7 +46,6 @@
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_CLANG := true) \
-    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index 551765a..2d78be0 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -12,7 +12,7 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
 LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_MULTILIB := both
 
@@ -27,7 +27,7 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
 
@@ -48,7 +48,7 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
 LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_MULTILIB := both
 
@@ -63,8 +63,46 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# v3.
+
+NATIVE_BRIDGE3_COMMON_SRC_FILES := \
+  DummyNativeBridge3.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
 
 include $(BUILD_HOST_SHARED_LIBRARY)
+
+
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
new file mode 100644
index 0000000..13fce85
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+#include <signal.h>
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge3_initialize(
+                      const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+                      const char* /* app_code_cache_dir */,
+                      const char* /* isa */) {
+  return true;
+}
+
+extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
+  return nullptr;
+}
+
+extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
+                                             const char* /* shorty */, uint32_t /* len */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
+  return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
+    const char* /* abi */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
+  // For testing, allow 1-3, but disallow 4+.
+  return version <= 3;
+}
+
+static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
+  // TODO: Implement something here. We'd either have to have a death test with a log here, or
+  //       we'd have to be able to resume after the faulting instruction...
+  return true;
+}
+
+extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
+  if (signal == SIGSEGV) {
+    return &native_bridge3_dummy_signal_handler;
+  }
+  return nullptr;
+}
+
+extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
+  return 0;
+}
+
+extern "C" const char* native_bridge3_getError() {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
+  return true;
+}
+
+extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
+                                        const char* /* anon_ns_library_path */) {
+  return true;
+}
+
+extern "C" android::native_bridge_namespace_t*
+native_bridge3_createNamespace(const char* /* name */,
+                               const char* /* ld_library_path */,
+                               const char* /* default_library_path */,
+                               uint64_t /* type */,
+                               const char* /* permitted_when_isolated_path */,
+                               android::native_bridge_namespace_t* /* parent_ns */) {
+  return nullptr;
+}
+
+extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
+                                               int /* flag */,
+                                               android::native_bridge_namespace_t* /* ns */) {
+  return nullptr;
+}
+
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+  // v1
+  .version = 3,
+  .initialize = &native_bridge3_initialize,
+  .loadLibrary = &native_bridge3_loadLibrary,
+  .getTrampoline = &native_bridge3_getTrampoline,
+  .isSupported = &native_bridge3_isSupported,
+  .getAppEnv = &native_bridge3_getAppEnv,
+  // v2
+  .isCompatibleWith = &native_bridge3_isCompatibleWith,
+  .getSignalHandler = &native_bridge3_getSignalHandler,
+  // v3
+  .unloadLibrary = &native_bridge3_unloadLibrary,
+  .getError = &native_bridge3_getError,
+  .isPathSupported  = &native_bridge3_isPathSupported,
+  .initNamespace = &native_bridge3_initNamespace,
+  .createNamespace = &native_bridge3_createNamespace,
+  .loadLibraryExt = &native_bridge3_loadLibraryExt
+};
+
diff --git a/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
new file mode 100644
index 0000000..668d942
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_CreateNamespace) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
+                                                   0, nullptr, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3GetError_test.cpp b/libnativebridge/tests/NativeBridge3GetError_test.cpp
new file mode 100644
index 0000000..0b9f582
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3GetError_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_GetError) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeGetError());
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
new file mode 100644
index 0000000..ae0fd2b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitNamespace) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
new file mode 100644
index 0000000..325e40b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_IsPathSupported) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(true, NativeBridgeIsPathSupported(nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
new file mode 100644
index 0000000..4caeb44
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
new file mode 100644
index 0000000..93a979c
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(0, NativeBridgeUnloadLibrary(nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
index d489420..0f99816 100644
--- a/libnativebridge/tests/NativeBridgeTest.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -25,6 +25,8 @@
 constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
 constexpr const char* kCodeCache = "./code_cache";
 constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
+constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
 
 namespace android {
 
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b4a69bc..9d33899 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -8,6 +8,7 @@
         "libnativehelper",
         "liblog",
         "libcutils",
+        "libnativebridge",
     ],
     static_libs: ["libbase"],
     target: {
@@ -24,7 +25,6 @@
         "-Wall",
     ],
     cppflags: [
-        "-std=gnu++14",
         "-fvisibility=hidden",
     ],
     export_include_dirs: ["include"],
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 2a6aaec..99ae3a7 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,7 @@
 
 #include "jni.h"
 #include <stdint.h>
+#include <string>
 #if defined(__ANDROID__)
 #include <android/dlext.h>
 #endif
@@ -41,10 +42,12 @@
                         int32_t target_sdk_version,
                         const char* path,
                         jobject class_loader,
-                        jstring library_path);
+                        jstring library_path,
+                        bool* needs_native_bridge,
+                        std::string* error_msg);
 
 __attribute__((visibility("default")))
-bool CloseNativeLibrary(void* handle);
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
 
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 3a6e54d..15fe054 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -24,6 +24,7 @@
 #include "android/log.h"
 #include "cutils/properties.h"
 #endif
+#include "nativebridge/native_bridge.h"
 
 #include <algorithm>
 #include <vector>
@@ -34,11 +35,53 @@
 #include <android-base/macros.h>
 #include <android-base/strings.h>
 
+#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
+                                             "%s:%d: %s CHECK '" #predicate "' failed.",\
+                                             __FILE__, __LINE__, __FUNCTION__)
+
 namespace android {
 
 #if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
-static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+class NativeLoaderNamespace {
+ public:
+  NativeLoaderNamespace()
+      : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+
+  explicit NativeLoaderNamespace(android_namespace_t* ns)
+      : android_ns_(ns), native_bridge_ns_(nullptr) { }
+
+  explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+      : android_ns_(nullptr), native_bridge_ns_(ns) { }
+
+  NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
+  NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
+
+  NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
+
+  android_namespace_t* get_android_ns() const {
+    CHECK(native_bridge_ns_ == nullptr);
+    return android_ns_;
+  }
+
+  native_bridge_namespace_t* get_native_bridge_ns() const {
+    CHECK(android_ns_ == nullptr);
+    return native_bridge_ns_;
+  }
+
+  bool is_android_namespace() const {
+    return native_bridge_ns_ == nullptr;
+  }
+
+ private:
+  // Only one of them can be not null
+  android_namespace_t* android_ns_;
+  native_bridge_namespace_t* native_bridge_ns_;
+};
+
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
+                                  "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig =
+                                  "/vendor/etc/public.libraries.txt";
 
 // (http://b/27588281) This is a workaround for apps using custom classloaders and calling
 // System.load() with an absolute path which is outside of the classloader library search path.
@@ -55,11 +98,13 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  android_namespace_t* Create(JNIEnv* env,
-                              jobject class_loader,
-                              bool is_shared,
-                              jstring java_library_path,
-                              jstring java_permitted_path) {
+  bool Create(JNIEnv* env,
+              jobject class_loader,
+              bool is_shared,
+              jstring java_library_path,
+              jstring java_permitted_path,
+              NativeLoaderNamespace* ns,
+              std::string* error_msg) {
     std::string library_path; // empty string by default.
 
     if (java_library_path != nullptr) {
@@ -82,13 +127,13 @@
       }
     }
 
-    if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
-      return nullptr;
+    if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+      return false;
     }
 
-    android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
+    bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
 
-    LOG_ALWAYS_FATAL_IF(ns != nullptr,
+    LOG_ALWAYS_FATAL_IF(found,
                         "There is already a namespace associated with this classloader");
 
     uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -96,28 +141,66 @@
       namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
     }
 
-    android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+    NativeLoaderNamespace parent_ns;
+    bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
 
-    ns = android_create_namespace("classloader-namespace",
-                                  nullptr,
-                                  library_path.c_str(),
-                                  namespace_type,
-                                  permitted_path.c_str(),
-                                  parent_ns);
+    bool is_native_bridge = false;
 
-    if (ns != nullptr) {
-      namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+    if (found_parent_namespace) {
+      is_native_bridge = !parent_ns.is_android_namespace();
+    } else if (!library_path.empty()) {
+      is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
     }
 
-    return ns;
+    NativeLoaderNamespace native_loader_ns;
+    if (!is_native_bridge) {
+      android_namespace_t* ns = android_create_namespace("classloader-namespace",
+                                                         nullptr,
+                                                         library_path.c_str(),
+                                                         namespace_type,
+                                                         permitted_path.c_str(),
+                                                         parent_ns.get_android_ns());
+      if (ns == nullptr) {
+        *error_msg = dlerror();
+        return false;
+      }
+
+      native_loader_ns = NativeLoaderNamespace(ns);
+    } else {
+      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+                                                                  nullptr,
+                                                                  library_path.c_str(),
+                                                                  namespace_type,
+                                                                  permitted_path.c_str(),
+                                                                  parent_ns.get_native_bridge_ns());
+      if (ns == nullptr) {
+        *error_msg = NativeBridgeGetError();
+        return false;
+      }
+
+      native_loader_ns = NativeLoaderNamespace(ns);
+    }
+
+    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+    *ns = native_loader_ns;
+    return true;
   }
 
-  android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
     auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
-                [&](const std::pair<jweak, android_namespace_t*>& value) {
+                [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
                   return env->IsSameObject(value.first, class_loader);
                 });
-    return it != namespaces_.end() ? it->second : nullptr;
+    if (it != namespaces_.end()) {
+      if (ns != nullptr) {
+        *ns = it->second;
+      }
+
+      return true;
+    }
+
+    return false;
   }
 
   void Initialize() {
@@ -217,12 +300,29 @@
     return true;
   }
 
-  bool InitPublicNamespace(const char* library_path) {
+  bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
+    // Ask native bride if this apps library path should be handled by it
+    bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
     // namespace which is the library_path of the classloader.
-    initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+    initialized_ = android_init_namespaces(public_libraries_.c_str(),
+                                           is_native_bridge ? nullptr : library_path);
+    if (!initialized_) {
+      *error_msg = dlerror();
+      return false;
+    }
+
+    // and now initialize native bridge namespaces if necessary.
+    if (NativeBridgeInitialized()) {
+      initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
+                                               is_native_bridge ? library_path : nullptr);
+      if (!initialized_) {
+        *error_msg = NativeBridgeGetError();
+      }
+    }
 
     return initialized_;
   }
@@ -236,22 +336,24 @@
     return env->CallObjectMethod(class_loader, get_parent);
   }
 
-  android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  bool FindParentNamespaceByClassLoader(JNIEnv* env,
+                                        jobject class_loader,
+                                        NativeLoaderNamespace* ns) {
     jobject parent_class_loader = GetParentClassLoader(env, class_loader);
 
     while (parent_class_loader != nullptr) {
-      android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
-      if (ns != nullptr) {
-        return ns;
+      if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
+        return true;
       }
 
       parent_class_loader = GetParentClassLoader(env, parent_class_loader);
     }
-    return nullptr;
+
+    return false;
   }
 
   bool initialized_;
-  std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+  std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string public_libraries_;
 
 
@@ -285,13 +387,18 @@
 #if defined(__ANDROID__)
   UNUSED(target_sdk_version);
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  android_namespace_t* ns = g_namespaces->Create(env,
-                                                 class_loader,
-                                                 is_shared,
-                                                 library_path,
-                                                 permitted_path);
-  if (ns == nullptr) {
-    return env->NewStringUTF(dlerror());
+
+  std::string error_msg;
+  NativeLoaderNamespace ns;
+  bool success = g_namespaces->Create(env,
+                                      class_loader,
+                                      is_shared,
+                                      library_path,
+                                      permitted_path,
+                                      &ns,
+                                      &error_msg);
+  if (!success) {
+    return env->NewStringUTF(error_msg.c_str());
   }
 #else
   UNUSED(env, target_sdk_version, class_loader, is_shared,
@@ -304,44 +411,83 @@
                         int32_t target_sdk_version,
                         const char* path,
                         jobject class_loader,
-                        jstring library_path) {
+                        jstring library_path,
+                        bool* needs_native_bridge,
+                        std::string* error_msg) {
 #if defined(__ANDROID__)
   UNUSED(target_sdk_version);
   if (class_loader == nullptr) {
+    *needs_native_bridge = false;
     return dlopen(path, RTLD_NOW);
   }
 
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+  NativeLoaderNamespace ns;
 
-  if (ns == nullptr) {
+  if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
     // This is the case where the classloader was not created by ApplicationLoaders
     // In this case we create an isolated not-shared namespace for it.
-    ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
-    if (ns == nullptr) {
+    if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
       return nullptr;
     }
   }
 
-  android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
-  extinfo.library_namespace = ns;
+  if (ns.is_android_namespace()) {
+    android_dlextinfo extinfo;
+    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+    extinfo.library_namespace = ns.get_android_ns();
 
-  return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+    if (handle == nullptr) {
+      *error_msg = dlerror();
+    }
+    *needs_native_bridge = false;
+    return handle;
+  } else {
+    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
+    if (handle == nullptr) {
+      *error_msg = NativeBridgeGetError();
+    }
+    *needs_native_bridge = true;
+    return handle;
+  }
 #else
   UNUSED(env, target_sdk_version, class_loader, library_path);
-  return dlopen(path, RTLD_NOW);
+  *needs_native_bridge = false;
+  void* handle = dlopen(path, RTLD_NOW);
+  if (handle == nullptr) {
+    if (NativeBridgeIsSupported(path)) {
+      *needs_native_bridge = true;
+      handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
+      if (handle == nullptr) {
+        *error_msg = NativeBridgeGetError();
+      }
+    } else {
+      *needs_native_bridge = false;
+      *error_msg = dlerror();
+    }
+  }
+  return handle;
 #endif
 }
 
-bool CloseNativeLibrary(void* handle) {
-  return dlclose(handle) == 0;
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
+    return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
+                                 dlclose(handle);
 }
 
 #if defined(__ANDROID__)
+// native_bridge_namespaces are not supported for callers of this function.
+// This function will return nullptr in the case when application is running
+// on native bridge.
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+  NativeLoaderNamespace ns;
+  if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+    return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+  }
+
+  return nullptr;
 }
 #endif
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index 67eba80..e212f1b 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -14,6 +14,7 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
+#define LOG_TAG "pixelflinger-code"
 
 #include <errno.h>
 #include <stdint.h>
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index d4aa475..092f140 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index d68f6dc..b8a0e55 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdio.h>
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index d66981d..f4f4657 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
index f00e50a..fa6338a 100644
--- a/libpixelflinger/trap.cpp
+++ b/libpixelflinger/trap.cpp
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "pixelflinger-trap"
+
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
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/libsparse/output_file.c b/libsparse/output_file.c
index d284736..2115998 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -34,7 +34,7 @@
 #include "sparse_crc32.h"
 #include "sparse_format.h"
 
-#ifndef USE_MINGW
+#ifndef _WIN32
 #include <sys/mman.h>
 #define O_BINARY 0
 #else
@@ -63,7 +63,7 @@
 	int (*open)(struct output_file *, int fd);
 	int (*skip)(struct output_file *, int64_t);
 	int (*pad)(struct output_file *, int64_t);
-	int (*write)(struct output_file *, void *, int);
+	int (*write)(struct output_file *, void *, size_t);
 	void (*close)(struct output_file *);
 };
 
@@ -149,18 +149,23 @@
 	return 0;
 }
 
-static int file_write(struct output_file *out, void *data, int len)
+static int file_write(struct output_file *out, void *data, size_t len)
 {
-	int ret;
+	ssize_t ret;
 	struct output_file_normal *outn = to_output_file_normal(out);
 
-	ret = write(outn->fd, data, len);
-	if (ret < 0) {
-		error_errno("write");
-		return -1;
-	} else if (ret < len) {
-		error("incomplete write");
-		return -1;
+	while (len > 0) {
+		ret = write(outn->fd, data, len);
+		if (ret < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			error_errno("write");
+			return -1;
+		}
+
+		data = (char *)data + ret;
+		len -= ret;
 	}
 
 	return 0;
@@ -232,18 +237,20 @@
 	return 0;
 }
 
-static int gz_file_write(struct output_file *out, void *data, int len)
+static int gz_file_write(struct output_file *out, void *data, size_t len)
 {
 	int ret;
 	struct output_file_gz *outgz = to_output_file_gz(out);
 
-	ret = gzwrite(outgz->gz_fd, data, len);
-	if (ret < 0) {
-		error_errno("gzwrite");
-		return -1;
-	} else if (ret < len) {
-		error("incomplete gzwrite");
-		return -1;
+	while (len > 0) {
+		ret = gzwrite(outgz->gz_fd, data,
+			      min(len, (unsigned int)INT_MAX));
+		if (ret == 0) {
+			error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
+			return -1;
+		}
+		len -= ret;
+		data = (char *)data + ret;
 	}
 
 	return 0;
@@ -293,7 +300,7 @@
 	return -1;
 }
 
-static int callback_file_write(struct output_file *out, void *data, int len)
+static int callback_file_write(struct output_file *out, void *data, size_t len)
 {
 	struct output_file_callback *outc = to_output_file_callback(out);
 
@@ -698,14 +705,16 @@
 	int ret;
 	int64_t aligned_offset;
 	int aligned_diff;
-	int buffer_size;
+	uint64_t buffer_size;
 	char *ptr;
 
 	aligned_offset = offset & ~(4096 - 1);
 	aligned_diff = offset - aligned_offset;
-	buffer_size = len + aligned_diff;
+	buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
 
-#ifndef USE_MINGW
+#ifndef _WIN32
+	if (buffer_size > SIZE_MAX)
+		return -E2BIG;
 	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
 			aligned_offset);
 	if (data == MAP_FAILED) {
@@ -733,7 +742,7 @@
 
 	ret = out->sparse_ops->write_data_chunk(out, len, ptr);
 
-#ifndef USE_MINGW
+#ifndef _WIN32
 	munmap(data, buffer_size);
 #else
 	free(data);
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
index c70d45f..82a03ad 100755
--- a/libsparse/simg_dump.py
+++ b/libsparse/simg_dump.py
@@ -15,43 +15,64 @@
 # limitations under the License.
 
 from __future__ import print_function
-import getopt, posixpath, signal, struct, sys
+import csv
+import getopt
+import hashlib
+import posixpath
+import signal
+import struct
+import sys
+
 
 def usage(argv0):
   print("""
-Usage: %s [-v] sparse_image_file ...
+Usage: %s [-v] [-s] [-c <filename>] sparse_image_file ...
  -v             verbose output
-""" % ( argv0 ))
+ -s             show sha1sum of data blocks
+ -c <filename>  save .csv file of blocks
+""" % (argv0))
   sys.exit(2)
 
-def main():
 
+def main():
   signal.signal(signal.SIGPIPE, signal.SIG_DFL)
 
   me = posixpath.basename(sys.argv[0])
 
   # Parse the command line
-  verbose = 0			# -v
+  verbose = 0                   # -v
+  showhash = 0                  # -s
+  csvfilename = None            # -c
   try:
     opts, args = getopt.getopt(sys.argv[1:],
-                               "v",
-                               ["verbose"])
+                               "vsc:",
+                               ["verbose", "showhash", "csvfile"])
   except getopt.GetoptError, e:
     print(e)
     usage(me)
   for o, a in opts:
     if o in ("-v", "--verbose"):
       verbose += 1
+    elif o in ("-s", "--showhash"):
+      showhash = True
+    elif o in ("-c", "--csvfile"):
+      csvfilename = a
     else:
       print("Unrecognized option \"%s\"" % (o))
       usage(me)
 
-  if len(args) == 0:
+  if not args:
     print("No sparse_image_file specified")
     usage(me)
 
+  if csvfilename:
+    csvfile = open(csvfilename, "wb")
+    csvwriter = csv.writer(csvfile)
+
+  output = verbose or csvfilename or showhash
+
   for path in args:
-    FH = open(path, 'rb')
+    FH = open(path, "rb")
     header_bin = FH.read(28)
     header = struct.unpack("<I4H4I", header_bin)
 
@@ -88,71 +109,99 @@
     if image_checksum != 0:
       print("checksum=0x%08X" % (image_checksum))
 
-    if not verbose:
+    if not output:
       continue
-    print("            input_bytes      output_blocks")
-    print("chunk    offset     number  offset  number")
+
+    if verbose > 0:
+      print("            input_bytes      output_blocks")
+      print("chunk    offset     number  offset  number")
+
+    if csvfilename:
+      csvwriter.writerow(["chunk", "input offset", "input bytes",
+                          "output offset", "output blocks", "type", "hash"])
+
     offset = 0
-    for i in xrange(1,total_chunks+1):
+    for i in xrange(1, total_chunks + 1):
       header_bin = FH.read(12)
       header = struct.unpack("<2H2I", header_bin)
       chunk_type = header[0]
-      reserved1 = header[1]
       chunk_sz = header[2]
       total_sz = header[3]
       data_sz = total_sz - 12
+      curhash = ""
+      curtype = ""
+      curpos = FH.tell()
 
-      print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
-            end=" ")
+      if verbose > 0:
+        print("%4u %10u %10u %7u %7u" % (i, curpos, data_sz, offset, chunk_sz),
+              end=" ")
 
       if chunk_type == 0xCAC1:
         if data_sz != (chunk_sz * blk_sz):
           print("Raw chunk input size (%u) does not match output size (%u)"
                 % (data_sz, chunk_sz * blk_sz))
-          break;
+          break
         else:
-          print("Raw data", end="")
-          FH.read(data_sz)
+          curtype = "Raw data"
+          data = FH.read(data_sz)
+          if showhash:
+            h = hashlib.sha1()
+            h.update(data)
+            curhash = h.hexdigest()
       elif chunk_type == 0xCAC2:
         if data_sz != 4:
           print("Fill chunk should have 4 bytes of fill, but this has %u"
-                % (data_sz), end="")
-          break;
+                % (data_sz))
+          break
         else:
           fill_bin = FH.read(4)
           fill = struct.unpack("<I", fill_bin)
-          print("Fill with 0x%08X" % (fill))
+          curtype = format("Fill with 0x%08X" % (fill))
+          if showhash:
+            h = hashlib.sha1()
+            data = fill_bin * (blk_sz / 4);
+            for block in xrange(chunk_sz):
+              h.update(data)
+            curhash = h.hexdigest()
       elif chunk_type == 0xCAC3:
         if data_sz != 0:
           print("Don't care chunk input size is non-zero (%u)" % (data_sz))
-          break;
+          break
         else:
-          print("Don't care", end="")
+          curtype = "Don't care"
       elif chunk_type == 0xCAC4:
         if data_sz != 4:
           print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
-                % (data_sz), end="")
-          break;
+                % (data_sz))
+          break
         else:
           crc_bin = FH.read(4)
           crc = struct.unpack("<I", crc_bin)
-          print("Unverified CRC32 0x%08X" % (crc))
+          curtype = format("Unverified CRC32 0x%08X" % (crc))
       else:
-          print("Unknown chunk type 0x%04X" % (chunk_type), end="")
-          break;
+        print("Unknown chunk type 0x%04X" % (chunk_type))
+        break
 
-      if verbose > 1:
-        header = struct.unpack("<12B", header_bin)
-        print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
-              % (header[0], header[1], header[2], header[3],
-                 header[4], header[5], header[6], header[7],
-                 header[8], header[9], header[10], header[11]))
-      else:
-        print()
+      if verbose > 0:
+        print("%-18s" % (curtype), end=" ")
+
+        if verbose > 1:
+          header = struct.unpack("<12B", header_bin)
+          print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
+                % (header[0], header[1], header[2], header[3],
+                   header[4], header[5], header[6], header[7],
+                   header[8], header[9], header[10], header[11]), end=" ")
+
+        print(curhash)
+
+      if csvfilename:
+        csvwriter.writerow([i, curpos, data_sz, offset, chunk_sz, curtype,
+                            curhash])
 
       offset += chunk_sz
 
-    print("     %10u            %7u         End" % (FH.tell(), offset))
+    if verbose > 0:
+      print("     %10u            %7u         End" % (FH.tell(), offset))
 
     if total_blks != offset:
       print("The header said we should have %u output blocks, but we saw %u"
@@ -163,6 +212,9 @@
       print("There were %u bytes of extra data at the end of the file."
             % (junk_len))
 
+  if csvfilename:
+    csvfile.close()
+
   sys.exit(0)
 
 if __name__ == "__main__":
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index dbb4dab..a188202 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -79,7 +79,7 @@
 		s = " at ";
 	}
 	if (verbose) {
-#ifndef USE_MINGW
+#ifndef _WIN32
 		if (err == -EOVERFLOW) {
 			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
 		} else
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index d27ceea..d442c94 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -4,8 +4,6 @@
     name: "libsuspend",
     srcs: [
         "autosuspend.c",
-        "autosuspend_autosleep.c",
-        "autosuspend_earlysuspend.c",
         "autosuspend_wakeup_count.c",
     ],
     export_include_dirs: ["include"],
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 64d1bfc..2e1983a 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -34,19 +34,6 @@
         return 0;
     }
 
-    autosuspend_ops = autosuspend_earlysuspend_init();
-    if (autosuspend_ops) {
-        goto out;
-    }
-
-/* Remove autosleep so userspace can manager suspend/resume and keep stats */
-#if 0
-    autosuspend_ops = autosuspend_autosleep_init();
-    if (autosuspend_ops) {
-        goto out;
-    }
-#endif
-
     autosuspend_ops = autosuspend_wakeup_count_init();
     if (autosuspend_ops) {
         goto out;
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
deleted file mode 100644
index 97109ac..0000000
--- a/libsuspend/autosuspend_autosleep.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
-
-static int autosleep_fd;
-static const char *sleep_state = "mem";
-static const char *on_state = "off";
-
-static int autosuspend_autosleep_enable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_autosleep_enable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        goto err;
-    }
-
-    ALOGV("autosuspend_autosleep_enable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-static int autosuspend_autosleep_disable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_autosleep_disable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        goto err;
-    }
-
-    ALOGV("autosuspend_autosleep_disable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-struct autosuspend_ops autosuspend_autosleep_ops = {
-        .enable = autosuspend_autosleep_enable,
-        .disable = autosuspend_autosleep_disable,
-};
-
-struct autosuspend_ops *autosuspend_autosleep_init(void)
-{
-    char buf[80];
-
-    autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
-    if (autosleep_fd < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        return NULL;
-    }
-
-    ALOGI("Selected autosleep\n");
-
-    autosuspend_autosleep_disable();
-
-    return &autosuspend_autosleep_ops;
-}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
deleted file mode 100644
index 9519e51..0000000
--- a/libsuspend/autosuspend_earlysuspend.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "autosuspend_ops.h"
-
-#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
-#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
-#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
-
-static int sPowerStatefd;
-static const char *pwr_state_mem = "mem";
-static const char *pwr_state_on = "on";
-static pthread_t earlysuspend_thread;
-static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
-static bool wait_for_earlysuspend;
-static enum {
-    EARLYSUSPEND_ON,
-    EARLYSUSPEND_MEM,
-} earlysuspend_state = EARLYSUSPEND_ON;
-
-int wait_for_fb_wake(void)
-{
-    int err = 0;
-    char buf;
-    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
-    // if the file doesn't exist, the error will be caught in read() below
-    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
-    ALOGE_IF(err < 0,
-            "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
-    close(fd);
-    return err < 0 ? err : 0;
-}
-
-static int wait_for_fb_sleep(void)
-{
-    int err = 0;
-    char buf;
-    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
-    // if the file doesn't exist, the error will be caught in read() below
-    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
-    ALOGE_IF(err < 0,
-            "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
-    close(fd);
-    return err < 0 ? err : 0;
-}
-
-static void *earlysuspend_thread_func(void __unused *arg)
-{
-    while (1) {
-        if (wait_for_fb_sleep()) {
-            ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
-            return NULL;
-        }
-        pthread_mutex_lock(&earlysuspend_mutex);
-        earlysuspend_state = EARLYSUSPEND_MEM;
-        pthread_cond_signal(&earlysuspend_cond);
-        pthread_mutex_unlock(&earlysuspend_mutex);
-
-        if (wait_for_fb_wake()) {
-            ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
-            return NULL;
-        }
-        pthread_mutex_lock(&earlysuspend_mutex);
-        earlysuspend_state = EARLYSUSPEND_ON;
-        pthread_cond_signal(&earlysuspend_cond);
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-}
-static int autosuspend_earlysuspend_enable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_earlysuspend_enable\n");
-
-    ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err;
-    }
-
-    if (wait_for_earlysuspend) {
-        pthread_mutex_lock(&earlysuspend_mutex);
-        while (earlysuspend_state != EARLYSUSPEND_MEM) {
-            pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
-        }
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-
-    ALOGV("autosuspend_earlysuspend_enable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-static int autosuspend_earlysuspend_disable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_earlysuspend_disable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err;
-    }
-
-    if (wait_for_earlysuspend) {
-        pthread_mutex_lock(&earlysuspend_mutex);
-        while (earlysuspend_state != EARLYSUSPEND_ON) {
-            pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
-        }
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-
-    ALOGV("autosuspend_earlysuspend_disable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-struct autosuspend_ops autosuspend_earlysuspend_ops = {
-        .enable = autosuspend_earlysuspend_enable,
-        .disable = autosuspend_earlysuspend_disable,
-};
-
-void start_earlysuspend_thread(void)
-{
-    char buf[80];
-    int ret;
-
-    ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
-    if (ret < 0) {
-        return;
-    }
-
-    ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
-    if (ret < 0) {
-        return;
-    }
-
-    wait_for_fb_wake();
-
-    ALOGI("Starting early suspend unblocker thread\n");
-    ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
-    if (ret) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error creating thread: %s\n", buf);
-        return;
-    }
-
-    wait_for_earlysuspend = true;
-}
-
-struct autosuspend_ops *autosuspend_earlysuspend_init(void)
-{
-    char buf[80];
-    int ret;
-
-    sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
-
-    if (sPowerStatefd < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        return NULL;
-    }
-
-    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err_write;
-    }
-
-    ALOGI("Selected early suspend\n");
-
-    start_earlysuspend_thread();
-
-    return &autosuspend_earlysuspend_ops;
-
-err_write:
-    close(sPowerStatefd);
-    return NULL;
-}
diff --git a/libsync/Android.bp b/libsync/Android.bp
index 4948aa5..a4e5599 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -34,7 +34,6 @@
         "-g",
         "-Wall",
         "-Werror",
-        "-std=gnu++11",
         "-Wno-missing-field-initializers",
         "-Wno-sign-compare",
     ],
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index dccacda..a6c4abc 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -18,7 +18,7 @@
 
 #include <errno.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/FrameworkCommand.h>
 
 #define UNUSED __attribute__((unused))
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b1fb849..1b6076f 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -19,8 +19,9 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/FrameworkCommand.h>
 #include <sysutils/FrameworkListener.h>
 #include <sysutils/SocketClient.h>
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index b787692..fef801a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -41,7 +41,7 @@
 const int LOCAL_QLOG_NL_EVENT = 112;
 const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/NetlinkEvent.h>
 
 NetlinkEvent::NetlinkEvent() {
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 1c4c7df..896dad3 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -20,11 +20,12 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <linux/netlink.h> /* out of order because must follow sys/socket.h */
 
-#include <android/log.h>
 #include <cutils/uevent.h>
+#include <log/log.h>
 #include <sysutils/NetlinkEvent.h>
 
 #if 1
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 1abe988..13bac09 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -17,10 +17,12 @@
 #define LOG_TAG "Service"
 
 #include <errno.h>
+#include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #include <sysutils/ServiceManager.h>
 
 ServiceManager::ServiceManager() {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 02505d3..971f908 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -25,8 +25,9 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/SocketClient.h>
 
 SocketClient::SocketClient(int socket, bool owned) {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 6a676a9..3f8f3db 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -24,9 +24,10 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/sockets.h>
+#include <log/log.h>
 #include <sysutils/SocketListener.h>
 #include <sysutils/SocketClient.h>
 
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 84594c8..a8dd673 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -144,17 +144,17 @@
  * usb_device_get_product_name and usb_device_get_serial.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_string(struct usb_device *device, int id);
+char* usb_device_get_string(struct usb_device *device, int id, int timeout);
 
 /* Returns the manufacturer name for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_manufacturer_name(struct usb_device *device);
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout);
 
 /* Returns the product name for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_product_name(struct usb_device *device);
+char* usb_device_get_product_name(struct usb_device *device, int timeout);
 
 /* Returns the version number for the USB device.
  */
@@ -163,7 +163,7 @@
 /* Returns the USB serial number for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_serial(struct usb_device *device);
+char* usb_device_get_serial(struct usb_device *device, int timeout);
 
 /* Returns true if we have write access to the USB device,
  * and false if we only have access to the USB device configuration.
@@ -232,10 +232,11 @@
 /* Submits a read or write request on the specified device */
 int usb_request_queue(struct usb_request *req);
 
- /* Waits for the results of a previous usb_request_queue operation.
+ /* Waits for the results of a previous usb_request_queue operation. timeoutMillis == -1 requests
+  * to wait forever.
   * Returns a usb_request, or NULL for error.
   */
-struct usb_request *usb_request_wait(struct usb_device *dev);
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis);
 
 /* Cancels a pending usb_request_queue() operation. */
 int usb_request_cancel(struct usb_request *req);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 68aca17..7adb4f2 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 // #define DEBUG 1
 #if DEBUG
 
@@ -43,6 +47,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
+#include <poll.h>
 #include <pthread.h>
 
 #include <linux/usbdevice_fs.h>
@@ -449,7 +454,7 @@
     return (struct usb_device_descriptor*)device->desc;
 }
 
-char* usb_device_get_string(struct usb_device *device, int id)
+char* usb_device_get_string(struct usb_device *device, int id, int timeout)
 {
     char string[256];
     __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
@@ -465,7 +470,8 @@
     // read list of supported languages
     result = usb_device_control_transfer(device,
             USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-            (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+            (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages),
+            timeout);
     if (result > 0)
         languageCount = (result - 2) / 2;
 
@@ -474,7 +480,8 @@
 
         result = usb_device_control_transfer(device,
                 USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-                (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+                (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer),
+                timeout);
         if (result > 0) {
             int i;
             // skip first word, and copy the rest to the string, changing shorts to bytes.
@@ -489,16 +496,16 @@
     return NULL;
 }
 
-char* usb_device_get_manufacturer_name(struct usb_device *device)
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iManufacturer);
+    return usb_device_get_string(device, desc->iManufacturer, timeout);
 }
 
-char* usb_device_get_product_name(struct usb_device *device)
+char* usb_device_get_product_name(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iProduct);
+    return usb_device_get_string(device, desc->iProduct, timeout);
 }
 
 int usb_device_get_version(struct usb_device *device)
@@ -507,10 +514,10 @@
     return desc->bcdUSB;
 }
 
-char* usb_device_get_serial(struct usb_device *device)
+char* usb_device_get_serial(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iSerialNumber);
+    return usb_device_get_string(device, desc->iSerialNumber, timeout);
 }
 
 int usb_device_is_writeable(struct usb_device *device)
@@ -681,29 +688,38 @@
     return res;
 }
 
-struct usb_request *usb_request_wait(struct usb_device *dev)
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis)
 {
-    struct usbdevfs_urb *urb = NULL;
-    struct usb_request *req = NULL;
+    // Poll until a request becomes available if there is a timeout
+    if (timeoutMillis > 0) {
+        struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0};
 
-    while (1) {
-        int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
-        D("USBDEVFS_REAPURB returned %d\n", res);
-        if (res < 0) {
-            if(errno == EINTR) {
-                continue;
-            }
-            D("[ reap urb - error ]\n");
+        int res = poll(&p, 1, timeoutMillis);
+
+        if (res != 1 || p.revents != POLLOUT) {
+            D("[ poll - event %d, error %d]\n", p.revents, errno);
             return NULL;
-        } else {
-            D("[ urb @%p status = %d, actual = %d ]\n",
-                urb, urb->status, urb->actual_length);
-            req = (struct usb_request*)urb->usercontext;
-            req->actual_length = urb->actual_length;
         }
-        break;
     }
-    return req;
+
+    // Read the request. This should usually succeed as we polled before, but it can fail e.g. when
+    // two threads are reading usb requests at the same time and only a single request is available.
+    struct usbdevfs_urb *urb = NULL;
+    int res = TEMP_FAILURE_RETRY(ioctl(dev->fd, timeoutMillis == -1 ? USBDEVFS_REAPURB :
+                                       USBDEVFS_REAPURBNDELAY, &urb));
+    D("%s returned %d\n", timeoutMillis == -1 ? "USBDEVFS_REAPURB" : "USBDEVFS_REAPURBNDELAY", res);
+
+    if (res < 0) {
+        D("[ reap urb - error %d]\n", errno);
+        return NULL;
+    } else {
+        D("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length);
+
+        struct usb_request *req = (struct usb_request*)urb->usercontext;
+        req->actual_length = urb->actual_length;
+
+        return req;
+    }
 }
 
 int usb_request_cancel(struct usb_request *req)
@@ -711,4 +727,3 @@
     struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
     return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
 }
-
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 1dc8632..98cd2c6 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -44,7 +44,7 @@
 
     char* formattedString;
 
-#ifndef USE_MINGW
+#ifndef _WIN32
     if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error
         ALOGE("%s: Failed to format string", __FUNCTION__);
         return;
@@ -115,7 +115,7 @@
         return;
     }
 
-#ifndef USE_MINGW
+#ifndef _WIN32
     dprintf(mFd, mFormatString, mPrefix, string);
 #endif
 }
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 1aa761a..229e3f2 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "sharedbuffer"
+
 #include <stdlib.h>
 #include <string.h>
 
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 0652101..c32f462 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "unicode"
+
 #include <limits.h>
 #include <stddef.h>
 
diff --git a/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip
new file mode 100644
index 0000000..294eaf5
--- /dev/null
+++ b/libziparchive/testdata/bad_filename.zip
Binary files differ
diff --git a/libziparchive/testdata/dummy-update.zip b/libziparchive/testdata/dummy-update.zip
new file mode 100644
index 0000000..6976bf1
--- /dev/null
+++ b/libziparchive/testdata/dummy-update.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a1455b0..c2055b7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,8 @@
  * Read-only access to Zip archives, with minimal heap allocation.
  */
 
+#define LOG_TAG "ziparchive"
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -30,11 +32,11 @@
 #include <memory>
 #include <vector>
 
-#include <android/log.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
 #include <android-base/memory.h>
+#include <log/log.h>
 #include <utils/Compat.h>
 #include <utils/FileMap.h>
 #include "ziparchive/zip_archive.h"
@@ -215,19 +217,14 @@
   return 0;
 }
 
-static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
-                                    ZipArchive* archive, off64_t file_length,
-                                    off64_t read_amount, uint8_t* scan_buffer) {
+static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
+                                    off64_t file_length, off64_t read_amount,
+                                    uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
 
-  if (lseek64(fd, search_start, SEEK_SET) != search_start) {
-    ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
-          strerror(errno));
-    return kIoError;
-  }
-  if (!android::base::ReadFully(fd, scan_buffer, static_cast<size_t>(read_amount))) {
-    ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
-          strerror(errno));
+  if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
+    ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed",
+          static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start));
     return kIoError;
   }
 
@@ -292,9 +289,11 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  if (!archive->directory_map.create(debug_file_name, fd,
-          static_cast<off64_t>(eocd->cd_start_offset),
-          static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
+
+  if (!archive->InitializeCentralDirectory(debug_file_name,
+                                           static_cast<off64_t>(eocd->cd_start_offset),
+                                           static_cast<size_t>(eocd->cd_size))) {
+    ALOGE("Zip: failed to intialize central directory.\n");
     return kMmapFailed;
   }
 
@@ -309,18 +308,16 @@
  *
  * On success, returns 0 after populating fields from the EOCD area:
  *   directory_offset
- *   directory_map
+ *   directory_ptr
  *   num_entries
  */
-static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
-                                   ZipArchive* archive) {
+static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
 
   // Test file length. We use lseek64 to make sure the file
   // is small enough to be a zip file (Its size must be less than
   // 0xffffffff bytes).
-  off64_t file_length = lseek64(fd, 0, SEEK_END);
+  off64_t file_length = archive->mapped_zip.GetFileLength();
   if (file_length == -1) {
-    ALOGV("Zip: lseek on fd %d failed", fd);
     return kInvalidFile;
   }
 
@@ -351,11 +348,9 @@
     read_amount = file_length;
   }
 
-  uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
-  int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
-                                        file_length, read_amount, scan_buffer);
-
-  free(scan_buffer);
+  std::vector<uint8_t> scan_buffer(read_amount);
+  int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount,
+                                        scan_buffer.data());
   return result;
 }
 
@@ -366,9 +361,8 @@
  * Returns 0 on success.
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
-  const uint8_t* const cd_ptr =
-      reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
-  const size_t cd_length = archive->directory_map.getDataLength();
+  const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
+  const size_t cd_length = archive->central_directory.GetMapLength();
   const uint16_t num_entries = archive->num_entries;
 
   /*
@@ -379,6 +373,11 @@
   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
   archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
       sizeof(ZipString)));
+  if (archive->hash_table == nullptr) {
+    ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
+          archive->hash_table_size, sizeof(ZipString));
+    return -1;
+  }
 
   /*
    * Walk through the central directory, adding entries to the hash
@@ -411,6 +410,11 @@
     const uint16_t comment_length = cdr->comment_length;
     const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
 
+    if (file_name + file_name_length > cd_end) {
+      ALOGW("Zip: file name boundary exceeds the central directory range, file_name_length: "
+            "%" PRIx16 ", cd_length: %zu", file_name_length, cd_length);
+      return -1;
+    }
     /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
     if (!IsValidEntryName(file_name, file_name_length)) {
       return -1;
@@ -442,7 +446,7 @@
 static int32_t OpenArchiveInternal(ZipArchive* archive,
                                    const char* debug_file_name) {
   int32_t result = -1;
-  if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
+  if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
     return result;
   }
 
@@ -473,6 +477,13 @@
   return OpenArchiveInternal(archive, fileName);
 }
 
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
+                              ZipArchiveHandle *handle) {
+  ZipArchive* archive = new ZipArchive(address, length);
+  *handle = archive;
+  return OpenArchiveInternal(archive, debug_file_name);
+}
+
 /*
  * Close a ZipArchive, closing the file and freeing the contents.
  */
@@ -482,10 +493,10 @@
   delete archive;
 }
 
-static int32_t UpdateEntryFromDataDescriptor(int fd,
+static int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip,
                                              ZipEntry *entry) {
   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
-  if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
+  if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
     return kIoError;
   }
 
@@ -500,23 +511,6 @@
   return 0;
 }
 
-// Attempts to read |len| bytes into |buf| at offset |off|.
-// On non-Windows platforms, callers are guaranteed that the |fd|
-// offset is unchanged and there is no side effect to this call.
-//
-// On Windows platforms this is not thread-safe.
-static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
-#if !defined(_WIN32)
-  return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
-#else
-  if (lseek64(fd, off, SEEK_SET) != off) {
-    ALOGW("Zip: failed seek to offset %" PRId64, off);
-    return false;
-  }
-  return android::base::ReadFully(fd, buf, len);
-#endif
-}
-
 static int32_t FindEntry(const ZipArchive* archive, const int ent,
                          ZipEntry* data) {
   const uint16_t nameLen = archive->hash_table[ent].name_length;
@@ -530,9 +524,8 @@
   // This is the base of our mmapped region, we have to sanity check that
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
-  const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
-    archive->directory_map.getDataPtr());
-  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
+  const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
+  if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -564,7 +557,7 @@
   }
 
   uint8_t lfh_buf[sizeof(LocalFileHeader)];
-  if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
+  if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) {
     ALOGW("Zip: failed reading lfh name from offset %" PRId64,
         static_cast<int64_t>(local_header_offset));
     return kIoError;
@@ -604,19 +597,16 @@
       return kInvalidOffset;
     }
 
-    uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
-    if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
+    std::vector<uint8_t> name_buf(nameLen);
+    if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
       ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
-      free(name_buf);
       return kIoError;
     }
 
-    if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
-      free(name_buf);
+    if (memcmp(archive->hash_table[ent].name, name_buf.data(), nameLen)) {
       return kInconsistentInformation;
     }
 
-    free(name_buf);
   } else {
     ALOGW("Zip: lfh name did not match central directory.");
     return kInconsistentInformation;
@@ -806,7 +796,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) {
@@ -839,13 +830,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));
   }
 
@@ -886,7 +886,7 @@
 }
 #pragma GCC diagnostic pop
 
-static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
                                     Writer* writer, uint64_t* crc_out) {
   const size_t kBufSize = 32768;
   std::vector<uint8_t> read_buf(kBufSize);
@@ -936,7 +936,7 @@
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
+      if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
         ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
         return kIoError;
       }
@@ -984,7 +984,7 @@
   return 0;
 }
 
-static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
                                  uint64_t *crc_out) {
   static const uint32_t kBufSize = 32768;
   std::vector<uint8_t> buf(kBufSize);
@@ -998,7 +998,7 @@
     // Safe conversion because kBufSize is narrow enough for a 32 bit signed
     // value.
     const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
-    if (!android::base::ReadFully(fd, buf.data(), block_size)) {
+    if (!mapped_zip.ReadData(buf.data(), block_size)) {
       ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
       return kIoError;
     }
@@ -1021,7 +1021,7 @@
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
 
-  if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
     ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
     return kIoError;
   }
@@ -1030,13 +1030,13 @@
   int32_t return_value = -1;
   uint64_t crc = 0;
   if (method == kCompressStored) {
-    return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
+    return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
   } else if (method == kCompressDeflated) {
-    return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
+    return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
   }
 
   if (!return_value && entry->has_data_descriptor) {
-    return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
+    return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry);
     if (return_value) {
       return return_value;
     }
@@ -1077,7 +1077,7 @@
 }
 
 int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return reinterpret_cast<ZipArchive*>(handle)->fd;
+  return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
 }
 
 ZipString::ZipString(const char* entry_name)
@@ -1086,3 +1086,143 @@
   CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
   name_length = static_cast<uint16_t>(len);
 }
+
+#if !defined(_WIN32)
+class ProcessWriter : public Writer {
+ public:
+  ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(),
+    proc_function_(func),
+    cookie_(cookie) {
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    return proc_function_(buf, buf_size, cookie_);
+  }
+
+ private:
+  ProcessZipEntryFunction proc_function_;
+  void* cookie_;
+};
+
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+                                ProcessZipEntryFunction func, void* cookie) {
+  ProcessWriter writer(func, cookie);
+  return ExtractToWriter(handle, entry, &writer);
+}
+
+#endif //!defined(_WIN32)
+
+int MappedZipFile::GetFileDescriptor() const {
+  if (!has_fd_) {
+    ALOGW("Zip: MappedZipFile doesn't have a file descriptor.");
+    return -1;
+  }
+  return fd_;
+}
+
+void* MappedZipFile::GetBasePtr() const {
+  if (has_fd_) {
+    ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
+    return nullptr;
+  }
+  return base_ptr_;
+}
+
+off64_t MappedZipFile::GetFileLength() const {
+  if (has_fd_) {
+    off64_t result = lseek64(fd_, 0, SEEK_END);
+    if (result == -1) {
+      ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
+    }
+    return result;
+  } else {
+    if (base_ptr_ == nullptr) {
+      ALOGE("Zip: invalid file map\n");
+      return -1;
+    }
+    return static_cast<off64_t>(data_length_);
+  }
+}
+
+bool MappedZipFile::SeekToOffset(off64_t offset) {
+  if (has_fd_) {
+    if (lseek64(fd_, offset, SEEK_SET) != offset) {
+      ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
+      return false;
+    }
+    return true;
+  } else {
+    if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
+      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset,
+            data_length_);
+      return false;
+    }
+
+    read_pos_ = offset;
+    return true;
+  }
+}
+
+bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
+  if (has_fd_) {
+    if(!android::base::ReadFully(fd_, buffer, read_amount)) {
+      ALOGE("Zip: read from %d failed\n", fd_);
+      return false;
+    }
+  } else {
+    memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
+    read_pos_ += read_amount;
+  }
+  return true;
+}
+
+// Attempts to read |len| bytes into |buf| at offset |off|.
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+#if !defined(_WIN32)
+  if (has_fd_) {
+    if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+      ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
+      return false;
+    }
+    return true;
+  }
+#endif
+  if (!SeekToOffset(off)) {
+    return false;
+  }
+  return ReadData(buf, len);
+
+}
+
+void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
+  base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset;
+  length_ = cd_size;
+}
+
+bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+                                            size_t cd_size) {
+  if (mapped_zip.HasFd()) {
+    if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(),
+                               cd_start_offset, cd_size, true /* read only */)) {
+      return false;
+    }
+
+    CHECK_EQ(directory_map->getDataLength(), cd_size);
+    central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size);
+  } else {
+    if (mapped_zip.GetBasePtr() == nullptr) {
+      ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
+      return false;
+    }
+    if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
+        mapped_zip.GetFileLength()) {
+      ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region ("
+            "start_offset %"  PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
+            static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
+      return false;
+    }
+
+    central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size);
+  }
+  return true;
+}
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index ab52368..971db4f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -21,17 +21,83 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <memory>
+#include <vector>
+
 #include <utils/FileMap.h>
 #include <ziparchive/zip_archive.h>
 
+class MappedZipFile {
+ public:
+  explicit MappedZipFile(const int fd) :
+    has_fd_(true),
+    fd_(fd),
+    base_ptr_(nullptr),
+    data_length_(0),
+    read_pos_(0) {}
+
+  explicit MappedZipFile(void* address, size_t length) :
+    has_fd_(false),
+    fd_(-1),
+    base_ptr_(address),
+    data_length_(static_cast<off64_t>(length)),
+    read_pos_(0) {}
+
+  bool HasFd() const {return has_fd_;}
+
+  int GetFileDescriptor() const;
+
+  void* GetBasePtr() const;
+
+  off64_t GetFileLength() const;
+
+  bool SeekToOffset(off64_t offset);
+
+  bool ReadData(uint8_t* buffer, size_t read_amount);
+
+  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+
+ private:
+  // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
+  // from the file. Otherwise, we're opening the archive from a memory mapped
+  // file. In that case, base_ptr_ points to the start of the memory region and
+  // data_length_ defines the file length.
+  const bool has_fd_;
+
+  const int fd_;
+
+  void* const base_ptr_;
+  const off64_t data_length_;
+  // read_pos_ is the offset to the base_ptr_ where we read data from.
+  size_t read_pos_;
+};
+
+class CentralDirectory {
+ public:
+  CentralDirectory(void) :
+    base_ptr_(nullptr),
+    length_(0) {}
+
+  const uint8_t* GetBasePtr() const {return base_ptr_;}
+
+  size_t GetMapLength() const {return length_;}
+
+  void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
+
+ private:
+  const uint8_t* base_ptr_;
+  size_t length_;
+};
+
 struct ZipArchive {
   // open Zip archive
-  const int fd;
+  mutable MappedZipFile mapped_zip;
   const bool close_file;
 
   // mapped central directory area
   off64_t directory_offset;
-  android::FileMap directory_map;
+  CentralDirectory central_directory;
+  std::unique_ptr<android::FileMap> directory_map;
 
   // number of entries in the Zip archive
   uint16_t num_entries;
@@ -44,20 +110,36 @@
   ZipString* hash_table;
 
   ZipArchive(const int fd, bool assume_ownership) :
-      fd(fd),
-      close_file(assume_ownership),
-      directory_offset(0),
-      num_entries(0),
-      hash_table_size(0),
-      hash_table(NULL) {}
+    mapped_zip(fd),
+    close_file(assume_ownership),
+    directory_offset(0),
+    central_directory(),
+    directory_map(new android::FileMap()),
+    num_entries(0),
+    hash_table_size(0),
+    hash_table(nullptr) {}
+
+  ZipArchive(void* address, size_t length) :
+    mapped_zip(address, length),
+    close_file(false),
+    directory_offset(0),
+    central_directory(),
+    directory_map(new android::FileMap()),
+    num_entries(0),
+    hash_table_size(0),
+    hash_table(nullptr) {}
 
   ~ZipArchive() {
-    if (close_file && fd >= 0) {
-      close(fd);
+    if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+      close(mapped_zip.GetFileDescriptor());
     }
 
     free(hash_table);
   }
+
+  bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+                                  size_t cd_size);
+
 };
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 41988bc..64b24c3 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -39,7 +39,7 @@
 bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   off64_t data_offset = entry.offset;
-  if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
     ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
     return false;
   }
@@ -88,7 +88,7 @@
   size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   errno = 0;
-  if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
+  if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
     if (errno != 0) {
       ALOGE("Error reading from archive fd: %s", strerror(errno));
     } else {
@@ -209,7 +209,7 @@
       size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
       ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
       errno = 0;
-      if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
+      if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
         if (errno != 0) {
           ALOGE("Error reading from archive fd: %s", strerror(errno));
         } else {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 42eb5ee..493a0ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -26,7 +26,9 @@
 
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
+#include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
+#include <utils/FileMap.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 
@@ -37,6 +39,8 @@
 static const std::string kLargeZip = "large.zip";
 static const std::string kBadCrcZip = "bad_crc.zip";
 static const std::string kCrashApk = "crash.apk";
+static const std::string kBadFilenameZip = "bad_filename.zip";
+static const std::string kUpdateZip = "dummy-update.zip";
 
 static const std::vector<uint8_t> kATxtContents {
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@@ -81,7 +85,9 @@
 TEST(ziparchive, Open) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+  CloseArchive(handle);
 
+  ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
   CloseArchive(handle);
 }
 
@@ -501,6 +507,32 @@
             lseek64(tmp_file.fd, 0, SEEK_END));
 }
 
+#if !defined(_WIN32)
+TEST(ziparchive, OpenFromMemory) {
+  const std::string zip_path = test_data_dir + "/" + kUpdateZip;
+  android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
+  ASSERT_NE(-1, fd);
+  struct stat sb;
+  ASSERT_EQ(0, fstat(fd, &sb));
+
+  // Memory map the file first and open the archive from the memory region.
+  android::FileMap file_map;
+  file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
+                                     zip_path.c_str(), &handle));
+
+  // Assert one entry can be found and extracted correctly.
+  std::string BINARY_PATH("META-INF/com/google/android/update-binary");
+  ZipString binary_path(BINARY_PATH.c_str());
+  ZipEntry binary_entry;
+  ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+  TemporaryFile tmp_binary;
+  ASSERT_NE(-1, tmp_binary.fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
+}
+#endif
+
 static void ZipArchiveStreamTest(
     ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
     bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 107aa3e..49746b3 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,6 +18,7 @@
 
 #include <arpa/inet.h>
 #include <errno.h>
+#include <sched.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d1a23ae..94b8691 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -25,15 +25,14 @@
 #include <memory>
 #include <string>
 
-#include <android/log.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
-#include <log/logger.h>
 #include <log/logprint.h>
+#include <private/android_logger.h>
 #include <system/thread_defs.h>
 
 #include <pcrecpp.h>
@@ -82,9 +81,16 @@
 static size_t g_maxCount;
 static size_t g_printCount;
 static bool g_printItAnyways;
+static bool g_debug;
+
+enum helpType {
+    HELP_FALSE,
+    HELP_TRUE,
+    HELP_FORMAT
+};
 
 // if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
 
 static int openLogFile (const char *pathname)
 {
@@ -134,7 +140,7 @@
     g_outFD = openLogFile(g_outputFileName);
 
     if (g_outFD < 0) {
-        logcat_panic(false, "couldn't open output file");
+        logcat_panic(HELP_FALSE, "couldn't open output file");
     }
 
     g_outByteCount = 0;
@@ -171,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,
@@ -183,11 +189,13 @@
     } else {
         err = android_log_processLogBuffer(&buf->entry_v1, &entry);
     }
-    if (err < 0) {
+    if ((err < 0) && !g_debug) {
         goto error;
     }
 
-    if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+    if (android_log_shouldPrintLine(g_logformat,
+                                    std::string(entry.tag, entry.tagLen).c_str(),
+                                    entry.priority)) {
         bool match = regexOk(entry);
 
         g_printCount += match;
@@ -195,7 +203,7 @@
             bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
             if (bytesWritten < 0) {
-                logcat_panic(false, "output error");
+                logcat_panic(HELP_FALSE, "output error");
             }
         }
     }
@@ -209,7 +217,6 @@
     }
 
 error:
-    //fprintf (stderr, "Error processing record\n");
     return;
 }
 
@@ -221,7 +228,7 @@
                      dev->printed ? "switch to" : "beginning of",
                      dev->device);
             if (write(g_outFD, buf, strlen(buf)) < 0) {
-                logcat_panic(false, "output error");
+                logcat_panic(HELP_FALSE, "output error");
             }
         }
         dev->printed = true;
@@ -255,18 +262,18 @@
     g_outFD = openLogFile (g_outputFileName);
 
     if (g_outFD < 0) {
-        logcat_panic(false, "couldn't open output file");
+        logcat_panic(HELP_FALSE, "couldn't open output file");
     }
 
     struct stat statbuf;
     if (fstat(g_outFD, &statbuf) == -1) {
         close(g_outFD);
-        logcat_panic(false, "couldn't get output file stat\n");
+        logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
     }
 
     if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
         close(g_outFD);
-        logcat_panic(false, "invalid output file stat\n");
+        logcat_panic(HELP_FALSE, "invalid output file stat\n");
     }
 
     g_outByteCount = statbuf.st_size;
@@ -287,9 +294,10 @@
                     "                  the fileset and continue\n"
                     "  -v <format>, --format=<format>\n"
                     "                  Sets log print format verb and adverbs, where <format> is:\n"
-                    "                    brief long process raw tag thread threadtime time\n"
+                    "                    brief help long process raw tag thread threadtime time\n"
                     "                  and individually flagged modifying adverbs can be added:\n"
-                    "                    color epoch monotonic printable uid usec UTC year zone\n"
+                    "                    color descriptive epoch monotonic printable uid\n"
+                    "                    usec UTC year zone\n"
                     "  -D, --dividers  Print dividers between each log buffer\n"
                     "  -c, --clear     Clear (flush) the entire log and exit\n"
                     "                  if Log to File specified, clear fileset instead\n"
@@ -355,6 +363,40 @@
                    "or defaults to \"threadtime\"\n\n");
 }
 
+static void show_format_help()
+{
+    fprintf(stderr,
+        "-v <format>, --format=<format> options:\n"
+        "  Sets log print format verb and adverbs, where <format> is:\n"
+        "    brief long process raw tag thread threadtime time\n"
+        "  and individually flagged modifying adverbs can be added:\n"
+        "    color descriptive epoch monotonic printable uid usec UTC year zone\n"
+        "\nSingle format verbs:\n"
+        "  brief      — Display priority/tag and PID of the process issuing the message.\n"
+        "  long       — Display all metadata fields, separate messages with blank lines.\n"
+        "  process    — Display PID only.\n"
+        "  raw        — Display the raw log message, with no other metadata fields.\n"
+        "  tag        — Display the priority/tag only.\n"
+        "  threadtime — Display the date, invocation time, priority, tag, and the PID\n"
+        "               and TID of the thread issuing the message. (the default format).\n"
+        "  time       — Display the date, invocation time, priority/tag, and PID of the\n"
+        "             process issuing the message.\n"
+        "\nAdverb modifiers can be used in combination:\n"
+        "  color       — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
+        "                \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+        "  descriptive — events logs only, descriptions from event-log-tags database.\n"
+        "  epoch       — Display time as seconds since Jan 1 1970.\n"
+        "  monotonic   — Display time as cpu seconds since last boot.\n"
+        "  printable   — Ensure that any binary logging content is escaped.\n"
+        "  uid         — If permitted, display the UID or Android ID of logged process.\n"
+        "  usec        — Display time down the microsecond precision.\n"
+        "  UTC         — Display time as UTC.\n"
+        "  year        — Add the year to the displayed time.\n"
+        "  zone        — Add the local timezone to the displayed time.\n"
+        "  \"<zone>\"    — Print using this public named timezone (experimental).\n\n"
+    );
+}
+
 static int setLogFormat(const char * formatString)
 {
     static AndroidLogPrintFormat format;
@@ -417,15 +459,23 @@
     return true;
 }
 
-static void logcat_panic(bool showHelp, const char *fmt, ...)
+static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
 {
     va_list  args;
     va_start(args, fmt);
     vfprintf(stderr, fmt,  args);
     va_end(args);
 
-    if (showHelp) {
+    switch (showHelp) {
+    case HELP_TRUE:
        show_help(getprogname());
+       break;
+    case HELP_FORMAT:
+       show_format_help();
+       break;
+    case HELP_FALSE:
+    default:
+      break;
     }
 
     exit(EXIT_FAILURE);
@@ -570,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";
@@ -578,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' },
@@ -615,7 +667,7 @@
                 if (long_options[option_index].name == pid_str) {
                     // ToDo: determine runtime PID_MAX?
                     if (!getSizeTArg(optarg, &pid, 1)) {
-                        logcat_panic(true, "%s %s out of range\n",
+                        logcat_panic(HELP_TRUE, "%s %s out of range\n",
                                      long_options[option_index].name, optarg);
                     }
                     break;
@@ -627,7 +679,7 @@
                     // ToDo: implement API that supports setting a wrap timeout
                     size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
                     if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
-                        logcat_panic(true, "%s %s out of range\n",
+                        logcat_panic(HELP_TRUE, "%s %s out of range\n",
                                      long_options[option_index].name, optarg);
                     }
                     if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
@@ -642,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;
@@ -674,7 +730,8 @@
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
                     char *cp = parseTime(tail_time, optarg);
                     if (!cp) {
-                        logcat_panic(false, "-%c \"%s\" not in time format\n",
+                        logcat_panic(HELP_FALSE,
+                                     "-%c \"%s\" not in time format\n",
                                      ret, optarg);
                     }
                     if (*cp) {
@@ -706,7 +763,7 @@
             case 'm': {
                 char *end = NULL;
                 if (!getSizeTArg(optarg, &g_maxCount)) {
-                    logcat_panic(false, "-%c \"%s\" isn't an "
+                    logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
                                  "integer greater than zero\n", ret, optarg);
                 }
             }
@@ -779,7 +836,8 @@
                         const char *name = android_log_id_to_name(log_id);
 
                         if (strcmp(name, optarg) != 0) {
-                            logcat_panic(true, "unknown buffer %s\n", optarg);
+                            logcat_panic(HELP_TRUE,
+                                         "unknown buffer %s\n", optarg);
                         }
                         idMask |= (1 << log_id);
                     }
@@ -840,20 +898,27 @@
 
             case 'r':
                 if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+                    logcat_panic(HELP_TRUE,
+                                 "Invalid parameter \"%s\" to -r\n", optarg);
                 }
             break;
 
             case 'n':
                 if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+                    logcat_panic(HELP_TRUE,
+                                 "Invalid parameter \"%s\" to -n\n", optarg);
                 }
             break;
 
             case 'v':
-                err = setLogFormat (optarg);
+                if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
+                    show_format_help();
+                    exit(0);
+                }
+                err = setLogFormat(optarg);
                 if (err < 0) {
-                    logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+                    logcat_panic(HELP_FORMAT,
+                                 "Invalid parameter \"%s\" to -v\n", optarg);
                 }
                 hasSetLogFormat |= err;
             break;
@@ -931,17 +996,20 @@
                 break;
 
             case ':':
-                logcat_panic(true, "Option -%c needs an argument\n", optopt);
+                logcat_panic(HELP_TRUE,
+                             "Option -%c needs an argument\n", optopt);
                 break;
 
             default:
-                logcat_panic(true, "Unrecognized Option %c\n", optopt);
+                logcat_panic(HELP_TRUE,
+                             "Unrecognized Option %c\n", optopt);
                 break;
         }
     }
 
     if (g_maxCount && got_t) {
-        logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
+        logcat_panic(HELP_TRUE,
+                     "Cannot use -m (--max-count) and -t together\n");
     }
     if (g_printItAnyways && (!g_regex || !g_maxCount)) {
         // One day it would be nice if --print -v color and --regex <expr>
@@ -967,12 +1035,12 @@
     }
 
     if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
-        logcat_panic(true, "-r requires -f as well\n");
+        logcat_panic(HELP_TRUE, "-r requires -f as well\n");
     }
 
     if (setId != NULL) {
         if (g_outputFileName == NULL) {
-            logcat_panic(true, "--id='%s' requires -f as well\n", setId);
+            logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
         }
 
         std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
@@ -1002,7 +1070,8 @@
     if (forceFilters) {
         err = android_log_addFilterString(g_logformat, forceFilters);
         if (err < 0) {
-            logcat_panic(false, "Invalid filter expression in logcat args\n");
+            logcat_panic(HELP_FALSE,
+                         "Invalid filter expression in logcat args\n");
         }
     } else if (argc == optind) {
         // Add from environment variable
@@ -1012,7 +1081,7 @@
             err = android_log_addFilterString(g_logformat, env_tags_orig);
 
             if (err < 0) {
-                logcat_panic(true,
+                logcat_panic(HELP_TRUE,
                             "Invalid filter expression in ANDROID_LOG_TAGS\n");
             }
         }
@@ -1022,7 +1091,8 @@
             err = android_log_addFilterString(g_logformat, argv[i]);
 
             if (err < 0) {
-                logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
+                logcat_panic(HELP_TRUE,
+                             "Invalid filter expression '%s'\n", argv[i]);
             }
         }
     }
@@ -1108,17 +1178,20 @@
     }
     // report any errors in the above loop and exit
     if (openDeviceFail) {
-        logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+        logcat_panic(HELP_FALSE,
+                     "Unable to open log device '%s'\n", openDeviceFail);
     }
     if (clearFail) {
-        logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to clear the '%s' log\n", clearFail);
     }
     if (setSizeFail) {
-        logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to set the '%s' log size\n", setSizeFail);
     }
     if (getSizeFail) {
-        logcat_panic(false, "failed to get the readable '%s' log size",
-                     getSizeFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to get the readable '%s' log size", getSizeFail);
     }
 
     if (setPruneList) {
@@ -1129,11 +1202,11 @@
         if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
             buf[len] = '\0';
             if (android_logger_set_prune_list(logger_list, buf, bLen)) {
-                logcat_panic(false, "failed to set the prune list");
+                logcat_panic(HELP_FALSE, "failed to set the prune list");
             }
             free(buf);
         } else {
-            logcat_panic(false, "failed to set the prune list (alloc)");
+            logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
         }
     }
 
@@ -1164,7 +1237,7 @@
         }
 
         if (!buf) {
-            logcat_panic(false, "failed to read data");
+            logcat_panic(HELP_FALSE, "failed to read data");
         }
 
         // remove trailing FF
@@ -1216,7 +1289,7 @@
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            logcat_panic(false, "read: unexpected EOF!\n");
+            logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
         }
 
         if (ret < 0) {
@@ -1225,12 +1298,12 @@
             }
 
             if (ret == -EIO) {
-                logcat_panic(false, "read: unexpected EOF!\n");
+                logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
             }
             if (ret == -EINVAL) {
-                logcat_panic(false, "read: unexpected length.\n");
+                logcat_panic(HELP_FALSE, "read: unexpected length.\n");
             }
-            logcat_panic(false, "logcat read failure");
+            logcat_panic(HELP_FALSE, "logcat read failure");
         }
 
         for (d = devices; d; d = d->next) {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index a28664e..99c2e0a 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -25,7 +25,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 # -----------------------------------------------------------------------------
 # Benchmarks (actually a gTest where the result code does not matter)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9c9043e..11cffe6 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,10 +25,11 @@
 #include <sys/wait.h>
 
 #include <memory>
+#include <string>
 
-#include <android/log.h>
 #include <gtest/gtest.h>
-#include <log/logger.h>
+#include <log/log.h>
+#include <log/log_event_list.h>
 
 #define BIG_BUFFER (5 * 1024)
 
@@ -79,6 +80,26 @@
     EXPECT_EQ(4, count);
 }
 
+TEST(logcat, event_tag_filter) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen(
+      "logcat -b events -d -s auditd am_proc_start am_pss am_proc_bound dvm_lock_sample am_wtf 2>/dev/null",
+      "r")));
+
+    char buffer[BIG_BUFFER];
+
+    int count = 0;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        ++count;
+    }
+
+    pclose(fp);
+
+    EXPECT_LT(4, count);
+}
+
 TEST(logcat, year) {
 
     if (android_log_clockid() == CLOCK_MONOTONIC) {
@@ -570,6 +591,14 @@
     EXPECT_EQ(1, signals);
 }
 
+// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
+static testing::AssertionResult IsFalse(int ret, const char* command) {
+    return ret ?
+        (testing::AssertionSuccess() <<
+            "ret=" << ret << " command=\"" << command << "\"") :
+        testing::AssertionFailure();
+}
+
 TEST(logcat, logrotate) {
     static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
     char buf[sizeof(form)];
@@ -581,7 +610,7 @@
     snprintf(command, sizeof(command), comm, buf);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (!ret) {
         snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
 
@@ -611,7 +640,7 @@
         }
     }
     snprintf(command, sizeof(command), "rm -rf %s", buf);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_suffix) {
@@ -625,7 +654,7 @@
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (!ret) {
         snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
 
@@ -664,7 +693,7 @@
         EXPECT_EQ(11, log_file_count);
     }
     snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_continue) {
@@ -679,10 +708,10 @@
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (ret) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     FILE *fp;
@@ -690,7 +719,7 @@
     EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
     if (!fp) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     char *line = NULL;
@@ -714,23 +743,23 @@
     EXPECT_TRUE(NULL != second_last_line);
     if (!second_last_line) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     // re-run the command, it should only add a few lines more content if it
     // continues where it left off.
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (ret) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
     EXPECT_NE(nullptr, dir);
     if (!dir) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     struct dirent *entry;
@@ -769,7 +798,7 @@
     free(second_last_line);
 
     snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_clear) {
@@ -790,17 +819,17 @@
                  logcat_cmd, tmp_out_dir, log_filename, num_val);
 
         int ret;
-        EXPECT_FALSE((ret = system(command)));
+        EXPECT_FALSE(IsFalse(ret = system(command), command));
         if (ret) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
         EXPECT_NE(nullptr, dir);
         if (!dir) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         struct dirent *entry;
@@ -819,17 +848,18 @@
         strcat(command, clear_cmd);
 
         int ret;
-        EXPECT_FALSE((ret = system(command)));
+        EXPECT_FALSE(IsFalse(ret = system(command), command));
         if (ret) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
             EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
         EXPECT_NE(nullptr, dir);
         if (!dir) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         struct dirent *entry;
@@ -845,7 +875,7 @@
     }
 
     snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) {
@@ -856,7 +886,7 @@
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (ret) {
         return -1;
     }
@@ -914,7 +944,7 @@
     static const char cleanup_cmd[] = "rm -rf %s";
     char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
     snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_nodir) {
@@ -1062,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);
@@ -1097,7 +1127,7 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1207,3 +1237,175 @@
 
     ASSERT_EQ(3, count);
 }
+
+static bool End_to_End(const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 2, 3)))
+#endif
+    ;
+
+static bool End_to_End(const char* tag, const char* fmt, ...) {
+    FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
+    if (!fp) return false;
+
+    char buffer[BIG_BUFFER];
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsnprintf(buffer, sizeof(buffer), fmt, ap);
+    va_end(ap);
+
+    char *str = NULL;
+    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, &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);
+
+    if ((count == 0) && (lastMatch.length() > 0)) {
+        // Help us pinpoint where things went wrong ...
+        fprintf(stderr, "Closest match for\n    %s\n  is\n    %s",
+                expect.c_str(), lastMatch.c_str());
+    }
+
+    return count == 1;
+}
+
+TEST(logcat, descriptive) {
+    struct tag {
+        uint32_t tagNo;
+        const char* tagStr;
+    };
+
+    {
+        static const struct tag hhgtg = { 42, "answer" };
+        android_log_event_list ctx(hhgtg.tagNo);
+        static const char theAnswer[] = "what is five by seven";
+        ctx << theAnswer;
+        ctx.write();
+        EXPECT_TRUE(End_to_End(hhgtg.tagStr,
+                               "to life the universe etc=%s", theAnswer));
+    }
+
+    {
+        static const struct tag sync = { 2720, "sync" };
+        static const char id[] = "logcat.decriptive";
+        {
+            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,
+                                   "[id=%s,event=42,source=-1,account=0]",
+                                   id));
+        }
+
+        // Partial match to description
+        {
+            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,
+                                   "[id=%s,event=43,-1,0]",
+                                   id));
+        }
+
+        // Negative Test of End_to_End, ensure it is working
+        {
+            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");
+            EXPECT_FALSE(End_to_End(sync.tagStr,
+                                    "[id=%s,event=44,source=-1,account=0]",
+                                    id));
+        }
+    }
+
+    {
+        static const struct tag sync = { 2747, "contacts_aggregation" };
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint64_t)30 << (int32_t)2;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[aggregation time=30ms,count=2]"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint64_t)31570 << (int32_t)911;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[aggregation time=31.57s,count=911]"));
+        }
+    }
+
+    {
+        static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
+        {
+            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_list ctx(sync.tagNo);
+            ctx << (uint32_t)3072;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
+        }
+
+        {
+            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_list ctx(sync.tagNo);
+            ctx << (uint32_t)2097153;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
+        }
+
+        {
+            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_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/Android.mk b/logd/Android.mk
index 81637d2..7fe48d7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -29,7 +29,7 @@
     libcutils \
     libbase \
     libpackagelistparser \
-    libminijail
+    libcap
 
 # This is what we want to do:
 #  event_logtags = $(shell \
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/FlushCommand.h b/logd/FlushCommand.h
index a6cdf9d..1e7818a 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -16,7 +16,7 @@
 #ifndef _FLUSH_COMMAND_H
 #define _FLUSH_COMMAND_H
 
-#include <log/logger.h>
+#include <android/log.h>
 #include <sysutils/SocketClientCommand.h>
 
 class LogBufferElement;
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index cc140b0..c3ccd84 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,7 +25,7 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
-#include <log/logger.h>
+#include <android-base/macros.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -144,7 +144,7 @@
                     iov[2].iov_len = strlen(newline);
                 }
 
-                writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+                writev(fdDmesg, iov, arraysize(iov));
                 free(last_str);
                 last_str = NULL;
             }
@@ -166,7 +166,7 @@
             iov[2].iov_base = const_cast<char *>(newline);
             iov[2].iov_len = strlen(newline);
 
-            writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+            writev(fdDmesg, iov, arraysize(iov));
         }
     }
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 7f5fe4f..a009433 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// for manual checking of stale entries during LogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/cdefs.h>
 #include <sys/user.h>
 #include <time.h>
 #include <unistd.h>
@@ -25,114 +28,25 @@
 #include <unordered_map>
 
 #include <cutils/properties.h>
-#include <log/logger.h>
+#include <private/android_logger.h>
 
 #include "LogBuffer.h"
 #include "LogKlog.h"
 #include "LogReader.h"
 
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
 // Default
-#define LOG_BUFFER_SIZE (256 * 1024) // Tuned with ro.logd.size per-platform
 #define log_buffer_size(id) mMaxSize[id]
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-
-static bool valid_size(unsigned long value) {
-    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
-        return false;
-    }
-
-    long pages = sysconf(_SC_PHYS_PAGES);
-    if (pages < 1) {
-        return true;
-    }
-
-    long pagesize = sysconf(_SC_PAGESIZE);
-    if (pagesize <= 1) {
-        pagesize = PAGE_SIZE;
-    }
-
-    // maximum memory impact a somewhat arbitrary ~3%
-    pages = (pages + 31) / 32;
-    unsigned long maximum = pages * pagesize;
-
-    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
-        return true;
-    }
-
-    return value <= maximum;
-}
-
-static unsigned long property_get_size(const char *key) {
-    char property[PROPERTY_VALUE_MAX];
-    property_get(key, property, "");
-
-    char *cp;
-    unsigned long value = strtoul(property, &cp, 10);
-
-    switch(*cp) {
-    case 'm':
-    case 'M':
-        value *= 1024;
-    /* FALLTHRU */
-    case 'k':
-    case 'K':
-        value *= 1024;
-    /* FALLTHRU */
-    case '\0':
-        break;
-
-    default:
-        value = 0;
-    }
-
-    if (!valid_size(value)) {
-        value = 0;
-    }
-
-    return value;
-}
 
 void LogBuffer::init() {
-    static const char global_tuneable[] = "persist.logd.size"; // Settings App
-    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
-
-    unsigned long default_size = property_get_size(global_tuneable);
-    if (!default_size) {
-        default_size = property_get_size(global_default);
-        if (!default_size) {
-            default_size = property_get_bool("ro.config.low_ram",
-                                             BOOL_DEFAULT_FALSE)
-                ? LOG_BUFFER_MIN_SIZE // 64K
-                : LOG_BUFFER_SIZE;    // 256K
-        }
-    }
-
     log_id_for_each(i) {
         mLastSet[i] = false;
         mLast[i] = mLogElements.begin();
 
-        char key[PROP_NAME_MAX];
-
-        snprintf(key, sizeof(key), "%s.%s",
-                 global_tuneable, android_log_id_to_name(i));
-        unsigned long property_size = property_get_size(key);
-
-        if (!property_size) {
-            snprintf(key, sizeof(key), "%s.%s",
-                     global_default, android_log_id_to_name(i));
-            property_size = property_get_size(key);
-        }
-
-        if (!property_size) {
-            property_size = default_size;
-        }
-
-        if (!property_size) {
-            property_size = LOG_BUFFER_SIZE;
-        }
-
-        if (setSize(i, property_size)) {
+        if (setSize(i, __android_logger_get_buffer_size(i))) {
             setSize(i, LOG_BUFFER_MIN_SIZE);
         }
     }
@@ -315,6 +229,9 @@
     LogBufferElement *element = *it;
     log_id_t id = element->getLogId();
 
+    // Remove iterator references in the various lists that will become stale
+    // after the element is erased from the main logging list.
+
     {   // start of scope for found iterator
         int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
                 element->getTag() : element->getUid();
@@ -324,8 +241,10 @@
         }
     }
 
-    if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (element->getUid() == AID_SYSTEM)) {
-        // start of scope for pid found iterator
+    {   // start of scope for pid found iterator
+        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
+        // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
+        // long term code stability, find() check should be fast for those ids.
         LogBufferPidIteratorMap::iterator found =
             mLastWorstPidOfSystem[id].find(element->getPid());
         if ((found != mLastWorstPidOfSystem[id].end())
@@ -339,18 +258,45 @@
     log_id_for_each(i) {
         doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    LogBufferElementCollection::iterator bad = it;
+    int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+            element->getTag() : element->getUid();
+#endif
     it = mLogElements.erase(it);
     if (doSetLast) {
         log_id_for_each(i) {
             if (setLast[i]) {
-                if (it == mLogElements.end()) { // unlikely
+                if (__predict_false(it == mLogElements.end())) { // impossible
                     mLastSet[i] = false;
+                    mLast[i] = mLogElements.begin();
                 } else {
-                    mLast[i] = it;
+                    mLast[i] = it; // push down the road as next-best-watermark
                 }
             }
         }
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    log_id_for_each(i) {
+        for(auto b : mLastWorst[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
+                                 i, b.first, key);
+            }
+        }
+        for(auto b : mLastWorstPidOfSystem[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
+                                 i, b.first);
+            }
+        }
+        if (mLastSet[i] && (bad == mLast[i])) {
+            android::prdebug("stale mLast[%d]\n", i);
+            mLastSet[i] = false;
+            mLast[i] = mLogElements.begin();
+        }
+    }
+#endif
     if (coalesce) {
         stats.erase(element);
     } else {
@@ -509,7 +455,7 @@
 
     LogBufferElementCollection::iterator it;
 
-    if (caller_uid != AID_ROOT) {
+    if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
         // Only here if clear all request from non system source, so chatty
         // filter logistics is not required.
         it = mLastSet[id] ? mLast[id] : mLogElements.begin();
@@ -561,6 +507,7 @@
             if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
                 stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
                     worst, worst_sizes, second_worst_sizes, threshold);
+                // per-pid filter for AID_SYSTEM sources is too complex
             } else {
                 stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
                     worst, worst_sizes, second_worst_sizes, threshold);
@@ -594,8 +541,9 @@
                     it = found->second;
                 }
             }
-            if (worstPid) {
-                // begin scope for pid worst found iterator
+            if (worstPid) { // begin scope for pid worst found iterator
+                // FYI: worstPid only set if !LOG_ID_EVENTS and
+                //      !LOG_ID_SECURITY, not going to make that assumption ...
                 LogBufferPidIteratorMap::iterator found
                     = mLastWorstPidOfSystem[id].find(worstPid);
                 if ((found != mLastWorstPidOfSystem[id].end())
@@ -627,6 +575,7 @@
                 ++it;
                 continue;
             }
+            // below this point element->getLogId() == id
 
             if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
                 mLast[id] = it;
@@ -683,6 +632,9 @@
                         && ((!gc && (element->getPid() == worstPid))
                            || (mLastWorstPidOfSystem[id].find(element->getPid())
                                 == mLastWorstPidOfSystem[id].end()))) {
+                    // element->getUid() may not be AID_SYSTEM, next best
+                    // watermark if current one empty. id is not LOG_ID_EVENTS
+                    // or LOG_ID_SECURITY because of worstPid check.
                     mLastWorstPidOfSystem[id][element->getPid()] = it;
                 }
                 if ((!gc && !worstPid && (key == worst))
@@ -700,6 +652,8 @@
                 ++it;
                 continue;
             }
+            // key == worst below here
+            // If worstPid set, then element->getPid() == worstPid below here
 
             pruneRows--;
             if (pruneRows == 0) {
@@ -723,6 +677,9 @@
                     if (worstPid && (!gc
                                 || (mLastWorstPidOfSystem[id].find(worstPid)
                                     == mLastWorstPidOfSystem[id].end()))) {
+                        // element->getUid() may not be AID_SYSTEM, next best
+                        // watermark if current one empty. id is not
+                        // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
                         mLastWorstPidOfSystem[id][worstPid] = it;
                     }
                     if ((!gc && !worstPid) ||
@@ -880,7 +837,7 @@
 // set the total space allocated to "id"
 int LogBuffer::setSize(log_id_t id, unsigned long size) {
     // Reasonable limits ...
-    if (!valid_size(size)) {
+    if (!__android_logger_valid_buffer_size(size)) {
         return -1;
     }
     pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index e5de11d..f5c60c7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -22,7 +22,6 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <log/logger.h>
 #include <private/android_logger.h>
 
 #include "LogBuffer.h"
@@ -37,29 +36,24 @@
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
                                    const char *msg, unsigned short len) :
-        mLogId(log_id),
         mUid(uid),
         mPid(pid),
         mTid(tid),
-        mMsgLen(len),
         mSequence(sequence.fetch_add(1, memory_order_relaxed)),
-        mRealTime(realtime) {
+        mRealTime(realtime),
+        mMsgLen(len),
+        mLogId(log_id) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
+    mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
+        le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
+        0;
 }
 
 LogBufferElement::~LogBufferElement() {
     delete [] mMsg;
 }
 
-uint32_t LogBufferElement::getTag() const {
-    if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
-            !mMsg || (mMsgLen < sizeof(uint32_t))) {
-        return 0;
-    }
-    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
-}
-
 // caller must own and free character string
 char *android::tidToName(pid_t tid) {
     char *retval = NULL;
@@ -165,7 +159,7 @@
     size_t hdrLen;
     // LOG_ID_SECURITY not strictly needed since spam filter not activated,
     // but required for accuracy.
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -179,7 +173,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index f089550..fb7fbed 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -21,9 +21,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/SocketClient.h>
-#include <log/logger.h>
 
 class LogBuffer;
 
@@ -37,33 +36,40 @@
 
     friend LogBuffer;
 
-    const log_id_t mLogId;
-    const uid_t mUid;
-    const pid_t mPid;
-    const pid_t mTid;
-    char *mMsg;
-    union {
-        const unsigned short mMsgLen; // mMSg != NULL
-        unsigned short mDropped;      // mMsg == NULL
-    };
+    // sized to match reality of incoming log packets
+    uint32_t mTag; // only valid for isBinary()
+    const uint32_t mUid;
+    const uint32_t mPid;
+    const uint32_t mTid;
     const uint64_t mSequence;
     log_time mRealTime;
+    char *mMsg;
+    union {
+        const uint16_t mMsgLen; // mMSg != NULL
+        uint16_t mDropped;      // mMsg == NULL
+    };
+    const uint8_t mLogId;
+
     static atomic_int_fast64_t sequence;
 
     // assumption: mMsg == NULL
     size_t populateDroppedMessage(char *&buffer,
                                   LogBuffer *parent);
-
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
                      uid_t uid, pid_t pid, pid_t tid,
                      const char *msg, unsigned short len);
     virtual ~LogBufferElement();
 
-    log_id_t getLogId() const { return mLogId; }
+    bool isBinary(void) const {
+        return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
+    }
+
+    log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
     uid_t getUid(void) const { return mUid; }
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
+    uint32_t getTag() const { return mTag; }
     unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
     unsigned short setDropped(unsigned short value) {
         if (mMsg) {
@@ -77,8 +83,6 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
-    uint32_t getTag(void) const;
-
     static const uint64_t FLUSH_ERROR;
     uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
 };
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index c7506ef..7073535 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -25,7 +25,7 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
-#include <log/logger.h>
+#include <private/android_logger.h>
 #include <private/android_filesystem_config.h>
 
 #include "LogBuffer.h"
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index c0c1223..11d88af 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -17,7 +17,7 @@
 #ifndef _LOGD_LOG_KLOG_H__
 #define _LOGD_LOG_KLOG_H__
 
-#include <log/logger.h>
+#include <private/android_logger.h>
 #include <sysutils/SocketListener.h>
 
 char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 61b7fd8..4a30e6d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -23,7 +23,6 @@
 #include <unistd.h>
 
 #include <cutils/sockets.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2c07984..61d4c49 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <cutils/sockets.h>
+#include <private/android_logger.h>
 
 #include "FlushCommand.h"
 #include "LogBuffer.h"
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index c6ebd52..d4b48ef 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -21,7 +21,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <log/logger.h>
+#include <list>
+
+#include <android/log.h>
 
 #include "LogStatistics.h"
 
@@ -467,55 +469,87 @@
     short spaces = 1;
 
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
         oldLength = output.length();
-        if (spaces < 0) {
-            spaces = 0;
-        }
+        if (spaces < 0) spaces = 0;
         output += android::base::StringPrintf("%*s%s", spaces, "",
                                               android_log_id_to_name(id));
         spaces += spaces_total + oldLength - output.length();
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*sTotal", spaces, "");
 
-    spaces = 4;
-    output += "\nTotal";
+    static const char TotalStr[] = "\nTotal";
+    spaces = 10 - strlen(TotalStr);
+    output += TotalStr;
 
+    size_t totalSize = 0;
+    size_t totalEls = 0;
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
         oldLength = output.length();
-        if (spaces < 0) {
-            spaces = 0;
-        }
-        output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
-                                              sizesTotal(id),
-                                              elementsTotal(id));
+        if (spaces < 0) spaces = 0;
+        size_t szs = sizesTotal(id);
+        totalSize += szs;
+        size_t els = elementsTotal(id);
+        totalEls += els;
+        output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
         spaces += spaces_total + oldLength - output.length();
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
 
-    spaces = 6;
-    output += "\nNow";
+    static const char NowStr[] = "\nNow";
+    spaces = 10 - strlen(NowStr);
+    output += NowStr;
 
+    totalSize = 0;
+    totalEls = 0;
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
 
         size_t els = elements(id);
         if (els) {
             oldLength = output.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
-                                                  sizes(id), els);
+            if (spaces < 0) spaces = 0;
+            size_t szs = sizes(id);
+            totalSize += szs;
+            totalEls += els;
+            output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
             spaces -= output.length() - oldLength;
         }
         spaces += spaces_total;
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
+
+    static const char OverheadStr[] = "\nOverhead";
+    spaces = 10 - strlen(OverheadStr);
+    output += OverheadStr;
+
+    totalSize = 0;
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) continue;
+
+        size_t els = elements(id);
+        if (els) {
+            oldLength = output.length();
+            if (spaces < 0) spaces = 0;
+            // estimate the std::list overhead.
+            static const size_t overhead =
+                ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
+                    -sizeof(uint64_t)) +
+                sizeof(std::list<LogBufferElement*>);
+            size_t szs = sizes(id) + els * overhead;
+            totalSize += szs;
+            output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
+            spaces -= output.length() - oldLength;
+        }
+        spaces += spaces_total;
+    }
+    totalSize += sizeOf();
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
 
     // Report on Chattiest
 
@@ -523,9 +557,7 @@
 
     // Chattiest by application (UID)
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
 
         name = (uid == AID_ROOT)
             ? "Chattiest UIDs in %s log buffer:"
@@ -539,27 +571,21 @@
             : "Logging for this PID:";
         output += pidTable.format(*this, uid, pid, name);
         name = "Chattiest TIDs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += tidTable.format(*this, uid, pid, name);
     }
 
     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
         name = "Chattiest events log buffer TAGs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
     }
 
     if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
         name = "Chattiest security log buffer TAGs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
     }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index bfaafa4..1f598af 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -42,8 +42,32 @@
 
     std::unordered_map<TKey, TEntry> map;
 
+    size_t bucket_size() const {
+        size_t count = 0;
+        for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
+            size_t bucket_size = map.bucket_size(idx);
+            if (bucket_size == 0) bucket_size = 1;
+            count += bucket_size;
+        }
+        float load_factor = map.max_load_factor();
+        if (load_factor < 1.0) return count;
+        return count * load_factor;
+    }
+
+    static const size_t unordered_map_per_entry_overhead = sizeof(void*);
+    static const size_t unordered_map_bucket_overhead = sizeof(void*);
+
 public:
 
+    size_t size() const { return map.size(); }
+
+    // Estimate unordered_map memory usage.
+    size_t sizeOf() const {
+        return sizeof(*this) +
+               (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
+               (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
+    }
+
     typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
     typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
@@ -155,6 +179,7 @@
         }
         return output;
     }
+
 };
 
 namespace EntryBaseConstants {
@@ -472,7 +497,30 @@
     // security tag list
     tagTable_t securityTagTable;
 
+    size_t sizeOf() const {
+        size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
+                      tagTable.sizeOf() + securityTagTable.sizeOf() +
+                      (pidTable.size() * sizeof(pidTable_t::iterator)) +
+                      (tagTable.size() * sizeof(tagTable_t::iterator));
+        for(auto it : pidTable) {
+            const char* name = it.second.getName();
+            if (name) size += strlen(name) + 1;
+        }
+        for(auto it : tidTable) {
+            const char* name = it.second.getName();
+            if (name) size += strlen(name) + 1;
+        }
+        log_id_for_each(id) {
+            size += uidTable[id].sizeOf();
+            size += uidTable[id].size() * sizeof(uidTable_t::iterator);
+            size += pidSystemTable[id].sizeOf();
+            size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
+        }
+        return size;
+    }
+
 public:
+
     LogStatistics();
 
     void enableStatistics() { enable = true; }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 8401953..12df994 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -23,7 +23,7 @@
 
 #include <list>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <sysutils/SocketClient.h>
 
 class LogReader;
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 6db4c51..44ac742 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,7 +20,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <private/android_logger.h>
 #include <sysutils/SocketClient.h>
 
 // Hijack this header as a common include file used by most all sources
@@ -45,16 +45,6 @@
 bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
 bool clientHasLogCredentials(SocketClient *cli);
 
-// Furnished in main.cpp
-#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
-#define BOOL_DEFAULT_FALSE       0x0     // false if property not present
-#define BOOL_DEFAULT_TRUE        0x1     // true if property not present
-#define BOOL_DEFAULT_FLAG_PERSIST    0x2 // <key>, persist.<key>, ro.<key>
-#define BOOL_DEFAULT_FLAG_ENG        0x4 // off for user
-#define BOOL_DEFAULT_FLAG_SVELTE     0x8 // off for low_ram
-
-bool property_get_bool(const char *key, int def);
-
 static inline bool worstUidEnabledForLogid(log_id_t id) {
     return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
             (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 288a052..d2b212e 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -18,26 +18,20 @@
  *
  */
 
-#define LOG_TAG "libaudit"
-
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
-
 #include "libaudit.h"
 
 /**
  * Waits for an ack from the kernel
  * @param fd
  *  The netlink socket fd
- * @param seq
- *  The current sequence number were acking on
  * @return
  *  This function returns 0 on success, else -errno.
  */
-static int get_ack(int fd, int16_t seq)
+static int get_ack(int fd)
 {
     int rc;
     struct audit_message rep;
@@ -60,11 +54,6 @@
         }
     }
 
-    if ((int16_t)rep.nlh.nlmsg_seq != seq) {
-        SLOGW("Expected sequence number between user space and kernel space is out of skew, "
-          "expected %u got %u", seq, rep.nlh.nlmsg_seq);
-    }
-
     return 0;
 }
 
@@ -109,7 +98,6 @@
 
     /* Ensure the message is not too big */
     if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
-        SLOGE("netlink message is too large");
         return -EINVAL;
     }
 
@@ -140,7 +128,6 @@
     /* Not all the bytes were sent */
     if (rc < 0) {
         rc = -errno;
-        SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
         goto out;
     } else if ((uint32_t) rc != req.nlh.nlmsg_len) {
         rc = -EPROTO;
@@ -148,7 +135,7 @@
     }
 
     /* We sent all the bytes, get the ack */
-    rc = get_ack(fd, sequence);
+    rc = get_ack(fd);
 
     /* If the ack failed, return the error, else return the sequence number */
     rc = (rc == 0) ? (int) sequence : rc;
@@ -156,7 +143,6 @@
 out:
     /* Don't let sequence roll to negative */
     if (sequence < 0) {
-        SLOGW("Auditd to Kernel sequence number has rolled over");
         sequence = 0;
     }
 
@@ -183,7 +169,6 @@
     /* Let the kernel know this pid will be registering for audit events */
     rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
     if (rc < 0) {
-        SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
         return rc;
     }
 
@@ -241,25 +226,21 @@
             /* If request is non blocking and errno is EAGAIN, just return 0 */
             return 0;
         }
-        SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc));
         return rc;
     }
 
     if (nladdrlen != sizeof(nladdr)) {
-        SLOGE("Protocol fault, error: %s", strerror(EPROTO));
         return -EPROTO;
     }
 
     /* Make sure the netlink message was not spoof'd */
     if (nladdr.nl_pid) {
-        SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
         return -EINVAL;
     }
 
     /* Check if the reply from the kernel was ok */
     if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
         rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
-        SLOGE("Bad kernel response %s", strerror(-rc));
     }
 
     return rc;
@@ -267,9 +248,5 @@
 
 void audit_close(int fd)
 {
-    int rc = close(fd);
-    if (rc < 0) {
-        SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
-    }
-    return;
+    close(fd);
 }
diff --git a/logd/logd.rc b/logd/logd.rc
index 31ed4df..54349dd 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -2,10 +2,15 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
-    group root system readproc
+    file /proc/kmsg r
+    file /dev/kmsg w
+    user logd
+    group logd system readproc
     writepid /dev/cpuset/system-background/tasks
 
 service logd-reinit /system/bin/logd --reinit
     oneshot
     disabled
+    user logd
+    group logd
     writepid /dev/cpuset/system-background/tasks
diff --git a/logd/main.cpp b/logd/main.cpp
index a0cea25..c3343d7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -37,14 +37,14 @@
 #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/sockets.h>
-#include <libminijail.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
-#include <scoped_minijail.h>
+#include <private/android_logger.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
@@ -89,29 +89,81 @@
 //    logd
 //
 
-static int drop_privs() {
+static int drop_privs(bool klogd, bool auditd) {
+    // Tricky, if ro.build.type is "eng" then this is true because of the
+    // side effect that ro.debuggable == 1 as well, else it is false.
+    bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
+
     struct sched_param param;
     memset(&param, 0, sizeof(param));
 
     if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-        return -1;
+        android::prdebug("failed to set background scheduling policy");
+        if (!eng) return -1;
     }
 
     if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
-        return -1;
+        android::prdebug("failed to set batch scheduler");
+        if (!eng) return -1;
     }
 
     if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+        android::prdebug("failed to set background cgroup");
+        if (!eng) return -1;
+    }
+
+    if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
+        android::prdebug("failed to clear PR_SET_DUMPABLE");
         return -1;
     }
 
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        android::prdebug("failed to set PR_SET_KEEPCAPS");
+        if (!eng) return -1;
+    }
+
+    std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+    if (cap_clear(caps.get()) < 0) return -1;
+    cap_value_t cap_value[] = {
+        CAP_SETGID, // must be first for below
+        klogd ? CAP_SYSLOG : CAP_SETGID,
+        auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
+    };
+    if (cap_set_flag(caps.get(), CAP_PERMITTED,
+                     arraysize(cap_value), cap_value,
+                     CAP_SET) < 0) return -1;
+    if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
+                     arraysize(cap_value), cap_value,
+                     CAP_SET) < 0) return -1;
+    if (cap_set_proc(caps.get()) < 0) {
+        android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
+        if (!eng) return -1;
+    }
+
     gid_t groups[] = { AID_READPROC };
-    ScopedMinijail j(minijail_new());
-    minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
-    minijail_change_uid(j.get(), AID_LOGD);
-    minijail_change_gid(j.get(), AID_LOGD);
-    minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
-    minijail_enter(j.get());
+
+    if (setgroups(arraysize(groups), groups) == -1) {
+        android::prdebug("failed to set AID_READPROC groups");
+        if (!eng) return -1;
+    }
+
+    if (setgid(AID_LOGD) != 0) {
+        android::prdebug("failed to set AID_LOGD gid");
+        if (!eng) return -1;
+    }
+
+    if (setuid(AID_LOGD) != 0) {
+        android::prdebug("failed to set AID_LOGD uid");
+        if (!eng) return -1;
+    }
+
+    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
+    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
+    if (cap_set_proc(caps.get()) < 0) {
+        android::prdebug("failed to clear CAP_SETGID (%d)", errno);
+        if (!eng) return -1;
+    }
+
     return 0;
 }
 
@@ -130,60 +182,6 @@
     return !*cp || !!strchr(sep, *cp);
 }
 
-bool property_get_bool(const char *key, int flag) {
-    char def[PROPERTY_VALUE_MAX];
-    char property[PROPERTY_VALUE_MAX];
-    def[0] = '\0';
-    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
-        char newkey[PROPERTY_KEY_MAX];
-        snprintf(newkey, sizeof(newkey), "ro.%s", key);
-        property_get(newkey, property, "");
-        // persist properties set by /data require inoculation with
-        // logd-reinit. They may be set in init.rc early and function, but
-        // otherwise are defunct unless reset. Do not rely on persist
-        // properties for startup-only keys unless you are willing to restart
-        // logd daemon (not advised).
-        snprintf(newkey, sizeof(newkey), "persist.%s", key);
-        property_get(newkey, def, property);
-    }
-
-    property_get(key, property, def);
-
-    if (check_flag(property, "true")) {
-        return true;
-    }
-    if (check_flag(property, "false")) {
-        return false;
-    }
-    if (check_flag(property, "eng")) {
-       flag |= BOOL_DEFAULT_FLAG_ENG;
-    }
-    // this is really a "not" flag
-    if (check_flag(property, "svelte")) {
-       flag |= BOOL_DEFAULT_FLAG_SVELTE;
-    }
-
-    // Sanity Check
-    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
-        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
-        flag |= BOOL_DEFAULT_TRUE;
-    }
-
-    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
-            && property_get_bool("ro.config.low_ram",
-                                 BOOL_DEFAULT_FALSE)) {
-        return false;
-    }
-    if (flag & BOOL_DEFAULT_FLAG_ENG) {
-        property_get("ro.debuggable", property, "");
-        if (strcmp(property, "1")) {
-            return false;
-        }
-    }
-
-    return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
-}
-
 static int fdDmesg = -1;
 void android::prdebug(const char *fmt, ...) {
     if (fdDmesg < 0) {
@@ -237,11 +235,16 @@
     set_sched_policy(0, SP_BACKGROUND);
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
 
-    // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
-    // else, we have even lesser privileges and accept our fate. Not worth
-    // checking for error returns setting this thread's privileges.
-    (void)setgid(AID_SYSTEM);
-    (void)setuid(AID_SYSTEM);
+    cap_t caps = cap_init();
+    (void)cap_clear(caps);
+    (void)cap_set_proc(caps);
+    (void)cap_free(caps);
+
+    // If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
+    // anything else, we have even lesser privileges and accept our fate. Not
+    // worth checking for error returns setting this thread's privileges.
+    (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
+    (void)setuid(AID_LOGD);   // access to everything logd.
 
     while (reinit_running && !sem_wait(&reinit) && reinit_running) {
 
@@ -308,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) {
@@ -359,6 +362,39 @@
     }
 }
 
+static int issueReinit() {
+    cap_t caps = cap_init();
+    (void)cap_clear(caps);
+    (void)cap_set_proc(caps);
+    (void)cap_free(caps);
+
+    int sock = TEMP_FAILURE_RETRY(
+        socket_local_client("logd",
+                            ANDROID_SOCKET_NAMESPACE_RESERVED,
+                            SOCK_STREAM));
+    if (sock < 0) return -errno;
+
+    static const char reinitStr[] = "reinit";
+    ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
+    if (ret < 0) return -errno;
+
+    struct pollfd p;
+    memset(&p, 0, sizeof(p));
+    p.fd = sock;
+    p.events = POLLIN;
+    ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
+    if (ret < 0) return -errno;
+    if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
+
+    static const char success[] = "success";
+    char buffer[sizeof(success) - 1];
+    memset(buffer, 0, sizeof(buffer));
+    ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
+    if (ret < 0) return -errno;
+
+    return strncmp(buffer, success, sizeof(success) - 1) != 0;
+}
+
 // Foreground waits for exit of the main persistent threads
 // that are started here. The threads are created to manage
 // UNIX domain client sockets for writing, reading and
@@ -366,50 +402,31 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
-    int fdPmesg = -1;
-    bool klogd = property_get_bool("logd.kernel",
-                                   BOOL_DEFAULT_TRUE |
-                                   BOOL_DEFAULT_FLAG_PERSIST |
-                                   BOOL_DEFAULT_FLAG_ENG |
-                                   BOOL_DEFAULT_FLAG_SVELTE);
-    if (klogd) {
-        fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
-    }
-    fdDmesg = open("/dev/kmsg", O_WRONLY);
-
     // issue reinit command. KISS argument parsing.
     if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
-        int sock = TEMP_FAILURE_RETRY(
-            socket_local_client("logd",
-                                ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                SOCK_STREAM));
-        if (sock < 0) {
-            return -errno;
+        return issueReinit();
+    }
+
+    static const char dev_kmsg[] = "/dev/kmsg";
+    fdDmesg = android_get_control_file(dev_kmsg);
+    if (fdDmesg < 0) {
+        fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
+    }
+
+    int fdPmesg = -1;
+    bool klogd = __android_logger_property_get_bool("logd.kernel",
+                                                    BOOL_DEFAULT_TRUE |
+                                                    BOOL_DEFAULT_FLAG_PERSIST |
+                                                    BOOL_DEFAULT_FLAG_ENG |
+                                                    BOOL_DEFAULT_FLAG_SVELTE);
+    if (klogd) {
+        static const char proc_kmsg[] = "/proc/kmsg";
+        fdPmesg = android_get_control_file(proc_kmsg);
+        if (fdPmesg < 0) {
+            fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
+                                              O_RDONLY | O_NDELAY | O_CLOEXEC));
         }
-        static const char reinit[] = "reinit";
-        ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
-        if (ret < 0) {
-            return -errno;
-        }
-        struct pollfd p;
-        memset(&p, 0, sizeof(p));
-        p.fd = sock;
-        p.events = POLLIN;
-        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
-        if (ret < 0) {
-            return -errno;
-        }
-        if ((ret == 0) || !(p.revents & POLLIN)) {
-            return -ETIME;
-        }
-        static const char success[] = "success";
-        char buffer[sizeof(success) - 1];
-        memset(buffer, 0, sizeof(buffer));
-        ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
-        if (ret < 0) {
-            return -errno;
-        }
-        return strncmp(buffer, success, sizeof(success) - 1) != 0;
+        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
     }
 
     // Reinit Thread
@@ -434,7 +451,10 @@
         pthread_attr_destroy(&attr);
     }
 
-    if (drop_privs() != 0) {
+    bool auditd = __android_logger_property_get_bool("logd.auditd",
+                                                     BOOL_DEFAULT_TRUE |
+                                                     BOOL_DEFAULT_FLAG_PERSIST);
+    if (drop_privs(klogd, auditd) != 0) {
         return -1;
     }
 
@@ -451,11 +471,11 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    if (property_get_bool("logd.statistics",
-                          BOOL_DEFAULT_TRUE |
-                          BOOL_DEFAULT_FLAG_PERSIST |
-                          BOOL_DEFAULT_FLAG_ENG |
-                          BOOL_DEFAULT_FLAG_SVELTE)) {
+    if (__android_logger_property_get_bool("logd.statistics",
+                                           BOOL_DEFAULT_TRUE |
+                                           BOOL_DEFAULT_FLAG_PERSIST |
+                                           BOOL_DEFAULT_FLAG_ENG |
+                                           BOOL_DEFAULT_FLAG_SVELTE)) {
         logBuf->enableStatistics();
     }
 
@@ -489,17 +509,14 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
-    bool auditd = property_get_bool("logd.auditd",
-                                    BOOL_DEFAULT_TRUE |
-                                    BOOL_DEFAULT_FLAG_PERSIST);
     LogAudit *al = NULL;
     if (auditd) {
         al = new LogAudit(logBuf, reader,
-                          property_get_bool("logd.auditd.dmesg",
-                                            BOOL_DEFAULT_TRUE |
-                                            BOOL_DEFAULT_FLAG_PERSIST)
-                              ? fdDmesg
-                              : -1);
+                          __android_logger_property_get_bool(
+                              "logd.auditd.dmesg",
+                              BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+                                  ? fdDmesg
+                                  : -1);
     }
 
     LogKlog *kl = NULL;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index cac8bce..254a3f8 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -23,11 +23,11 @@
 
 #include <string>
 
-#include <android/log.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 #include <gtest/gtest.h>
-#include <log/logger.h>
+#include <log/log.h>
 
 #include "../LogReader.h" // pickup LOGD_SNDTIMEO
 
@@ -352,7 +352,7 @@
         "/dev/log/system", "/dev/log_system",
     };
 
-    for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+    for (unsigned int i = 0; i < arraysize(loggers); ++i) {
         fd = open(loggers[i], O_RDONLY);
         if (fd < 0) {
             continue;
@@ -435,12 +435,12 @@
     static const unsigned int log_latency = 4;
     static const unsigned int log_delay = 5;
 
-    unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+    unsigned long ns[arraysize(benchmarks)];
 
     memset(ns, 0, sizeof(ns));
 
     while (fgets(buffer, sizeof(buffer), fp)) {
-        for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+        for (unsigned i = 0; i < arraysize(ns); ++i) {
             char *cp = strstr(buffer, benchmarks[i]);
             if (!cp) {
                 continue;
@@ -471,7 +471,7 @@
 
     EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
 
-    for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+    for (unsigned i = 0; i < arraysize(ns); ++i) {
         EXPECT_NE(0UL, ns[i]);
     }
 
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 41f0726..7ee0464 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -14,7 +14,6 @@
     local_include_dirs: ["include"],
     cflags: [
         "-Werror",
-        "-std=gnu99",
     ],
 }
 
@@ -31,6 +30,5 @@
     ],
     cflags: [
         "-Werror",
-        "-std=gnu99",
     ],
 }
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aa5a520..7d0c87d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -123,6 +123,7 @@
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     sbin dev proc sys system data oem acct 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 31b1821..11f91ce 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -294,7 +294,6 @@
     trigger early-boot
     trigger boot
 
-
 on post-fs
     start logd
     # once everything is setup, no need to modify /
@@ -306,7 +305,8 @@
     mount none none /storage slave rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
-    restorecon_recursive /sys/kernel/debug
+    # 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
@@ -446,10 +446,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
@@ -480,7 +476,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
@@ -646,10 +642,9 @@
     critical
     seclabel u:r:ueventd:s0
 
-service healthd /sbin/healthd
+service healthd /system/bin/healthd
     class core
     critical
-    seclabel u:r:healthd:s0
     group root system wakelock
 
 service console /system/bin/sh
@@ -669,13 +664,3 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
-
-service hwservicemanager /system/bin/hwservicemanager
-    user system
-    disabled
-    group system readproc
-    critical
-    writepid /dev/cpuset/system-background/tasks
-
-on property:hwservicemanager.ready=true
-    class_start hal
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 2d7d5c2..eedeba8 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,6 +1,8 @@
 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 4156847..84a907f 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,6 +1,8 @@
 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 8584cbb..76e2b79 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,6 +1,8 @@
 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 27eaa66..e918b67 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,6 +1,8 @@
 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     priority -20
+    user root
+    group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index f6dad8a..95559d7 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
 #define LOG_TAG "sdcard"
 
 #include "fuse.h"
@@ -223,7 +227,8 @@
 }
 
 static int touch(char* path, mode_t mode) {
-    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
+    int fd = TEMP_FAILURE_RETRY(open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
+                                     mode));
     if (fd == -1) {
         if (errno == EEXIST) {
             return 0;
@@ -469,27 +474,34 @@
     hdr.len = sizeof(hdr);
     hdr.error = err;
     hdr.unique = unique;
-    write(fuse->fd, &hdr, sizeof(hdr));
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fuse->fd, &hdr, sizeof(hdr)));
+    if (ret == -1) {
+        PLOG(ERROR) << "*** STATUS FAILED ***";
+    } else if (static_cast<size_t>(ret) != sizeof(hdr)) {
+        LOG(ERROR) << "*** STATUS FAILED: written " << ret << " expected "
+                   << sizeof(hdr) << " ***";
+    }
 }
 
 static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
 {
     struct fuse_out_header hdr;
-    struct iovec vec[2];
-    int res;
-
     hdr.len = len + sizeof(hdr);
     hdr.error = 0;
     hdr.unique = unique;
 
+    struct iovec vec[2];
     vec[0].iov_base = &hdr;
     vec[0].iov_len = sizeof(hdr);
     vec[1].iov_base = data;
     vec[1].iov_len = len;
 
-    res = writev(fuse->fd, vec, 2);
-    if (res < 0) {
+    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 2));
+    if (ret == -1) {
         PLOG(ERROR) << "*** REPLY FAILED ***";
+    } else if (static_cast<size_t>(ret) != sizeof(hdr) + len) {
+        LOG(ERROR) << "*** REPLY FAILED: written " << ret << " expected "
+                   << sizeof(hdr) + len << " ***";
     }
 }
 
@@ -501,7 +513,7 @@
     struct fuse_entry_out out;
     struct stat s;
 
-    if (lstat(path, &s) < 0) {
+    if (lstat(path, &s) == -1) {
         return -errno;
     }
 
@@ -528,7 +540,7 @@
     struct fuse_attr_out out;
     struct stat s;
 
-    if (lstat(path, &s) < 0) {
+    if (lstat(path, &s) == -1) {
         return -errno;
     }
     memset(&out, 0, sizeof(out));
@@ -542,10 +554,7 @@
         const __u64 child, const char* name) {
     struct fuse_out_header hdr;
     struct fuse_notify_delete_out data;
-    struct iovec vec[3];
     size_t namelen = strlen(name);
-    int res;
-
     hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
     hdr.error = FUSE_NOTIFY_DELETE;
     hdr.unique = 0;
@@ -555,6 +564,7 @@
     data.namelen = namelen;
     data.padding = 0;
 
+    struct iovec vec[3];
     vec[0].iov_base = &hdr;
     vec[0].iov_len = sizeof(hdr);
     vec[1].iov_base = &data;
@@ -562,10 +572,15 @@
     vec[2].iov_base = (void*) name;
     vec[2].iov_len = namelen + 1;
 
-    res = writev(fuse->fd, vec, 3);
+    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 3));
     /* Ignore ENOENT, since other views may not have seen the entry */
-    if (res < 0 && errno != ENOENT) {
-        PLOG(ERROR) << "*** NOTIFY FAILED ***";
+    if (ret == -1) {
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "*** NOTIFY FAILED ***";
+        }
+    } else if (static_cast<size_t>(ret) != sizeof(hdr) + sizeof(data) + namelen + 1) {
+        LOG(ERROR) << "*** NOTIFY FAILED: written " << ret << " expected "
+                   << sizeof(hdr) + sizeof(data) + namelen + 1 << " ***";
     }
 }
 
@@ -665,7 +680,7 @@
     /* XXX: incomplete implementation on purpose.
      * chmod/chown should NEVER be implemented.*/
 
-    if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
+    if ((req->valid & FATTR_SIZE) && TEMP_FAILURE_RETRY(truncate64(path, req->size)) == -1) {
         return -errno;
     }
 
@@ -727,7 +742,7 @@
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0664;
-    if (mknod(child_path, mode, req->rdev) < 0) {
+    if (mknod(child_path, mode, req->rdev) == -1) {
         return -errno;
     }
     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
@@ -757,7 +772,7 @@
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0775;
-    if (mkdir(child_path, mode) < 0) {
+    if (mkdir(child_path, mode) == -1) {
         return -errno;
     }
 
@@ -804,7 +819,7 @@
     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
-    if (unlink(child_path) < 0) {
+    if (unlink(child_path) == -1) {
         return -errno;
     }
     pthread_mutex_lock(&fuse->global->lock);
@@ -854,7 +869,7 @@
     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
-    if (rmdir(child_path) < 0) {
+    if (rmdir(child_path) == -1) {
         return -errno;
     }
     pthread_mutex_lock(&fuse->global->lock);
@@ -942,7 +957,7 @@
 
     DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
     res = rename(old_child_path, new_child_path);
-    if (res < 0) {
+    if (res == -1) {
         res = -errno;
         goto io_error;
     }
@@ -1004,8 +1019,8 @@
         return -ENOMEM;
     }
     DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
-    h->fd = open(path, req->flags);
-    if (h->fd < 0) {
+    h->fd = TEMP_FAILURE_RETRY(open(path, req->flags));
+    if (h->fd == -1) {
         free(h);
         return -errno;
     }
@@ -1034,8 +1049,8 @@
     if (size > MAX_READ) {
         return -EINVAL;
     }
-    res = pread64(h->fd, read_buffer, size, offset);
-    if (res < 0) {
+    res = TEMP_FAILURE_RETRY(pread64(h->fd, read_buffer, size, offset));
+    if (res == -1) {
         return -errno;
     }
     fuse_reply(fuse, unique, read_buffer, res);
@@ -1058,8 +1073,8 @@
 
     DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
                << "(" << h->fd << ") " << req->size << "@" << req->offset;
-    res = pwrite64(h->fd, buffer, req->size, req->offset);
-    if (res < 0) {
+    res = TEMP_FAILURE_RETRY(pwrite64(h->fd, buffer, req->size, req->offset));
+    if (res == -1) {
         return -errno;
     }
     out.size = res;
@@ -1083,7 +1098,7 @@
     if (res < 0) {
         return -ENOENT;
     }
-    if (statfs(fuse->global->root.name, &stat) < 0) {
+    if (TEMP_FAILURE_RETRY(statfs(fuse->global->root.name, &stat)) == -1) {
         return -errno;
     }
     memset(&out, 0, sizeof(out));
@@ -1245,12 +1260,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;
@@ -1291,7 +1303,6 @@
     return NO_STATUS;
 }
 
-
 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const void *data, size_t data_len)
 {
@@ -1425,7 +1436,7 @@
     for (;;) {
         ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
                 handler->request_buffer, sizeof(handler->request_buffer)));
-        if (len < 0) {
+        if (len == -1) {
             if (errno == ENODEV) {
                 LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
                 exit(2);
@@ -1434,14 +1445,14 @@
             continue;
         }
 
-        if ((size_t)len < sizeof(struct fuse_in_header)) {
+        if (static_cast<size_t>(len) < sizeof(struct fuse_in_header)) {
             LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
             continue;
         }
 
         const struct fuse_in_header* hdr =
             reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
-        if (hdr->len != (size_t)len) {
+        if (hdr->len != static_cast<size_t>(len)) {
             LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
                        << ", hdr->len=" << hdr->len;
             continue;
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 70bbf26..bc502a0 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -111,7 +111,7 @@
     char event_buf[512];
 
     int nfd = inotify_init();
-    if (nfd < 0) {
+    if (nfd == -1) {
         PLOG(ERROR) << "inotify_init failed";
         return;
     }
@@ -142,17 +142,19 @@
         }
 
         int event_pos = 0;
-        int res = read(nfd, event_buf, sizeof(event_buf));
-        if (res < (int) sizeof(*event)) {
-            if (errno == EINTR)
-                continue;
+        ssize_t res = TEMP_FAILURE_RETRY(read(nfd, event_buf, sizeof(event_buf)));
+        if (res == -1) {
             PLOG(ERROR) << "failed to read inotify event";
             return;
+        } else if (static_cast<size_t>(res) < sizeof(*event)) {
+            LOG(ERROR) << "failed to read inotify event: read " << res << " expected "
+                       << sizeof(event_buf);
+            return;
         }
 
-        while (res >= (int) sizeof(*event)) {
+        while (res >= static_cast<ssize_t>(sizeof(*event))) {
             int event_size;
-            event = (struct inotify_event *) (event_buf + event_pos);
+            event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
 
             DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec;
             if ((event->mask & IN_IGNORED) == IN_IGNORED) {
@@ -171,7 +173,7 @@
 static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
     char opts[256];
 
-    fuse->fd = open("/dev/fuse", O_RDWR);
+    fuse->fd = TEMP_FAILURE_RETRY(open("/dev/fuse", O_RDWR | O_CLOEXEC));
     if (fuse->fd == -1) {
         PLOG(ERROR) << "failed to open fuse device";
         return -1;
@@ -182,8 +184,8 @@
     snprintf(opts, sizeof(opts),
             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
             fuse->fd, fuse->global->uid, fuse->global->gid);
-    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
-            MS_NOATIME, opts) != 0) {
+    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME,
+              opts) == -1) {
         PLOG(ERROR) << "failed to mount fuse filesystem";
         return -1;
     }
@@ -321,7 +323,7 @@
             fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
 
     if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
-                        MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+              MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
         PLOG(ERROR) << "failed to mount sdcardfs filesystem";
         return false;
     }
@@ -480,7 +482,7 @@
 
     rlim.rlim_cur = 8192;
     rlim.rlim_max = 8192;
-    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
+    if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
         PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
     }
 
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 4852fa4..5319ff4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -42,7 +42,6 @@
 
 LOCAL_CFLAGS += $(common_cflags)
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_CONLYFLAGS += -std=gnu99
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
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/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
index ae536c5..45e65a7 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -17,8 +17,10 @@
 #define LOG_TAG "TrustyGateKeeper"
 
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <android/log.h>
 #include <trusty/tipc.h>
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
index 0159bce..8755093 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <android/log.h>
 #include <trusty/tipc.h>
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index ba16bee..2398a53 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -22,6 +22,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
 #include <android/log.h>
 
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
index caa25ab..ddaf333 100644
--- a/trusty/nvram/trusty_nvram_implementation.cpp
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <android/log.h>
 #include <hardware/nvram.h>
diff --git a/trusty/storage/proxy/ipc.c b/trusty/storage/proxy/ipc.c
index b4748e2..57cf600 100644
--- a/trusty/storage/proxy/ipc.c
+++ b/trusty/storage/proxy/ipc.c
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/uio.h>
+#include <unistd.h>
 
 #include <trusty/tipc.h>
 
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 9130458..9c79105 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <unistd.h>
 
 #include <linux/major.h>
 #include <linux/mmc/ioctl.h>