Merge "adb: fix adb trace tag"
diff --git a/adb/Android.mk b/adb/Android.mk
index be04cfa..16ed991 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -50,6 +50,7 @@
     fdevent.cpp \
     sockets.cpp \
     socket_spec.cpp \
+    sysdeps/errno.cpp \
     transport.cpp \
     transport_local.cpp \
     transport_usb.cpp \
@@ -88,10 +89,12 @@
 
 LIBADB_windows_SRC_FILES := \
     sysdeps_win32.cpp \
+    sysdeps/win32/errno.cpp \
     sysdeps/win32/stat.cpp \
     usb_windows.cpp \
 
 LIBADB_TEST_windows_SRCS := \
+    sysdeps/win32/errno_test.cpp \
     sysdeps_win32_test.cpp \
 
 include $(CLEAR_VARS)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 8b6b2b5..3cd50ba 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -30,7 +30,9 @@
 #include <sys/time.h>
 #include <time.h>
 
+#include <chrono>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/errors.h>
@@ -51,6 +53,7 @@
 #include <sys/capability.h>
 #include <sys/mount.h>
 #include <android-base/properties.h>
+using namespace std::chrono_literals;
 #endif
 
 std::string adb_version() {
@@ -375,7 +378,7 @@
                     adbd_auth_verified(t);
                     t->failed_auth_attempts = 0;
                 } else {
-                    if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
+                    if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
                     send_auth_request(t);
                 }
                 break;
diff --git a/adb/adb.h b/adb/adb.h
index df59aaa..19f09a3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -51,7 +51,7 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 37
+#define ADB_SERVER_VERSION 38
 
 class atransport;
 struct usb_handle;
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index ff2d76d..ec9b1c3 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -207,11 +207,6 @@
     }
 
     if (S_ISREG(st.st_mode)) {
-        if (!android::base::EndsWith(path, ".adb_key")) {
-            LOG(INFO) << "skipping non-adb_key '" << path << "'";
-            return false;
-        }
-
         return read_key_file(path);
     } else if (S_ISDIR(st.st_mode)) {
         if (!allow_dir) {
@@ -236,7 +231,12 @@
                 continue;
             }
 
-            result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false);
+            if (!android::base::EndsWith(name, ".adb_key")) {
+                LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
+                continue;
+            }
+
+            result |= read_key_file((path + OS_PATH_SEPARATOR + name));
         }
         return result;
     }
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 919e1c1..ef52189 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,27 +39,18 @@
 #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;
 
 static const char* __adb_server_socket_spec;
 
-void adb_set_transport(TransportType type, const char* serial)
-{
+void adb_set_transport(TransportType type, const char* serial) {
     __adb_transport = type;
     __adb_serial = serial;
 }
 
-void adb_get_transport(TransportType* type, const char** serial) {
-    if (type) {
-        *type = __adb_transport;
-    }
-    if (serial) {
-        *serial = __adb_serial;
-    }
-}
-
 void adb_set_socket_spec(const char* socket_spec) {
     if (__adb_server_socket_spec) {
         LOG(FATAL) << "attempted to reinitialize adb_server_socket_spec " << socket_spec << " (was " << __adb_server_socket_spec << ")";
@@ -188,8 +180,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 +226,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_client.h b/adb/adb_client.h
index d35d705..d07c1e9 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -40,9 +40,6 @@
 // Set the preferred transport to connect to.
 void adb_set_transport(TransportType type, const char* _Nullable serial);
 
-// Get the preferred transport to connect to.
-void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial);
-
 // Set the socket specification for the adb server.
 // This function can only be called once, and the argument must live to the end of the process.
 void adb_set_socket_spec(const char* _Nonnull socket_spec);
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.h b/adb/adb_trace.h
index 5206a99..aaffa29 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -58,4 +58,8 @@
 void adb_trace_init(char**);
 void adb_trace_enable(AdbTrace trace_tag);
 
+#define ATRACE_TAG ATRACE_TAG_ADB
+#include <cutils/trace.h>
+#include <utils/Trace.h>
+
 #endif /* __ADB_TRACE_H */
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 143c62a..9b59d05 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -21,7 +21,6 @@
 #include <string>
 #include <vector>
 
-#include <android-base/parseint.h>
 #include <android-base/strings.h>
 
 #include "sysdeps.h"
@@ -144,11 +143,9 @@
             //
             size_t idx1 = line.rfind(BUGZ_PROGRESS_PREFIX) + strlen(BUGZ_PROGRESS_PREFIX);
             size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR);
-            int progress, total;
-            if (android::base::ParseInt(line.substr(idx1, (idx2 - idx1)), &progress) &&
-                android::base::ParseInt(line.substr(idx2 + 1), &total)) {
-                br_->UpdateProgress(line_message_, progress, total);
-            }
+            int progress = std::stoi(line.substr(idx1, (idx2 - idx1)));
+            int total = std::stoi(line.substr(idx2 + 1));
+            br_->UpdateProgress(line_message_, progress, total);
         } else {
             invalid_lines_.push_back(line);
         }
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 4ec0fc2..d583516 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -23,6 +23,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <thread>
+
 #include <android-base/errors.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -33,6 +35,7 @@
 #include "adb_listeners.h"
 #include "adb_utils.h"
 #include "commandline.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 
 static std::string GetLogFilePath() {
@@ -113,8 +116,18 @@
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
 
     std::string error;
-    if (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error)) {
-        fatal("could not install *smartsocket* listener: %s", error.c_str());
+
+    auto start = std::chrono::steady_clock::now();
+
+    // If we told a previous adb server to quit because of version mismatch, we can get to this
+    // point before it's finished exiting. Retry for a while to give it some time.
+    while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
+           INSTALL_STATUS_OK) {
+        if (std::chrono::steady_clock::now() - start > 0.5s) {
+            fatal("could not install *smartsocket* listener: %s", error.c_str());
+        }
+
+        std::this_thread::sleep_for(100ms);
     }
 
     if (is_daemon) {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e15bcad..a064de2 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -33,6 +33,7 @@
 
 #include <memory>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/file.h>
@@ -59,6 +60,7 @@
 #include "file_sync_service.h"
 #include "services.h"
 #include "shell_service.h"
+#include "sysdeps/chrono.h"
 
 static int install_app(TransportType t, const char* serial, int argc, const char** argv);
 static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
@@ -1080,7 +1082,7 @@
 
     // Give adbd some time to kill itself and come back up.
     // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
-    adb_sleep_ms(3000);
+    std::this_thread::sleep_for(3s);
     return true;
 }
 
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index f1e4179..271943d 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -15,12 +15,10 @@
  */
 
 #include <dirent.h>
-#include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -43,6 +41,8 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 #include "line_printer.h"
+#include "sysdeps/errno.h"
+#include "sysdeps/stat.h"
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
@@ -64,22 +64,18 @@
 }
 
 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 {
     std::string lpath;
     std::string rpath;
-    unsigned int time = 0;
-    unsigned int mode;
+    int64_t time = 0;
+    uint32_t mode;
     uint64_t size = 0;
     bool skip = false;
 
@@ -149,7 +145,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%.
@@ -206,9 +202,16 @@
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
-        fd = adb_connect("sync:", &error);
-        if (fd < 0) {
-            Error("connect failed: %s", error.c_str());
+        FeatureSet features;
+        if (!adb_get_feature_set(&features, &error)) {
+            fd = -1;
+            Error("failed to get feature set: %s", error.c_str());
+        } else {
+            have_stat_v2_ = CanUseFeature(features, kFeatureStat2);
+            fd = adb_connect("sync:", &error);
+            if (fd < 0) {
+                Error("connect failed: %s", error.c_str());
+            }
         }
     }
 
@@ -295,6 +298,77 @@
         return WriteFdExactly(fd, &buf[0], buf.size());
     }
 
+    bool SendStat(const char* path_and_mode) {
+        if (!have_stat_v2_) {
+            errno = ENOTSUP;
+            return false;
+        }
+        return SendRequest(ID_STAT_V2, path_and_mode);
+    }
+
+    bool SendLstat(const char* path_and_mode) {
+        if (have_stat_v2_) {
+            return SendRequest(ID_LSTAT_V2, path_and_mode);
+        } else {
+            return SendRequest(ID_LSTAT_V1, path_and_mode);
+        }
+    }
+
+    bool FinishStat(struct stat* st) {
+        syncmsg msg;
+
+        memset(st, 0, sizeof(*st));
+        if (have_stat_v2_) {
+            if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
+                fatal_errno("protocol fault: failed to read stat response");
+            }
+
+            if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
+                fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
+                            msg.stat_v2.id);
+            }
+
+            if (msg.stat_v2.error != 0) {
+                errno = errno_from_wire(msg.stat_v2.error);
+                return false;
+            }
+
+            st->st_dev = msg.stat_v2.dev;
+            st->st_ino = msg.stat_v2.ino;
+            st->st_mode = msg.stat_v2.mode;
+            st->st_nlink = msg.stat_v2.nlink;
+            st->st_uid = msg.stat_v2.uid;
+            st->st_gid = msg.stat_v2.gid;
+            st->st_size = msg.stat_v2.size;
+            st->st_atime = msg.stat_v2.atime;
+            st->st_mtime = msg.stat_v2.mtime;
+            st->st_ctime = msg.stat_v2.ctime;
+            return true;
+        } else {
+            if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
+                fatal_errno("protocol fault: failed to read stat response");
+            }
+
+            if (msg.stat_v1.id != ID_LSTAT_V1) {
+                fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
+                            msg.stat_v1.id);
+            }
+
+            if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
+                // There's no way for us to know what the error was.
+                errno = ENOPROTOOPT;
+                return false;
+            }
+
+            st->st_mode = msg.stat_v1.mode;
+            st->st_size = msg.stat_v1.size;
+            st->st_ctime = msg.stat_v1.time;
+            st->st_mtime = msg.stat_v1.time;
+        }
+
+        return true;
+    }
+
     // Sending header, payload, and footer in a single write makes a huge
     // difference to "adb sync" performance.
     bool SendSmallFile(const char* path_and_mode,
@@ -432,7 +506,7 @@
             return false;
         }
         buf[msg.status.msglen] = 0;
-        Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
+        Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
         return false;
     }
 
@@ -503,6 +577,7 @@
 
   private:
     bool expect_done_;
+    bool have_stat_v2_;
 
     TransferLedger global_ledger_;
     TransferLedger current_ledger_;
@@ -558,25 +633,47 @@
     }
 }
 
-static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
-                             unsigned int* mode, unsigned int* size) {
-    syncmsg msg;
-    if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
+static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
+    return sc.SendStat(path) && sc.FinishStat(st);
+}
+
+static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
+    return sc.SendLstat(path) && sc.FinishStat(st);
+}
+
+static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
+    if (sync_stat(sc, path, st)) {
+        return true;
+    }
+
+    if (errno != ENOTSUP) {
         return false;
     }
 
-    if (timestamp) *timestamp = msg.stat.time;
-    if (mode) *mode = msg.stat.mode;
-    if (size) *size = msg.stat.size;
+    // Try to emulate the parts we can when talking to older adbds.
+    bool lstat_result = sync_lstat(sc, path, st);
+    if (!lstat_result) {
+        return false;
+    }
 
+    if (S_ISLNK(st->st_mode)) {
+        // If the target is a symlink, figure out whether it's a file or a directory.
+        // Also, zero out the st_size field, since no one actually cares what the path length is.
+        st->st_size = 0;
+        std::string dir_path = path;
+        dir_path.push_back('/');
+        struct stat tmp_st;
+
+        st->st_mode &= ~S_IFMT;
+        if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
+            st->st_mode |= S_IFDIR;
+        } else {
+            st->st_mode |= S_IFREG;
+        }
+    }
     return true;
 }
 
-static bool sync_stat(SyncConnection& sc, const char* path,
-                      unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
-    return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
-}
-
 static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
                       unsigned mtime, mode_t mode)
 {
@@ -623,10 +720,7 @@
 }
 
 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
-                      const char* name=nullptr) {
-    unsigned size = 0;
-    if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
-
+                      const char* name, uint64_t expected_size) {
     if (!sc.SendRequest(ID_RECV, rpath)) return false;
 
     adb_unlink(lpath);
@@ -678,7 +772,7 @@
         bytes_copied += msg.data.size;
 
         sc.RecordBytesTransferred(msg.data.size);
-        sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size);
+        sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
     }
 
     sc.RecordFilesTransferred(1);
@@ -781,20 +875,20 @@
 
     if (check_timestamps) {
         for (const copyinfo& ci : file_list) {
-            if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
+            if (!sc.SendLstat(ci.rpath.c_str())) {
+                sc.Error("failed to send lstat");
                 return false;
             }
         }
         for (copyinfo& ci : file_list) {
-            unsigned int timestamp, mode, size;
-            if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
-                return false;
-            }
-            if (size == ci.size) {
-                // For links, we cannot update the atime/mtime.
-                if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
-                        (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
-                    ci.skip = true;
+            struct stat st;
+            if (sc.FinishStat(&st)) {
+                if (st.st_size == static_cast<off_t>(ci.size)) {
+                    // For links, we cannot update the atime/mtime.
+                    if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) ||
+                        (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) {
+                        ci.skip = true;
+                    }
                 }
             }
         }
@@ -826,10 +920,22 @@
     if (!sc.IsValid()) return false;
 
     bool success = true;
-    unsigned dst_mode;
-    if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
-    bool dst_exists = (dst_mode != 0);
-    bool dst_isdir = S_ISDIR(dst_mode);
+    bool dst_exists;
+    bool dst_isdir;
+
+    struct stat st;
+    if (sync_stat_fallback(sc, dst, &st)) {
+        dst_exists = true;
+        dst_isdir = S_ISDIR(st.st_mode);
+    } else {
+        if (errno == ENOENT || errno == ENOPROTOOPT) {
+            dst_exists = false;
+            dst_isdir = false;
+        } else {
+            sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno));
+            return false;
+        }
+    }
 
     if (!dst_isdir) {
         if (srcs.size() > 1) {
@@ -874,8 +980,7 @@
                 dst_dir.append(adb_basename(src_path));
             }
 
-            success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
-                                             false, false);
+            success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false);
             continue;
         } else if (!should_push_file(st.st_mode)) {
             sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
@@ -904,17 +1009,6 @@
     return success;
 }
 
-static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
-    unsigned mode;
-    std::string dir_path = rpath;
-    dir_path.push_back('/');
-    if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
-        sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
-        return false;
-    }
-    return S_ISDIR(mode);
-}
-
 static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
                               const std::string& rpath, const std::string& lpath) {
     std::vector<copyinfo> dirlist;
@@ -952,7 +1046,13 @@
 
     // Check each symlink we found to see whether it's a file or directory.
     for (copyinfo& link_ci : linklist) {
-        if (remote_symlink_isdir(sc, link_ci.rpath)) {
+        struct stat st;
+        if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
+            sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
+            continue;
+        }
+
+        if (S_ISDIR(st.st_mode)) {
             dirlist.emplace_back(std::move(link_ci));
         } else {
             file_list->emplace_back(std::move(link_ci));
@@ -1015,7 +1115,7 @@
                 continue;
             }
 
-            if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
+            if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size)) {
                 return false;
             }
 
@@ -1078,22 +1178,19 @@
 
     for (const char* src_path : srcs) {
         const char* dst_path = dst;
-        unsigned src_mode, src_time, src_size;
-        if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
-            sc.Error("failed to stat remote object '%s'", src_path);
-            return false;
-        }
-        if (src_mode == 0) {
-            sc.Error("remote object '%s' does not exist", src_path);
+        struct stat src_st;
+        if (!sync_stat_fallback(sc, src_path, &src_st)) {
+            if (errno == ENOPROTOOPT) {
+                sc.Error("remote object '%s' does not exist", src_path);
+            } else {
+                sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno));
+            }
+
             success = false;
             continue;
         }
 
-        bool src_isdir = S_ISDIR(src_mode);
-        if (S_ISLNK(src_mode)) {
-            src_isdir = remote_symlink_isdir(sc, src_path);
-        }
-
+        bool src_isdir = S_ISDIR(src_st.st_mode);
         if (src_isdir) {
             std::string dst_dir = dst;
 
@@ -1112,8 +1209,8 @@
 
             success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
             continue;
-        } else if (!should_pull_file(src_mode)) {
-            sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode);
+        } else if (!should_pull_file(src_st.st_mode)) {
+            sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
             continue;
         }
 
@@ -1128,13 +1225,13 @@
         }
 
         sc.NewTransfer();
-        sc.SetExpectedTotalBytes(src_size);
-        if (!sync_recv(sc, src_path, dst_path, name)) {
+        sc.SetExpectedTotalBytes(src_st.st_size);
+        if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size)) {
             success = false;
             continue;
         }
 
-        if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
+        if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) {
             success = false;
             continue;
         }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 7a92d2e..e667bf8 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -39,8 +39,12 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_trace.h"
 #include "adb_utils.h"
 #include "security_log_tags.h"
+#include "sysdeps/errno.h"
+
+using android::base::StringPrintf;
 
 static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
@@ -98,18 +102,47 @@
     return true;
 }
 
-static bool do_stat(int s, const char* path) {
-    syncmsg msg;
-    msg.stat.id = ID_STAT;
+static bool do_lstat_v1(int s, const char* path) {
+    syncmsg msg = {};
+    msg.stat_v1.id = ID_LSTAT_V1;
 
     struct stat st = {};
-    // TODO: add a way to report that the stat failed!
     lstat(path, &st);
-    msg.stat.mode = st.st_mode;
-    msg.stat.size = st.st_size;
-    msg.stat.time = st.st_mtime;
+    msg.stat_v1.mode = st.st_mode;
+    msg.stat_v1.size = st.st_size;
+    msg.stat_v1.time = st.st_mtime;
+    return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1));
+}
 
-    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat));
+static bool do_stat_v2(int s, uint32_t id, const char* path) {
+    syncmsg msg = {};
+    msg.stat_v2.id = id;
+
+    decltype(&stat) stat_fn;
+    if (id == ID_STAT_V2) {
+        stat_fn = stat;
+    } else {
+        stat_fn = lstat;
+    }
+
+    struct stat st = {};
+    int rc = stat_fn(path, &st);
+    if (rc == -1) {
+        msg.stat_v2.error = errno_to_wire(errno);
+    } else {
+        msg.stat_v2.dev = st.st_dev;
+        msg.stat_v2.ino = st.st_ino;
+        msg.stat_v2.mode = st.st_mode;
+        msg.stat_v2.nlink = st.st_nlink;
+        msg.stat_v2.uid = st.st_uid;
+        msg.stat_v2.gid = st.st_gid;
+        msg.stat_v2.size = st.st_size;
+        msg.stat_v2.atime = st.st_atime;
+        msg.stat_v2.mtime = st.st_mtime;
+        msg.stat_v2.ctime = st.st_ctime;
+    }
+
+    return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
 }
 
 static bool do_list(int s, const char* path) {
@@ -122,7 +155,7 @@
     if (!d) goto done;
 
     while ((de = readdir(d.get()))) {
-        std::string filename(android::base::StringPrintf("%s/%s", path, de->d_name));
+        std::string filename(StringPrintf("%s/%s", path, de->d_name));
 
         struct stat st;
         if (lstat(filename.c_str(), &st) == 0) {
@@ -161,7 +194,7 @@
 }
 
 static bool SendSyncFailErrno(int fd, const std::string& reason) {
-    return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
+    return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
 }
 
 static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
@@ -403,9 +436,31 @@
     return WriteFdExactly(s, &msg.data, sizeof(msg.data));
 }
 
+static const char* sync_id_to_name(uint32_t id) {
+  switch (id) {
+    case ID_LSTAT_V1:
+      return "lstat_v1";
+    case ID_LSTAT_V2:
+      return "lstat_v2";
+    case ID_STAT_V2:
+      return "stat_v2";
+    case ID_LIST:
+      return "list";
+    case ID_SEND:
+      return "send";
+    case ID_RECV:
+      return "recv";
+    case ID_QUIT:
+        return "quit";
+    default:
+        return "???";
+  }
+}
+
 static bool handle_sync_command(int fd, std::vector<char>& buffer) {
     D("sync: waiting for request");
 
+    ATRACE_CALL();
     SyncRequest request;
     if (!ReadFdExactly(fd, &request, sizeof(request))) {
         SendSyncFail(fd, "command read failure");
@@ -423,34 +478,39 @@
     }
     name[path_length] = 0;
 
-    const char* id = reinterpret_cast<const char*>(&request.id);
-    D("sync: '%.4s' '%s'", id, name);
+    std::string id_name = sync_id_to_name(request.id);
+    std::string trace_name = StringPrintf("%s(%s)", id_name.c_str(), name);
+    ATRACE_NAME(trace_name.c_str());
 
+    D("sync: %s('%s')", id_name.c_str(), name);
     switch (request.id) {
-      case ID_STAT:
-        if (!do_stat(fd, name)) return false;
-        break;
-      case ID_LIST:
-        if (!do_list(fd, name)) return false;
-        break;
-      case ID_SEND:
-        if (!do_send(fd, name, buffer)) return false;
-        break;
-      case ID_RECV:
-        if (!do_recv(fd, name, buffer)) return false;
-        break;
-      case ID_QUIT:
-        return false;
-      default:
-        SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
-                                                     id, request.id));
-        return false;
+        case ID_LSTAT_V1:
+            if (!do_lstat_v1(fd, name)) return false;
+            break;
+        case ID_LSTAT_V2:
+        case ID_STAT_V2:
+            if (!do_stat_v2(fd, request.id, name)) return false;
+            break;
+        case ID_LIST:
+            if (!do_list(fd, name)) return false;
+            break;
+        case ID_SEND:
+            if (!do_send(fd, name, buffer)) return false;
+            break;
+        case ID_RECV:
+            if (!do_recv(fd, name, buffer)) return false;
+            break;
+        case ID_QUIT:
+            return false;
+        default:
+            SendSyncFail(fd, StringPrintf("unknown command %08x", request.id));
+            return false;
     }
 
     return true;
 }
 
-void file_sync_service(int fd, void* cookie) {
+void file_sync_service(int fd, void*) {
     std::vector<char> buffer(SYNC_DATA_MAX);
 
     while (handle_sync_command(fd, buffer)) {
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 0e25974..90f1965 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -22,7 +22,9 @@
 
 #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
 
-#define ID_STAT MKID('S','T','A','T')
+#define ID_LSTAT_V1 MKID('S','T','A','T')
+#define ID_STAT_V2 MKID('S','T','A','2')
+#define ID_LSTAT_V2 MKID('L','S','T','2')
 #define ID_LIST MKID('L','I','S','T')
 #define ID_SEND MKID('S','E','N','D')
 #define ID_RECV MKID('R','E','C','V')
@@ -45,7 +47,21 @@
         uint32_t mode;
         uint32_t size;
         uint32_t time;
-    } stat;
+    } stat_v1;
+    struct __attribute__((packed)) {
+        uint32_t id;
+        uint32_t error;
+        uint64_t dev;
+        uint64_t ino;
+        uint32_t mode;
+        uint32_t nlink;
+        uint32_t uid;
+        uint32_t gid;
+        uint64_t size;
+        int64_t atime;
+        int64_t mtime;
+        int64_t ctime;
+    } stat_v2;
     struct __attribute__((packed)) {
         uint32_t id;
         uint32_t mode;
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index e2b388b..4975fab 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -106,20 +106,6 @@
 
 namespace {
 
-void init_subproc_child()
-{
-    setsid();
-
-    // Set OOM score adjustment to prevent killing
-    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        adb_write(fd, "0", 1);
-        adb_close(fd);
-    } else {
-       D("adb: unable to update oom_score_adj");
-    }
-}
-
 // Reads from |fd| until close or failure.
 std::string ReadAll(int fd) {
     char buffer[512];
@@ -316,7 +302,7 @@
 
     if (pid_ == 0) {
         // Subprocess child.
-        init_subproc_child();
+        setsid();
 
         if (type_ == SubprocessType::kPty) {
             child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5e79b5e..f56f7f7 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -22,6 +22,7 @@
 #include <limits>
 #include <queue>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <unistd.h>
@@ -31,6 +32,7 @@
 #include "fdevent_test.h"
 #include "socket.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
 
 struct ThreadArg {
     int first_read_fd;
@@ -44,7 +46,7 @@
     fdevent_loop();
 }
 
-const size_t SLEEP_FOR_FDEVENT_IN_MS = 100;
+constexpr auto SLEEP_FOR_FDEVENT = 100ms;
 
 TEST_F(LocalSocketTest, smoke) {
     // Join two socketpairs with a chain of intermediate socketpairs.
@@ -101,7 +103,7 @@
     ASSERT_EQ(0, adb_close(last[1]));
 
     // Wait until the local sockets are closed.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -154,12 +156,12 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -179,9 +181,9 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Verify if we can read successfully.
@@ -190,7 +192,7 @@
     ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -214,11 +216,11 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
@@ -229,7 +231,7 @@
     std::string error;
     int fd = network_loopback_client(5038, SOCK_STREAM, &error);
     ASSERT_GE(fd, 0) << error;
-    adb_sleep_ms(200);
+    std::this_thread::sleep_for(200ms);
     ASSERT_EQ(0, adb_close(fd));
 }
 
@@ -265,13 +267,13 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Wait until the client closes its socket.
     ASSERT_TRUE(adb_thread_join(client_thread));
 
-    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index ad9b9fd..654072c 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -34,6 +34,7 @@
 #include <android-base/unique_fd.h>
 #include <android-base/utf8.h>
 
+#include "sysdeps/errno.h"
 #include "sysdeps/stat.h"
 
 /*
@@ -180,8 +181,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 +247,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);
@@ -368,9 +362,6 @@
 
 #define getcwd adb_getcwd
 
-char* adb_strerror(int err);
-#define strerror adb_strerror
-
 // Helper class to convert UTF-16 argv from wmain() to UTF-8 args that can be
 // passed to main().
 class NarrowArgs {
@@ -766,11 +757,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/errno.cpp b/adb/sysdeps/errno.cpp
new file mode 100644
index 0000000..6869947
--- /dev/null
+++ b/adb/sysdeps/errno.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 "sysdeps/errno.h"
+
+#include <errno.h>
+
+#include <thread>
+#include <unordered_map>
+#include <utility>
+
+#include "adb.h"
+
+#if defined(_WIN32)
+#define ETXTBSY EBUSY
+#endif
+
+// Use the linux asm-generic values for errno (which are used on all android archs but mips).
+#define ERRNO_VALUES()             \
+    ERRNO_VALUE(EACCES, 13);       \
+    ERRNO_VALUE(EEXIST, 17);       \
+    ERRNO_VALUE(EFAULT, 14);       \
+    ERRNO_VALUE(EFBIG, 27);        \
+    ERRNO_VALUE(EINTR, 4);         \
+    ERRNO_VALUE(EINVAL, 22);       \
+    ERRNO_VALUE(EIO, 5);           \
+    ERRNO_VALUE(EISDIR, 21);       \
+    ERRNO_VALUE(ELOOP, 40);        \
+    ERRNO_VALUE(EMFILE, 24);       \
+    ERRNO_VALUE(ENAMETOOLONG, 36); \
+    ERRNO_VALUE(ENFILE, 23);       \
+    ERRNO_VALUE(ENOENT, 2);        \
+    ERRNO_VALUE(ENOMEM, 12);       \
+    ERRNO_VALUE(ENOSPC, 28);       \
+    ERRNO_VALUE(ENOTDIR, 20);      \
+    ERRNO_VALUE(EOVERFLOW, 75);    \
+    ERRNO_VALUE(EPERM, 1);         \
+    ERRNO_VALUE(EROFS, 30);        \
+    ERRNO_VALUE(ETXTBSY, 26)
+
+// Make sure these values are actually correct.
+#if defined(__linux__) && !defined(__mips__)
+#define ERRNO_VALUE(error_name, wire_value) static_assert((error_name) == (wire_value), "")
+ERRNO_VALUES();
+#undef ERRNO_VALUE
+#endif
+
+static std::unordered_map<int, int>* generate_host_to_wire() {
+    auto result = new std::unordered_map<int, int>();
+#define ERRNO_VALUE(error_name, wire_value) \
+    result->insert(std::make_pair((error_name), (wire_value)))
+    ERRNO_VALUES();
+#undef ERRNO_VALUE
+    return result;
+}
+
+static std::unordered_map<int, int>* generate_wire_to_host() {
+    auto result = new std::unordered_map<int, int>();
+#define ERRNO_VALUE(error_name, wire_value) \
+    result->insert(std::make_pair((wire_value), (error_name)))
+    ERRNO_VALUES();
+#undef ERRNO_VALUE
+    return result;
+}
+
+static std::unordered_map<int, int>& host_to_wire = *generate_host_to_wire();
+static std::unordered_map<int, int>& wire_to_host = *generate_wire_to_host();
+
+int errno_to_wire(int error) {
+    auto it = host_to_wire.find(error);
+    if (it == host_to_wire.end()) {
+        LOG(ERROR) << "failed to convert errno " << error << " (" << strerror(error) << ") to wire";
+
+        // Return EIO;
+        return 5;
+    }
+    return it->second;
+}
+
+int errno_from_wire(int error) {
+    auto it = host_to_wire.find(error);
+    if (it == host_to_wire.end()) {
+        LOG(ERROR) << "failed to convert errno " << error << " from wire";
+        return EIO;
+    }
+    return it->second;
+}
diff --git a/adb/sysdeps/errno.h b/adb/sysdeps/errno.h
new file mode 100644
index 0000000..72816b1
--- /dev/null
+++ b/adb/sysdeps/errno.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+
+#if defined(_WIN32)
+char* adb_strerror(int err);
+#define strerror adb_strerror
+#endif
+
+// errno values differ between operating systems and between Linux architectures.
+// Arbitrarily select the Linux asm-generic values to use in the wire protocol.
+int errno_to_wire(int error);
+int errno_from_wire(int error);
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/win32/errno.cpp b/adb/sysdeps/win32/errno.cpp
new file mode 100644
index 0000000..a3b9d9b
--- /dev/null
+++ b/adb/sysdeps/win32/errno.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "sysdeps/errno.h"
+
+#include <windows.h>
+
+#include <string>
+
+// Overrides strerror() to handle error codes not supported by the Windows C
+// Runtime (MSVCRT.DLL).
+char* adb_strerror(int err) {
+// sysdeps.h defines strerror to adb_strerror, but in this function, we
+// want to call the real C Runtime strerror().
+#pragma push_macro("strerror")
+#undef strerror
+    const int saved_err = errno;  // Save because we overwrite it later.
+
+    // Lookup the string for an unknown error.
+    char* errmsg = strerror(-1);
+    const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg;
+
+    // Lookup the string for this error to see if the C Runtime has it.
+    errmsg = strerror(err);
+    if (errmsg != nullptr && unknown_error != errmsg) {
+        // The CRT returned an error message and it is different than the error
+        // message for an unknown error, so it is probably valid, so use it.
+    } else {
+        // Check if we have a string for this error code.
+        const char* custom_msg = nullptr;
+        switch (err) {
+#pragma push_macro("ERR")
+#undef ERR
+#define ERR(errnum, desc) case errnum: custom_msg = desc; break
+            // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h.
+            // Note that these cannot be longer than 94 characters because we
+            // pass this to _strerror() which has that requirement.
+            ERR(ECONNRESET,    "Connection reset by peer");
+            ERR(EHOSTUNREACH,  "No route to host");
+            ERR(ENETDOWN,      "Network is down");
+            ERR(ENETRESET,     "Network dropped connection because of reset");
+            ERR(ENOBUFS,       "No buffer space available");
+            ERR(ENOPROTOOPT,   "Protocol not available");
+            ERR(ENOTCONN,      "Transport endpoint is not connected");
+            ERR(ENOTSOCK,      "Socket operation on non-socket");
+            ERR(EOPNOTSUPP,    "Operation not supported on transport endpoint");
+#pragma pop_macro("ERR")
+        }
+
+        if (custom_msg != nullptr) {
+            // Use _strerror() to write our string into the writable per-thread
+            // buffer used by strerror()/_strerror(). _strerror() appends the
+            // msg for the current value of errno, so set errno to a consistent
+            // value for every call so that our code-path is always the same.
+            errno = 0;
+            errmsg = _strerror(custom_msg);
+            const size_t custom_msg_len = strlen(custom_msg);
+            // Just in case _strerror() returned a read-only string, check if
+            // the returned string starts with our custom message because that
+            // implies that the string is not read-only.
+            if ((errmsg != nullptr) && !strncmp(custom_msg, errmsg, custom_msg_len)) {
+                // _strerror() puts other text after our custom message, so
+                // remove that by terminating after our message.
+                errmsg[custom_msg_len] = '\0';
+            } else {
+                // For some reason nullptr was returned or a pointer to a
+                // read-only string was returned, so fallback to whatever
+                // strerror() can muster (probably "Unknown error" or some
+                // generic CRT error string).
+                errmsg = strerror(err);
+            }
+        } else {
+            // We don't have a custom message, so use whatever strerror(err)
+            // returned earlier.
+        }
+    }
+
+    errno = saved_err;  // restore
+
+    return errmsg;
+#pragma pop_macro("strerror")
+}
diff --git a/adb/sysdeps/win32/errno_test.cpp b/adb/sysdeps/win32/errno_test.cpp
new file mode 100644
index 0000000..09ec52c
--- /dev/null
+++ b/adb/sysdeps/win32/errno_test.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "sysdeps/errno.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+void TestAdbStrError(int err, const char* expected) {
+    errno = 12345;
+    const char* result = adb_strerror(err);
+    // Check that errno is not overwritten.
+    EXPECT_EQ(12345, errno);
+    EXPECT_STREQ(expected, result);
+}
+
+TEST(sysdeps_win32, adb_strerror) {
+    // Test an error code that should not have a mapped string. Use an error
+    // code that is not used by the internal implementation of adb_strerror().
+    TestAdbStrError(-2, "Unknown error");
+    // adb_strerror() uses -1 internally, so test that it can still be passed
+    // as a parameter.
+    TestAdbStrError(-1, "Unknown error");
+    // Test very big, positive unknown error.
+    TestAdbStrError(1000000, "Unknown error");
+
+    // Test success case.
+    // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both.
+    std::string success = adb_strerror(0);
+    EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success;
+
+    // Test error that regular strerror() should have a string for.
+    TestAdbStrError(EPERM, "Operation not permitted");
+    // Test error that regular strerror() doesn't have a string for, but that
+    // adb_strerror() returns.
+    TestAdbStrError(ECONNRESET, "Connection reset by peer");
+}
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/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 4dd549d..a4b5e69 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -477,81 +477,6 @@
     return 0;
 }
 
-// Overrides strerror() to handle error codes not supported by the Windows C
-// Runtime (MSVCRT.DLL).
-char* adb_strerror(int err) {
-    // sysdeps.h defines strerror to adb_strerror, but in this function, we
-    // want to call the real C Runtime strerror().
-#pragma push_macro("strerror")
-#undef strerror
-    const int saved_err = errno;      // Save because we overwrite it later.
-
-    // Lookup the string for an unknown error.
-    char* errmsg = strerror(-1);
-    const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg;
-
-    // Lookup the string for this error to see if the C Runtime has it.
-    errmsg = strerror(err);
-    if (errmsg != nullptr && unknown_error != errmsg) {
-        // The CRT returned an error message and it is different than the error
-        // message for an unknown error, so it is probably valid, so use it.
-    } else {
-        // Check if we have a string for this error code.
-        const char* custom_msg = nullptr;
-        switch (err) {
-#pragma push_macro("ERR")
-#undef ERR
-#define ERR(errnum, desc) case errnum: custom_msg = desc; break
-            // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h.
-            // Note that these cannot be longer than 94 characters because we
-            // pass this to _strerror() which has that requirement.
-            ERR(ECONNRESET,    "Connection reset by peer");
-            ERR(EHOSTUNREACH,  "No route to host");
-            ERR(ENETDOWN,      "Network is down");
-            ERR(ENETRESET,     "Network dropped connection because of reset");
-            ERR(ENOBUFS,       "No buffer space available");
-            ERR(ENOPROTOOPT,   "Protocol not available");
-            ERR(ENOTCONN,      "Transport endpoint is not connected");
-            ERR(ENOTSOCK,      "Socket operation on non-socket");
-            ERR(EOPNOTSUPP,    "Operation not supported on transport endpoint");
-#pragma pop_macro("ERR")
-        }
-
-        if (custom_msg != nullptr) {
-            // Use _strerror() to write our string into the writable per-thread
-            // buffer used by strerror()/_strerror(). _strerror() appends the
-            // msg for the current value of errno, so set errno to a consistent
-            // value for every call so that our code-path is always the same.
-            errno = 0;
-            errmsg = _strerror(custom_msg);
-            const size_t custom_msg_len = strlen(custom_msg);
-            // Just in case _strerror() returned a read-only string, check if
-            // the returned string starts with our custom message because that
-            // implies that the string is not read-only.
-            if ((errmsg != nullptr) &&
-                !strncmp(custom_msg, errmsg, custom_msg_len)) {
-                // _strerror() puts other text after our custom message, so
-                // remove that by terminating after our message.
-                errmsg[custom_msg_len] = '\0';
-            } else {
-                // For some reason nullptr was returned or a pointer to a
-                // read-only string was returned, so fallback to whatever
-                // strerror() can muster (probably "Unknown error" or some
-                // generic CRT error string).
-                errmsg = strerror(err);
-            }
-        } else {
-            // We don't have a custom message, so use whatever strerror(err)
-            // returned earlier.
-        }
-    }
-
-    errno = saved_err;  // restore
-
-    return errmsg;
-#pragma pop_macro("strerror")
-}
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -565,7 +490,7 @@
 static void _socket_set_errno( const DWORD err ) {
     // Because the Windows C Runtime (MSVCRT.DLL) strerror() does not support a
     // lot of POSIX and socket error codes, some of the resulting error codes
-    // are mapped to strings by adb_strerror() above.
+    // are mapped to strings by adb_strerror().
     switch ( err ) {
     case 0:              errno = 0; break;
     // Don't map WSAEINTR since that is only for Winsock 1.1 which we don't use.
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
old mode 100755
new mode 100644
index c3a3fd7..529b212
--- a/adb/sysdeps_win32_test.cpp
+++ b/adb/sysdeps_win32_test.cpp
@@ -70,36 +70,6 @@
     }
 }
 
-void TestAdbStrError(int err, const char* expected) {
-    errno = 12345;
-    const char* result = adb_strerror(err);
-    // Check that errno is not overwritten.
-    EXPECT_EQ(12345, errno);
-    EXPECT_STREQ(expected, result);
-}
-
-TEST(sysdeps_win32, adb_strerror) {
-    // Test an error code that should not have a mapped string. Use an error
-    // code that is not used by the internal implementation of adb_strerror().
-    TestAdbStrError(-2, "Unknown error");
-    // adb_strerror() uses -1 internally, so test that it can still be passed
-    // as a parameter.
-    TestAdbStrError(-1, "Unknown error");
-    // Test very big, positive unknown error.
-    TestAdbStrError(1000000, "Unknown error");
-
-    // Test success case.
-    // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both.
-    std::string success = adb_strerror(0);
-    EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success;
-
-    // Test error that regular strerror() should have a string for.
-    TestAdbStrError(EPERM, "Operation not permitted");
-    // Test error that regular strerror() doesn't have a string for, but that
-    // adb_strerror() returns.
-    TestAdbStrError(ECONNRESET, "Connection reset by peer");
-}
-
 TEST(sysdeps_win32, unix_isatty) {
     // stdin and stdout should be consoles. Use CONIN$ and CONOUT$ special files
     // so that we can test this even if stdin/stdout have been redirected. Read
diff --git a/adb/test_device.py b/adb/test_device.py
index 02a16e4..e76aaed 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -890,7 +890,8 @@
             except subprocess.CalledProcessError as e:
                 output = e.output
 
-            self.assertIn('Permission denied', output)
+            self.assertTrue('Permission denied' in output or
+                            'Read-only file system' in output)
 
     def _test_pull(self, remote_file, checksum):
         tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
diff --git a/adb/trace.sh b/adb/trace.sh
new file mode 100755
index 0000000..49e5026
--- /dev/null
+++ b/adb/trace.sh
@@ -0,0 +1,17 @@
+set -e
+
+if ! [ -e $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py ]; then
+    echo "error: can't find systrace.py at \$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py"
+    exit 1
+fi
+
+adb shell "sleep 1; atrace -b 65536 --async_start adb sched power freq idle disk mmc load"
+adb shell killall adbd
+adb wait-for-device
+echo "press enter to finish..."
+read
+TRACE_TEMP=`mktemp /tmp/trace.XXXXXX`
+echo Saving trace to ${TRACE_TEMP}, html file to ${TRACE_TEMP}.html
+adb shell atrace --async_stop -z > ${TRACE_TEMP}
+$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=${TRACE_TEMP} -o ${TRACE_TEMP}.html
+chrome ${TRACE_TEMP}.html
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 132702d..60f3b5c 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -37,6 +37,7 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_trace.h"
 #include "adb_utils.h"
 #include "diagnose_usb.h"
 
@@ -49,18 +50,18 @@
 
 const char* const kFeatureShell2 = "shell_v2";
 const char* const kFeatureCmd = "cmd";
+const char* const kFeatureStat2 = "stat_v2";
 
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
-    unsigned  command = p->msg.command;
-    int       len     = p->msg.data_length;
-    char      cmd[9];
-    char      arg0[12], arg1[12];
-    int       n;
+    unsigned command = p->msg.command;
+    int len = p->msg.data_length;
+    char cmd[9];
+    char arg0[12], arg1[12];
+    int n;
 
     for (n = 0; n < 4; n++) {
-        int  b = (command >> (n*8)) & 255;
-        if (b < 32 || b >= 127)
-            break;
+        int b = (command >> (n * 8)) & 255;
+        if (b < 32 || b >= 127) break;
         cmd[n] = (char)b;
     }
     if (n == 4) {
@@ -81,25 +82,24 @@
     else
         snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
 
-    std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
-                                                     name, func, cmd, arg0, arg1, len);
+    std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name,
+                                                     func, cmd, arg0, arg1, len);
     result += dump_hex(p->data, len);
     return result;
 }
 
-static int
-read_packet(int  fd, const char* name, apacket** ppacket)
-{
+static int read_packet(int fd, const char* name, apacket** ppacket) {
+    ATRACE_NAME("read_packet");
     char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
-    char* p = reinterpret_cast<char*>(ppacket);  /* really read a packet address */
+    char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
     int len = sizeof(apacket*);
-    while(len > 0) {
+    while (len > 0) {
         int r = adb_read(fd, p, len);
-        if(r > 0) {
+        if (r > 0) {
             len -= r;
             p += r;
         } else {
@@ -112,20 +112,19 @@
     return 0;
 }
 
-static int
-write_packet(int  fd, const char* name, apacket** ppacket)
-{
+static int write_packet(int fd, const char* name, apacket** ppacket) {
+    ATRACE_NAME("write_packet");
     char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
     VLOG(TRANSPORT) << dump_packet(name, "to remote", *ppacket);
-    char* p = reinterpret_cast<char*>(ppacket);  /* we really write the packet address */
+    char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */
     int len = sizeof(apacket*);
-    while(len > 0) {
+    while (len > 0) {
         int r = adb_write(fd, p, len);
-        if(r > 0) {
+        if (r > 0) {
             len -= r;
             p += r;
         } else {
@@ -136,16 +135,15 @@
     return 0;
 }
 
-static void transport_socket_events(int fd, unsigned events, void *_t)
-{
-    atransport *t = reinterpret_cast<atransport*>(_t);
+static void transport_socket_events(int fd, unsigned events, void* _t) {
+    atransport* t = reinterpret_cast<atransport*>(_t);
     D("transport_socket_events(fd=%d, events=%04x,...)", fd, events);
-    if(events & FDE_READ){
-        apacket *p = 0;
-        if(read_packet(fd, t->serial, &p)){
+    if (events & FDE_READ) {
+        apacket* p = 0;
+        if (read_packet(fd, t->serial, &p)) {
             D("%s: failed to read packet from transport socket on fd %d", t->serial, fd);
         } else {
-            handle_packet(p, (atransport *) _t);
+            handle_packet(p, (atransport*)_t);
         }
     }
 }
@@ -179,40 +177,43 @@
 // read_transport thread reads data from a transport (representing a usb/tcp connection),
 // and makes the main thread call handle_packet().
 static void read_transport_thread(void* _t) {
-    atransport *t = reinterpret_cast<atransport*>(_t);
-    apacket *p;
+    atransport* t = reinterpret_cast<atransport*>(_t);
+    apacket* p;
 
-    adb_thread_setname(android::base::StringPrintf("<-%s",
-                                                   (t->serial != nullptr ? t->serial : "transport")));
-    D("%s: starting read_transport thread on fd %d, SYNC online (%d)",
-       t->serial, t->fd, t->sync_token + 1);
+    adb_thread_setname(
+        android::base::StringPrintf("<-%s", (t->serial != nullptr ? t->serial : "transport")));
+    D("%s: starting read_transport thread on fd %d, SYNC online (%d)", t->serial, t->fd,
+      t->sync_token + 1);
     p = get_apacket();
     p->msg.command = A_SYNC;
     p->msg.arg0 = 1;
     p->msg.arg1 = ++(t->sync_token);
     p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, t->serial, &p)) {
+    if (write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
         D("%s: failed to write SYNC packet", t->serial);
         goto oops;
     }
 
     D("%s: data pump started", t->serial);
-    for(;;) {
+    for (;;) {
+        ATRACE_NAME("read_transport loop");
         p = get_apacket();
 
-        if(t->read_from_remote(p, t) == 0){
-            D("%s: received remote packet, sending to transport",
-              t->serial);
-            if(write_packet(t->fd, t->serial, &p)){
+        {
+            ATRACE_NAME("read_transport read_remote");
+            if (t->read_from_remote(p, t) != 0) {
+                D("%s: remote read failed for transport", t->serial);
                 put_apacket(p);
-                D("%s: failed to write apacket to transport", t->serial);
-                goto oops;
+                break;
             }
-        } else {
-            D("%s: remote read failed for transport", t->serial);
+        }
+
+        D("%s: received remote packet, sending to transport", t->serial);
+        if (write_packet(t->fd, t->serial, &p)) {
             put_apacket(p);
-            break;
+            D("%s: failed to write apacket to transport", t->serial);
+            goto oops;
         }
     }
 
@@ -222,7 +223,7 @@
     p->msg.arg0 = 0;
     p->msg.arg1 = 0;
     p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, t->serial, &p)) {
+    if (write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
         D("%s: failed to write SYNC apacket to transport", t->serial);
     }
@@ -236,38 +237,38 @@
 // write_transport thread gets packets sent by the main thread (through send_packet()),
 // and writes to a transport (representing a usb/tcp connection).
 static void write_transport_thread(void* _t) {
-    atransport *t = reinterpret_cast<atransport*>(_t);
-    apacket *p;
+    atransport* t = reinterpret_cast<atransport*>(_t);
+    apacket* p;
     int active = 0;
 
-    adb_thread_setname(android::base::StringPrintf("->%s",
-                                                   (t->serial != nullptr ? t->serial : "transport")));
-    D("%s: starting write_transport thread, reading from fd %d",
-       t->serial, t->fd);
+    adb_thread_setname(
+        android::base::StringPrintf("->%s", (t->serial != nullptr ? t->serial : "transport")));
+    D("%s: starting write_transport thread, reading from fd %d", t->serial, t->fd);
 
-    for(;;){
-        if(read_packet(t->fd, t->serial, &p)) {
-            D("%s: failed to read apacket from transport on fd %d",
-               t->serial, t->fd );
+    for (;;) {
+        ATRACE_NAME("write_transport loop");
+        if (read_packet(t->fd, t->serial, &p)) {
+            D("%s: failed to read apacket from transport on fd %d", t->serial, t->fd);
             break;
         }
-        if(p->msg.command == A_SYNC){
-            if(p->msg.arg0 == 0) {
+
+        if (p->msg.command == A_SYNC) {
+            if (p->msg.arg0 == 0) {
                 D("%s: transport SYNC offline", t->serial);
                 put_apacket(p);
                 break;
             } else {
-                if(p->msg.arg1 == t->sync_token) {
+                if (p->msg.arg1 == t->sync_token) {
                     D("%s: transport SYNC online", t->serial);
                     active = 1;
                 } else {
-                    D("%s: transport ignoring SYNC %d != %d",
-                      t->serial, p->msg.arg1, t->sync_token);
+                    D("%s: transport ignoring SYNC %d != %d", t->serial, p->msg.arg1, t->sync_token);
                 }
             }
         } else {
-            if(active) {
+            if (active) {
                 D("%s: transport got packet, sending to remote", t->serial);
+                ATRACE_NAME("write_transport write_remote");
                 t->write_to_remote(p, t);
             } else {
                 D("%s: transport ignoring packet while offline", t->serial);
@@ -295,7 +296,6 @@
 static int transport_registration_recv = -1;
 static fdevent transport_registration_fde;
 
-
 #if ADB_HOST
 
 /* this adds support required by the 'track-devices' service.
@@ -304,19 +304,17 @@
  * live TCP connection
  */
 struct device_tracker {
-    asocket          socket;
-    int              update_needed;
-    device_tracker*  next;
+    asocket socket;
+    int update_needed;
+    device_tracker* next;
 };
 
 /* linked list of all device trackers */
-static device_tracker*   device_tracker_list;
+static device_tracker* device_tracker_list;
 
-static void
-device_tracker_remove( device_tracker*  tracker )
-{
-    device_tracker**  pnode = &device_tracker_list;
-    device_tracker*   node  = *pnode;
+static void device_tracker_remove(device_tracker* tracker) {
+    device_tracker** pnode = &device_tracker_list;
+    device_tracker* node = *pnode;
 
     std::lock_guard<std::mutex> lock(transport_lock);
     while (node) {
@@ -325,17 +323,15 @@
             break;
         }
         pnode = &node->next;
-        node  = *pnode;
+        node = *pnode;
     }
 }
 
-static void
-device_tracker_close( asocket*  socket )
-{
-    device_tracker*  tracker = (device_tracker*) socket;
-    asocket*         peer    = socket->peer;
+static void device_tracker_close(asocket* socket) {
+    device_tracker* tracker = (device_tracker*)socket;
+    asocket* peer = socket->peer;
 
-    D( "device tracker %p removed", tracker);
+    D("device tracker %p removed", tracker);
     if (peer) {
         peer->peer = NULL;
         peer->close(peer);
@@ -344,9 +340,7 @@
     free(tracker);
 }
 
-static int
-device_tracker_enqueue( asocket*  socket, apacket*  p )
-{
+static int device_tracker_enqueue(asocket* socket, apacket* p) {
     /* you can't read from a device tracker, close immediately */
     put_apacket(p);
     device_tracker_close(socket);
@@ -376,26 +370,23 @@
     }
 }
 
-asocket*
-create_device_tracker(void)
-{
+asocket* create_device_tracker(void) {
     device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
     if (tracker == nullptr) fatal("cannot allocate device tracker");
 
-    D( "device tracker %p created", tracker);
+    D("device tracker %p created", tracker);
 
     tracker->socket.enqueue = device_tracker_enqueue;
-    tracker->socket.ready   = device_tracker_ready;
-    tracker->socket.close   = device_tracker_close;
-    tracker->update_needed  = 1;
+    tracker->socket.ready = device_tracker_ready;
+    tracker->socket.close = device_tracker_close;
+    tracker->update_needed = 1;
 
-    tracker->next       = device_tracker_list;
+    tracker->next = device_tracker_list;
     device_tracker_list = tracker;
 
     return &tracker->socket;
 }
 
-
 // Call this function each time the transport list has changed.
 void update_transports() {
     std::string transports = list_transports(false);
@@ -415,26 +406,23 @@
     // Nothing to do on the device side.
 }
 
-#endif // ADB_HOST
+#endif  // ADB_HOST
 
-struct tmsg
-{
-    atransport *transport;
-    int         action;
+struct tmsg {
+    atransport* transport;
+    int action;
 };
 
-static int
-transport_read_action(int  fd, struct tmsg*  m)
-{
-    char *p   = (char*)m;
-    int   len = sizeof(*m);
-    int   r;
+static int transport_read_action(int fd, struct tmsg* m) {
+    char* p = (char*)m;
+    int len = sizeof(*m);
+    int r;
 
-    while(len > 0) {
+    while (len > 0) {
         r = adb_read(fd, p, len);
-        if(r > 0) {
+        if (r > 0) {
             len -= r;
-            p   += r;
+            p += r;
         } else {
             D("transport_read_action: on fd %d: %s", fd, strerror(errno));
             return -1;
@@ -443,18 +431,16 @@
     return 0;
 }
 
-static int
-transport_write_action(int  fd, struct tmsg*  m)
-{
-    char *p   = (char*)m;
-    int   len = sizeof(*m);
-    int   r;
+static int transport_write_action(int fd, struct tmsg* m) {
+    char* p = (char*)m;
+    int len = sizeof(*m);
+    int r;
 
-    while(len > 0) {
+    while (len > 0) {
         r = adb_write(fd, p, len);
-        if(r > 0) {
+        if (r > 0) {
             len -= r;
-            p   += r;
+            p += r;
         } else {
             D("transport_write_action: on fd %d: %s", fd, strerror(errno));
             return -1;
@@ -463,17 +449,16 @@
     return 0;
 }
 
-static void transport_registration_func(int _fd, unsigned ev, void *data)
-{
+static void transport_registration_func(int _fd, unsigned ev, void* data) {
     tmsg m;
     int s[2];
-    atransport *t;
+    atransport* t;
 
-    if(!(ev & FDE_READ)) {
+    if (!(ev & FDE_READ)) {
         return;
     }
 
-    if(transport_read_action(_fd, &m)) {
+    if (transport_read_action(_fd, &m)) {
         fatal_errno("cannot read transport registration socket");
     }
 
@@ -482,9 +467,9 @@
     if (m.action == 0) {
         D("transport: %s removing and free'ing %d", t->serial, t->transport_socket);
 
-            /* IMPORTANT: the remove closes one half of the
-            ** socket pair.  The close closes the other half.
-            */
+        /* IMPORTANT: the remove closes one half of the
+        ** socket pair.  The close closes the other half.
+        */
         fdevent_remove(&(t->transport_fde));
         adb_close(t->fd);
 
@@ -493,16 +478,11 @@
             transport_list.remove(t);
         }
 
-        if (t->product)
-            free(t->product);
-        if (t->serial)
-            free(t->serial);
-        if (t->model)
-            free(t->model);
-        if (t->device)
-            free(t->device);
-        if (t->devpath)
-            free(t->devpath);
+        if (t->product) free(t->product);
+        if (t->serial) free(t->serial);
+        if (t->model) free(t->model);
+        if (t->device) free(t->device);
+        if (t->devpath) free(t->devpath);
 
         delete t;
 
@@ -524,10 +504,7 @@
         t->transport_socket = s[0];
         t->fd = s[1];
 
-        fdevent_install(&(t->transport_fde),
-                        t->transport_socket,
-                        transport_socket_events,
-                        t);
+        fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
 
         fdevent_set(&(t->transport_fde), FDE_READ);
 
@@ -549,11 +526,10 @@
     update_transports();
 }
 
-void init_transport_registration(void)
-{
+void init_transport_registration(void) {
     int s[2];
 
-    if(adb_socketpair(s)){
+    if (adb_socketpair(s)) {
         fatal_errno("cannot open transport registration socketpair");
     }
     D("socketpair: (%d,%d)", s[0], s[1]);
@@ -561,38 +537,33 @@
     transport_registration_send = s[0];
     transport_registration_recv = s[1];
 
-    fdevent_install(&transport_registration_fde,
-                    transport_registration_recv,
-                    transport_registration_func,
-                    0);
+    fdevent_install(&transport_registration_fde, transport_registration_recv,
+                    transport_registration_func, 0);
 
     fdevent_set(&transport_registration_fde, FDE_READ);
 }
 
 /* the fdevent select pump is single threaded */
-static void register_transport(atransport *transport)
-{
+static void register_transport(atransport* transport) {
     tmsg m;
     m.transport = transport;
     m.action = 1;
     D("transport: %s registered", transport->serial);
-    if(transport_write_action(transport_registration_send, &m)) {
+    if (transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
 }
 
-static void remove_transport(atransport *transport)
-{
+static void remove_transport(atransport* transport) {
     tmsg m;
     m.transport = transport;
     m.action = 0;
     D("transport: %s removed", transport->serial);
-    if(transport_write_action(transport_registration_send, &m)) {
+    if (transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
 }
 
-
 static void transport_unref(atransport* t) {
     CHECK(t != nullptr);
 
@@ -608,37 +579,31 @@
     }
 }
 
-static int qual_match(const char *to_test,
-                      const char *prefix, const char *qual, bool sanitize_qual)
-{
-    if (!to_test || !*to_test)
-        /* Return true if both the qual and to_test are null strings. */
+static int qual_match(const char* to_test, const char* prefix, const char* qual,
+                      bool sanitize_qual) {
+    if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */
         return !qual || !*qual;
 
-    if (!qual)
-        return 0;
+    if (!qual) return 0;
 
     if (prefix) {
         while (*prefix) {
-            if (*prefix++ != *to_test++)
-                return 0;
+            if (*prefix++ != *to_test++) return 0;
         }
     }
 
     while (*qual) {
         char ch = *qual++;
-        if (sanitize_qual && !isalnum(ch))
-            ch = '_';
-        if (ch != *to_test++)
-            return 0;
+        if (sanitize_qual && !isalnum(ch)) ch = '_';
+        if (ch != *to_test++) return 0;
     }
 
     /* Everything matched so far.  Return true if *to_test is a NUL. */
     return !*to_test;
 }
 
-atransport* acquire_one_transport(TransportType type, const char* serial,
-                                  bool* is_ambiguous, std::string* error_out) {
+atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
+                                  std::string* error_out) {
     atransport* result = nullptr;
 
     if (serial) {
@@ -736,15 +701,24 @@
 
 const std::string atransport::connection_state_name() const {
     switch (connection_state) {
-        case kCsOffline: return "offline";
-        case kCsBootloader: return "bootloader";
-        case kCsDevice: return "device";
-        case kCsHost: return "host";
-        case kCsRecovery: return "recovery";
-        case kCsNoPerm: return UsbNoPermissionsShortHelpText();
-        case kCsSideload: return "sideload";
-        case kCsUnauthorized: return "unauthorized";
-        default: return "unknown";
+        case kCsOffline:
+            return "offline";
+        case kCsBootloader:
+            return "bootloader";
+        case kCsDevice:
+            return "device";
+        case kCsHost:
+            return "host";
+        case kCsRecovery:
+            return "recovery";
+        case kCsNoPerm:
+            return UsbNoPermissionsShortHelpText();
+        case kCsSideload:
+            return "sideload";
+        case kCsUnauthorized:
+            return "unauthorized";
+        default:
+            return "unknown";
     }
 }
 
@@ -770,8 +744,7 @@
 const FeatureSet& supported_features() {
     // Local static allocation to avoid global non-POD variables.
     static const FeatureSet* features = new FeatureSet{
-        kFeatureShell2,
-        kFeatureCmd
+        kFeatureShell2, kFeatureCmd, kFeatureStat2,
         // Increment ADB_SERVER_VERSION whenever the feature list changes to
         // make sure that the adb client and server features stay in sync
         // (http://b/24370690).
@@ -789,14 +762,12 @@
         return FeatureSet();
     }
 
-    auto names = android::base::Split(features_string,
-                                      {kFeatureStringDelimiter});
+    auto names = android::base::Split(features_string, {kFeatureStringDelimiter});
     return FeatureSet(names.begin(), names.end());
 }
 
 bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature) {
-    return feature_set.count(feature) > 0 &&
-            supported_features().count(feature) > 0;
+    return feature_set.count(feature) > 0 && supported_features().count(feature) > 0;
 }
 
 bool atransport::has_feature(const std::string& feature) const {
@@ -832,21 +803,20 @@
 
             // For fastboot compatibility, ignore protocol prefixes.
             if (android::base::StartsWith(target, "tcp:") ||
-                    android::base::StartsWith(target, "udp:")) {
+                android::base::StartsWith(target, "udp:")) {
                 local_target_ptr += 4;
             }
 
             // Parse our |serial| and the given |target| to check if the hostnames and ports match.
             std::string serial_host, error;
             int serial_port = -1;
-            if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr,
-                                               &error)) {
+            if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr, &error)) {
                 // |target| may omit the port to default to ours.
                 std::string target_host;
                 int target_port = serial_port;
                 if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
                                                    nullptr, &error) &&
-                        serial_host == target_host && serial_port == target_port) {
+                    serial_host == target_host && serial_port == target_port) {
                     return true;
                 }
             }
@@ -861,8 +831,8 @@
 
 #if ADB_HOST
 
-static void append_transport_info(std::string* result, const char* key,
-                                  const char* value, bool sanitize) {
+static void append_transport_info(std::string* result, const char* key, const char* value,
+                                  bool sanitize) {
     if (value == nullptr || *value == '\0') {
         return;
     }
@@ -875,8 +845,7 @@
     }
 }
 
-static void append_transport(const atransport* t, std::string* result,
-                             bool long_listing) {
+static void append_transport(const atransport* t, std::string* result, bool long_listing) {
     const char* serial = t->serial;
     if (!serial || !serial[0]) {
         serial = "(no serial number)";
@@ -887,8 +856,7 @@
         *result += '\t';
         *result += t->connection_state_name();
     } else {
-        android::base::StringAppendF(result, "%-22s %s", serial,
-                                     t->connection_state_name().c_str());
+        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name().c_str());
 
         append_transport_info(result, "", t->devpath, false);
         append_transport_info(result, "product:", t->product, false);
@@ -921,9 +889,9 @@
 void close_usb_devices() {
     close_usb_devices([](const atransport*) { return true; });
 }
-#endif // ADB_HOST
+#endif  // ADB_HOST
 
-int register_socket_transport(int s, const char *serial, int port, int local) {
+int register_socket_transport(int s, const char* serial, int port, int local) {
     atransport* t = new atransport();
 
     if (!serial) {
@@ -942,7 +910,7 @@
     for (const auto& transport : pending_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             VLOG(TRANSPORT) << "socket transport " << transport->serial
-                << " is already in pending_list and fails to register";
+                            << " is already in pending_list and fails to register";
             delete t;
             return -1;
         }
@@ -951,7 +919,7 @@
     for (const auto& transport : transport_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             VLOG(TRANSPORT) << "socket transport " << transport->serial
-                << " is already in transport_list and fails to register";
+                            << " is already in transport_list and fails to register";
             delete t;
             return -1;
         }
@@ -967,7 +935,7 @@
 }
 
 #if ADB_HOST
-atransport *find_transport(const char *serial) {
+atransport* find_transport(const char* serial) {
     atransport* result = nullptr;
 
     std::lock_guard<std::mutex> lock(transport_lock);
@@ -996,14 +964,13 @@
 
 #endif
 
-void register_usb_transport(usb_handle* usb, const char* serial,
-                            const char* devpath, unsigned writeable) {
+void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
+                            unsigned writeable) {
     atransport* t = new atransport();
 
-    D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb,
-      serial ? serial : "");
+    D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
     init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
-    if(serial) {
+    if (serial) {
         t->serial = strdup(serial);
     }
 
@@ -1020,23 +987,21 @@
 }
 
 // This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle *usb) {
+void unregister_usb_transport(usb_handle* usb) {
     std::lock_guard<std::mutex> lock(transport_lock);
-    transport_list.remove_if([usb](atransport* t) {
-        return t->usb == usb && t->connection_state == kCsNoPerm;
-    });
+    transport_list.remove_if(
+        [usb](atransport* t) { return t->usb == usb && t->connection_state == kCsNoPerm; });
 }
 
-int check_header(apacket *p, atransport *t)
-{
-    if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
+int check_header(apacket* p, atransport* t) {
+    if (p->msg.magic != (p->msg.command ^ 0xffffffff)) {
         VLOG(RWX) << "check_header(): invalid magic";
         return -1;
     }
 
-    if(p->msg.data_length > t->get_max_payload()) {
-        VLOG(RWX) << "check_header(): " << p->msg.data_length << " atransport::max_payload = "
-                  << t->get_max_payload();
+    if (p->msg.data_length > t->get_max_payload()) {
+        VLOG(RWX) << "check_header(): " << p->msg.data_length
+                  << " atransport::max_payload = " << t->get_max_payload();
         return -1;
     }
 
diff --git a/adb/transport.h b/adb/transport.h
index b2df838..3306388 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -46,6 +46,7 @@
 extern const char* const kFeatureShell2;
 // The 'cmd' command is available
 extern const char* const kFeatureCmd;
+extern const char* const kFeatureStat2;
 
 class atransport {
 public:
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index ba2b28d..c17f869 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -27,6 +27,7 @@
 
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 #include <vector>
 
 #include <android-base/stringprintf.h>
@@ -39,6 +40,7 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
+#include "sysdeps/chrono.h"
 
 #if ADB_HOST
 
@@ -144,7 +146,7 @@
 
 // Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
 constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
-constexpr uint32_t LOCAL_PORT_RETRY_INTERVAL_IN_MS = 1000;
+constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s;
 
 struct RetryPort {
     int port;
@@ -173,7 +175,7 @@
         // Sleep here instead of the end of loop, because if we immediately try to reconnect
         // the emulator just kicked, the adbd on the emulator may not have time to remove the
         // just kicked transport.
-        adb_sleep_ms(LOCAL_PORT_RETRY_INTERVAL_IN_MS);
+        std::this_thread::sleep_for(LOCAL_PORT_RETRY_INTERVAL);
 
         // Try connecting retry ports.
         std::vector<RetryPort> next_ports;
@@ -214,7 +216,7 @@
             serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
             if(serverfd < 0) {
                 D("server: cannot bind socket yet: %s", error.c_str());
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
                 continue;
             }
             close_on_exec(serverfd);
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 3e5028d..e7f1338 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -38,6 +38,7 @@
 #include <list>
 #include <mutex>
 #include <string>
+#include <thread>
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -46,6 +47,7 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
 using namespace std::literals;
 
 /* usb scan debugging is waaaay too verbose */
@@ -577,7 +579,7 @@
         // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
         kick_disconnected_devices();
-        sleep(1);
+        std::this_thread::sleep_for(1s);
     }
 }
 
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 6de10f5..1cc7f68 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,8 +31,10 @@
 
 #include <algorithm>
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -40,6 +42,8 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_PACKET_SIZE_FS	64
 #define MAX_PACKET_SIZE_HS	512
 #define MAX_PACKET_SIZE_SS	1024
@@ -268,7 +272,7 @@
                 fd = unix_open("/dev/android", O_RDWR);
             }
             if (fd < 0) {
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
             }
         } while (fd < 0);
         D("[ opening device succeeded ]");
@@ -476,7 +480,7 @@
             if (init_functionfs(usb)) {
                 break;
             }
-            adb_sleep_ms(1000);
+            std::this_thread::sleep_for(1s);
         }
         android::base::SetProperty("sys.usb.ffs.ready", "1");
 
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 2ee2aae..e541f6e 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -30,8 +30,10 @@
 #include <stdio.h>
 
 #include <atomic>
+#include <chrono>
 #include <memory>
 #include <mutex>
+#include <thread>
 #include <vector>
 
 #include <android-base/logging.h>
@@ -40,6 +42,8 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 struct usb_handle
 {
     UInt8 bulkIn;
@@ -411,7 +415,7 @@
         }
         // Signal the parent that we are running
         usb_inited_flag = true;
-        adb_sleep_ms(1000);
+        std::this_thread::sleep_for(1s);
     }
     VLOG(USB) << "RunLoopThread done";
 }
@@ -436,7 +440,7 @@
 
         // Wait for initialization to finish
         while (!usb_inited_flag) {
-            adb_sleep_ms(100);
+            std::this_thread::sleep_for(100ms);
         }
 
         initialized = true;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 755f07e..640e91e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -28,12 +28,14 @@
 #include <stdlib.h>
 
 #include <mutex>
+#include <thread>
 
 #include <adb_api.h>
 
 #include <android-base/errors.h>
 
 #include "adb.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 
 /** Structure usb_handle describes our connection to the usb device via
@@ -176,9 +178,9 @@
   adb_thread_setname("Device Poll");
   D("Created device thread");
 
-  while(1) {
+  while (true) {
     find_devices();
-    adb_sleep_ms(1000);
+    std::this_thread::sleep_for(1s);
   }
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index e6ad15b..b9a6e0b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -49,6 +49,11 @@
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
         },
+        linux_bionic: {
+            srcs: ["errors_unix.cpp"],
+            cppflags: ["-Wexit-time-destructors"],
+            enabled: true,
+        },
         linux: {
             srcs: ["errors_unix.cpp"],
             cppflags: ["-Wexit-time-destructors"],
diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h
index 3a2f8fa..9971226 100644
--- a/base/include/android-base/memory.h
+++ b/base/include/android-base/memory.h
@@ -20,25 +20,19 @@
 namespace android {
 namespace base {
 
-// Use packed structures for access to unaligned data on targets with alignment
+// Use memcpy for access to unaligned data on targets with alignment
 // restrictions.  The compiler will generate appropriate code to access these
 // structures without generating alignment exceptions.
 template <typename T>
-static inline T get_unaligned(const T* address) {
-  struct unaligned {
-    T v;
-  } __attribute__((packed));
-  const unaligned* p = reinterpret_cast<const unaligned*>(address);
-  return p->v;
+static inline T get_unaligned(const void* address) {
+  T result;
+  memcpy(&result, address, sizeof(T));
+  return result;
 }
 
 template <typename T>
-static inline void put_unaligned(T* address, T v) {
-  struct unaligned {
-    T v;
-  } __attribute__((packed));
-  unaligned* p = reinterpret_cast<unaligned*>(address);
-  p->v = v;
+static inline void put_unaligned(void* address, T v) {
+  memcpy(address, &v, sizeof(T));
 }
 
 } // namespace base
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 95d1b6a..4d7082a 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -61,4 +61,4 @@
 } // namespace base
 } // namespace android
 
-#endif  // ANDROID_BASE_MEMORY_H
+#endif  // ANDROID_BASE_PROPERTIES_H
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index ba8f81c..c96e996 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -11,13 +11,8 @@
 on post-fs-data && property:init.svc.bootanim=running
     exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
 
-# The first marker, boot animation stopped, is considered the point at which
-# the user may interact with the device, so it is a good proxy for the boot
-# complete signal.
-#
-# The second marker ensures an encrypted device is decrypted before logging
-# boot time data.
-on property:init.svc.bootanim=stopped && property:vold.decrypt=trigger_restart_framework
+# Record boot complete metrics.
+on property:sys.boot_completed=1
     # Record boot_complete and related stats (decryption, etc).
     exec - root root -- /system/bin/bootstat --record_boot_complete
 
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index 6a9ef2b..73f3295 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -19,13 +19,13 @@
 #include <cstdlib>
 
 #include <android-base/logging.h>
-#include <log/log.h>
+#include <log/log_event_list.h>
 
 namespace bootstat {
 
 void LogHistogram(const std::string& event, int32_t data) {
   LOG(INFO) << "Logging histogram: " << event << " " << data;
-  android_log_event_context log(HISTOGRAM_LOG_TAG);
+  android_log_event_list log(HISTOGRAM_LOG_TAG);
   log << event << data << LOG_ID_EVENTS;
 }
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 155b309..e3bdd43 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -18,6 +18,7 @@
     debuggerd.cpp \
     elf_utils.cpp \
     getevent.cpp \
+    open_files_list.cpp \
     signal_sender.cpp \
     tombstone.cpp \
     utility.cpp \
@@ -51,7 +52,7 @@
 
 include $(BUILD_EXECUTABLE)
 
-crasher_cppflags := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
+crasher_cppflags := $(common_cppflags) -O0 -fstack-protector-all -Wno-free-nonheap-object
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := crasher.cpp
@@ -64,7 +65,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
 LOCAL_CPPFLAGS := $(crasher_cppflags)
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES := libbase liblog
 
 # The arm emulator has VFP but not VFPv3-D32.
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -90,7 +91,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
 LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 # The arm emulator has VFP but not VFPv3-D32.
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -102,15 +102,17 @@
 LOCAL_MODULE_STEM_64 := static_crasher64
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_LIBRARIES := libdebuggerd_client libcutils liblog
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client libbase liblog
 
 include $(BUILD_EXECUTABLE)
 
 debuggerd_test_src_files := \
     utility.cpp \
+    open_files_list.cpp \
     test/dump_memory_test.cpp \
     test/elf_fake.cpp \
     test/log_fake.cpp \
+    test/open_files_list_test.cpp \
     test/property_fake.cpp \
     test/ptrace_fake.cpp \
     test/tombstone_test.cpp \
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index b0e8b17..e650f22 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -17,47 +17,43 @@
 #define LOG_TAG "crasher"
 
 #include <assert.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
-#include <sched.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/cdefs.h>
 #include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
 #include <unistd.h>
 
+// We test both kinds of logging.
 #include <android/log.h>
-#include <cutils/sockets.h>
+#include <android-base/logging.h>
 
 #if defined(STATIC_CRASHER)
 #include "debuggerd/client.h"
 #endif
 
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
+#define noinline __attribute__((__noinline__))
 
-extern const char* __progname;
+// Avoid name mangling so that stacks are more readable.
+extern "C" {
 
-extern "C" void crash1(void);
-extern "C" void crashnostack(void);
+void crash1(void);
+void crashnostack(void);
 
-static int do_action(const char* arg);
+int do_action(const char* arg);
 
-static void maybe_abort() {
+noinline void maybe_abort() {
     if (time(0) != 42) {
         abort();
     }
 }
 
-static char* smash_stack_dummy_buf;
-__attribute__ ((noinline)) static void smash_stack_dummy_function(volatile int* plen) {
+char* smash_stack_dummy_buf;
+noinline void smash_stack_dummy_function(volatile int* plen) {
   smash_stack_dummy_buf[*plen] = 0;
 }
 
@@ -65,8 +61,8 @@
 // compiler generates the proper stack guards around this function.
 // Assign local array address to global variable to force stack guards.
 // Use another noinline function to corrupt the stack.
-__attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
-    printf("%s: deliberately corrupting stack...\n", __progname);
+noinline int smash_stack(volatile int* plen) {
+    printf("%s: deliberately corrupting stack...\n", getprogname());
 
     char buf[128];
     smash_stack_dummy_buf = buf;
@@ -75,91 +71,107 @@
     return 0;
 }
 
-#if defined(__clang__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Winfinite-recursion"
-#endif
 
-static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
+void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
 
-__attribute__((noinline)) static void overflow_stack(void* p) {
+noinline void overflow_stack(void* p) {
     void* buf[1];
     buf[0] = p;
     global = buf;
     overflow_stack(&buf);
 }
 
-#if defined(__clang__)
 #pragma clang diagnostic pop
-#endif
 
-static void *noisy(void *x)
-{
-    char c = (uintptr_t) x;
-    for(;;) {
-        usleep(250*1000);
-        write(2, &c, 1);
-        if(c == 'C') *((volatile unsigned*) 0) = 42;
-    }
-    return NULL;
+noinline void* thread_callback(void* raw_arg) {
+    const char* arg = reinterpret_cast<const char*>(raw_arg);
+    return reinterpret_cast<void*>(static_cast<uintptr_t>(do_action(arg)));
 }
 
-static int ctest()
-{
-    pthread_t thr;
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-    pthread_create(&thr, &attr, noisy, (void*) 'A');
-    pthread_create(&thr, &attr, noisy, (void*) 'B');
-    pthread_create(&thr, &attr, noisy, (void*) 'C');
-    for(;;) ;
-    return 0;
-}
-
-static void* thread_callback(void* raw_arg)
-{
-    return (void*) (uintptr_t) do_action((const char*) raw_arg);
-}
-
-static int do_action_on_thread(const char* arg)
-{
+noinline int do_action_on_thread(const char* arg) {
     pthread_t t;
-    pthread_create(&t, NULL, thread_callback, (void*) arg);
-    void* result = NULL;
+    pthread_create(&t, nullptr, thread_callback, const_cast<char*>(arg));
+    void* result = nullptr;
     pthread_join(t, &result);
-    return (int) (uintptr_t) result;
+    return reinterpret_cast<uintptr_t>(result);
 }
 
-__attribute__((noinline)) static int crash3(int a) {
-    *((int*) 0xdead) = a;
+noinline int crash3(int a) {
+    *reinterpret_cast<int*>(0xdead) = a;
     return a*4;
 }
 
-__attribute__((noinline)) static int crash2(int a) {
+noinline int crash2(int a) {
     a = crash3(a) + 2;
     return a*3;
 }
 
-__attribute__((noinline)) static int crash(int a) {
+noinline int crash(int a) {
     a = crash2(a) + 1;
     return a*2;
 }
 
-static void abuse_heap() {
+noinline void abuse_heap() {
     char buf[16];
-    free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
+    free(buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
 }
 
-static void sigsegv_non_null() {
+noinline void sigsegv_non_null() {
     int* a = (int *)(&do_action);
     *a = 42;
 }
 
-static int do_action(const char* arg)
-{
-    fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
+noinline void fprintf_null() {
+    fprintf(nullptr, "oops");
+}
 
+noinline void readdir_null() {
+    readdir(nullptr);
+}
+
+noinline int strlen_null() {
+    char* sneaky_null = nullptr;
+    return strlen(sneaky_null);
+}
+
+static int usage() {
+    fprintf(stderr, "usage: %s KIND\n", getprogname());
+    fprintf(stderr, "\n");
+    fprintf(stderr, "where KIND is:\n");
+    fprintf(stderr, "  smash-stack           overwrite a -fstack-protector guard\n");
+    fprintf(stderr, "  stack-overflow        recurse until the stack overflows\n");
+    fprintf(stderr, "  heap-corruption       cause a libc abort by corrupting the heap\n");
+    fprintf(stderr, "  heap-usage            cause a libc abort by abusing a heap function\n");
+    fprintf(stderr, "  nostack               crash with a NULL stack pointer\n");
+    fprintf(stderr, "  abort                 call abort()\n");
+    fprintf(stderr, "  assert                call assert() without a function\n");
+    fprintf(stderr, "  assert2               call assert() with a function\n");
+    fprintf(stderr, "  exit                  call exit(1)\n");
+    fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL      call liblog LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call liblog LOG_ALWAYS_FATAL_IF\n");
+    fprintf(stderr, "  LOG-FATAL             call libbase LOG(FATAL)\n");
+    fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
+    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+    fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
+    fprintf(stderr, "  SIGSEGV-unmapped      mmap/munmap a region of memory and then attempt to access it\n");
+    fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
+    fprintf(stderr, "  fprintf-NULL          pass a null pointer to fprintf\n");
+    fprintf(stderr, "  readdir-NULL          pass a null pointer to readdir\n");
+    fprintf(stderr, "  strlen-NULL           pass a null pointer to strlen\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "prefix any of the above with 'thread-' to run on a new 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_FAILURE;
+}
+
+noinline int do_action(const char* arg) {
+    // Prefixes.
     if (!strncmp(arg, "wait-", strlen("wait-"))) {
       char buf[1];
       TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
@@ -172,82 +184,66 @@
       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")) {
+    }
+
+    // Actions.
+    if (!strcasecmp(arg, "SIGSEGV-non-null")) {
         sigsegv_non_null();
-    } else if (!strcmp(arg, "smash-stack")) {
+    } else if (!strcasecmp(arg, "smash-stack")) {
         volatile int len = 128;
         return smash_stack(&len);
-    } else if (!strcmp(arg, "stack-overflow")) {
-        overflow_stack(NULL);
-    } else if (!strcmp(arg, "nostack")) {
+    } else if (!strcasecmp(arg, "stack-overflow")) {
+        overflow_stack(nullptr);
+    } else if (!strcasecmp(arg, "nostack")) {
         crashnostack();
-    } else if (!strcmp(arg, "ctest")) {
-        return ctest();
-    } else if (!strcmp(arg, "exit")) {
+    } else if (!strcasecmp(arg, "exit")) {
         exit(1);
-    } else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
+    } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
         return crash(42);
-    } else if (!strcmp(arg, "abort")) {
+    } else if (!strcasecmp(arg, "abort")) {
         maybe_abort();
-    } else if (!strcmp(arg, "assert")) {
+    } else if (!strcasecmp(arg, "assert")) {
         __assert("some_file.c", 123, "false");
-    } else if (!strcmp(arg, "assert2")) {
+    } else if (!strcasecmp(arg, "assert2")) {
         __assert2("some_file.c", 123, "some_function", "false");
-    } else if (!strcmp(arg, "fortify")) {
+    } else if (!strcasecmp(arg, "fortify")) {
         char buf[10];
         __read_chk(-1, buf, 32, 10);
         while (true) pause();
-    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
+    } else if (!strcasecmp(arg, "LOG(FATAL)")) {
+        LOG(FATAL) << "hello " << 123;
+    } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
         LOG_ALWAYS_FATAL("hello %s", "world");
-    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
+    } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL_IF")) {
         LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
-    } else if (!strcmp(arg, "SIGFPE")) {
+    } else if (!strcasecmp(arg, "SIGFPE")) {
         raise(SIGFPE);
         return EXIT_SUCCESS;
-    } else if (!strcmp(arg, "SIGTRAP")) {
+    } else if (!strcasecmp(arg, "SIGTRAP")) {
         raise(SIGTRAP);
         return EXIT_SUCCESS;
-    } else if (!strcmp(arg, "heap-usage")) {
+    } else if (!strcasecmp(arg, "fprintf-NULL")) {
+        fprintf_null();
+    } else if (!strcasecmp(arg, "readdir-NULL")) {
+        readdir_null();
+    } else if (!strcasecmp(arg, "strlen-NULL")) {
+        return strlen_null();
+    } else if (!strcasecmp(arg, "heap-usage")) {
         abuse_heap();
-    } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
-        char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+    } else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
+        char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
+                                                 MAP_SHARED | MAP_ANONYMOUS, -1, 0));
         munmap(map, sizeof(int));
         map[0] = '8';
+    } else {
+        return usage();
     }
 
-    fprintf(stderr, "%s OP\n", __progname);
-    fprintf(stderr, "where OP is:\n");
-    fprintf(stderr, "  smash-stack           overwrite a stack-guard canary\n");
-    fprintf(stderr, "  stack-overflow        recurse until the stack overflows\n");
-    fprintf(stderr, "  heap-corruption       cause a libc abort by corrupting the heap\n");
-    fprintf(stderr, "  heap-usage            cause a libc abort by abusing a heap function\n");
-    fprintf(stderr, "  nostack               crash with a NULL stack pointer\n");
-    fprintf(stderr, "  ctest                 (obsoleted by thread-crash?)\n");
-    fprintf(stderr, "  exit                  call exit(1)\n");
-    fprintf(stderr, "  abort                 call abort()\n");
-    fprintf(stderr, "  assert                call assert() without a function\n");
-    fprintf(stderr, "  assert2               call assert() with a function\n");
-    fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
-    fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
-    fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
-    fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
-    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
-    fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
-    fprintf(stderr, "  SIGSEGV-unmapped      mmap/munmap a region of memory and then attempt to access it\n");
-    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");
-
+    fprintf(stderr, "%s: exiting normally!\n", getprogname());
     return EXIT_SUCCESS;
 }
 
-int main(int argc, char **argv)
-{
-    fprintf(stderr, "%s: built at " __TIME__ "!@\n", __progname);
-
+int main(int argc, char** argv) {
 #if defined(STATIC_CRASHER)
     debuggerd_callbacks_t callbacks = {
       .get_abort_message = []() {
@@ -265,11 +261,10 @@
     debuggerd_init(&callbacks);
 #endif
 
-    if (argc > 1) {
-        return do_action(argv[1]);
-    } else {
-        crash1();
-    }
+    if (argc == 1) crash1();
+    else if (argc == 2) return do_action(argv[1]);
 
-    return 0;
+    return usage();
 }
+
+};
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 5ae66db..9b82f64 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -55,6 +55,7 @@
 
 #include "backtrace.h"
 #include "getevent.h"
+#include "open_files_list.h"
 #include "signal_sender.h"
 #include "tombstone.h"
 #include "utility.h"
@@ -184,6 +185,16 @@
    return allowed;
 }
 
+static bool pid_contains_tid(pid_t pid, pid_t tid) {
+  char task_path[PATH_MAX];
+  if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
+    ALOGE("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
+    exit(1);
+  }
+
+  return access(task_path, F_OK) == 0;
+}
+
 static int read_request(int fd, debugger_request_t* out_request) {
   ucred cr;
   socklen_t len = sizeof(cr);
@@ -226,16 +237,13 @@
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
-    char buf[64];
-    struct stat s;
-    snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
-    if (stat(buf, &s)) {
-      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
-          out_request->tid, out_request->pid);
+    // This check needs to happen again after ptracing the requested thread to prevent a race.
+    if (!pid_contains_tid(out_request->pid, out_request->tid)) {
+      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
+            out_request->pid);
       return -1;
     }
-  } else if (cr.uid == 0
-            || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
+  } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
     // Only root or system can ask us to attach to any process and dump it explicitly.
     // However, system is only allowed to collect backtraces but cannot dump tombstones.
     status = get_process_info(out_request->tid, &out_request->pid,
@@ -412,10 +420,31 @@
 }
 #endif
 
-static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::set<pid_t>& tids) {
-  char task_path[64];
+// Attach to a thread, and verify that it's still a member of the given process
+static bool ptrace_attach_thread(pid_t pid, pid_t tid) {
+  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+    return false;
+  }
 
-  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+  // Make sure that the task we attached to is actually part of the pid we're dumping.
+  if (!pid_contains_tid(pid, tid)) {
+    if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+      ALOGE("debuggerd: failed to detach from thread '%d'", tid);
+      exit(1);
+    }
+    return false;
+  }
+
+  return true;
+}
+
+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) {
+    ALOGE("debuggerd: task path overflow (pid = %d)\n", pid);
+    abort();
+  }
 
   std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path), closedir);
 
@@ -442,7 +471,7 @@
       continue;
     }
 
-    if (ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
+    if (!ptrace_attach_thread(pid, tid)) {
       ALOGE("debuggerd: ptrace attach to %d failed: %s", tid, strerror(errno));
       continue;
     }
@@ -452,7 +481,8 @@
 }
 
 static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
-                         BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
+                         BacktraceMap* backtrace_map, const OpenFilesList& open_files,
+                         const std::set<pid_t>& siblings,
                          int* crash_signal, std::string* amfd_data) {
   if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
     ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
@@ -471,7 +501,8 @@
       case SIGSTOP:
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("debuggerd: stopped -- dumping to tombstone");
-          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+          engrave_tombstone(tombstone_fd, backtrace_map, open_files,
+                            request.pid, request.tid, siblings,
                             request.abort_msg_address, amfd_data);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
@@ -498,7 +529,8 @@
       case SIGTRAP:
         ALOGV("stopped -- fatal signal\n");
         *crash_signal = signal;
-        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+        engrave_tombstone(tombstone_fd, backtrace_map, open_files,
+                          request.pid, request.tid, siblings,
                           request.abort_msg_address, amfd_data);
         break;
 
@@ -568,11 +600,33 @@
   // debugger_signal_handler().
 
   // Attach to the target process.
-  if (ptrace(PTRACE_ATTACH, request.tid, 0, 0) != 0) {
+  if (!ptrace_attach_thread(request.pid, request.tid)) {
     ALOGE("debuggerd: ptrace attach failed: %s", strerror(errno));
     exit(1);
   }
 
+  // DEBUGGER_ACTION_CRASH requests can come from arbitrary processes and the tid field in the
+  // request is sent from the other side. If an attacker can cause a process to be spawned with the
+  // pid of their process, they could trick debuggerd into dumping that process by exiting after
+  // sending the request. Validate the trusted request.uid/gid to defend against this.
+  if (request.action == DEBUGGER_ACTION_CRASH) {
+    pid_t pid;
+    uid_t uid;
+    gid_t gid;
+    if (get_process_info(request.tid, &pid, &uid, &gid) != 0) {
+      ALOGE("debuggerd: failed to get process info for tid '%d'", request.tid);
+      exit(1);
+    }
+
+    if (pid != request.pid || uid != request.uid || gid != request.gid) {
+      ALOGE(
+        "debuggerd: attached task %d does not match request: "
+        "expected pid=%d,uid=%d,gid=%d, actual pid=%d,uid=%d,gid=%d",
+        request.tid, request.pid, request.uid, request.gid, pid, uid, gid);
+      exit(1);
+    }
+  }
+
   // Don't attach to the sibling threads if we want to attach gdb.
   // Supposedly, it makes the process less reliable.
   bool attach_gdb = should_attach_gdb(request);
@@ -593,6 +647,10 @@
   // Generate the backtrace map before dropping privileges.
   std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
 
+  // Collect the list of open files before dropping privileges.
+  OpenFilesList open_files;
+  populate_open_files_list(request.pid, &open_files);
+
   int amfd = -1;
   std::unique_ptr<std::string> amfd_data;
   if (request.action == DEBUGGER_ACTION_CRASH) {
@@ -610,8 +668,8 @@
   }
 
   int crash_signal = SIGKILL;
-  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
-                           &crash_signal, amfd_data.get());
+  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), open_files,
+                           siblings, &crash_signal, amfd_data.get());
   if (succeeded) {
     if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
       if (!tombstone_path.empty()) {
diff --git a/debuggerd/open_files_list.cpp b/debuggerd/open_files_list.cpp
new file mode 100644
index 0000000..5ef2abc
--- /dev/null
+++ b/debuggerd/open_files_list.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "DEBUG"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android/log.h>
+
+#include "open_files_list.h"
+
+#include "utility.h"
+
+void populate_open_files_list(pid_t pid, OpenFilesList* list) {
+  std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd";
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fd_dir_name.c_str()), closedir);
+  if (dir == nullptr) {
+    ALOGE("failed to open directory %s: %s", fd_dir_name.c_str(), strerror(errno));
+    return;
+  }
+
+  struct dirent* de;
+  while ((de = readdir(dir.get())) != nullptr) {
+    if (*de->d_name == '.') {
+      continue;
+    }
+
+    int fd = atoi(de->d_name);
+    std::string path = fd_dir_name + "/" + std::string(de->d_name);
+    std::string target;
+    if (android::base::Readlink(path, &target)) {
+      list->emplace_back(fd, target);
+    } else {
+      ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno));
+      list->emplace_back(fd, "???");
+    }
+  }
+}
+
+void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix) {
+  for (auto& file : files) {
+    _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
+  }
+}
+
diff --git a/debuggerd/open_files_list.h b/debuggerd/open_files_list.h
new file mode 100644
index 0000000..b37228d
--- /dev/null
+++ b/debuggerd/open_files_list.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _DEBUGGERD_OPEN_FILES_LIST_H
+#define _DEBUGGERD_OPEN_FILES_LIST_H
+
+#include <sys/types.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "utility.h"
+
+typedef std::vector<std::pair<int, std::string>> OpenFilesList;
+
+/* Populates the given list with open files for the given process. */
+void populate_open_files_list(pid_t pid, OpenFilesList* list);
+
+/* Dumps the open files list to the log. */
+void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix);
+
+#endif // _DEBUGGERD_OPEN_FILES_LIST_H
diff --git a/debuggerd/test/open_files_list_test.cpp b/debuggerd/test/open_files_list_test.cpp
new file mode 100644
index 0000000..85e0695
--- /dev/null
+++ b/debuggerd/test/open_files_list_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "android-base/test_utils.h"
+
+#include "open_files_list.h"
+
+// Check that we can produce a list of open files for the current process, and
+// that it includes a known open file.
+TEST(OpenFilesListTest, BasicTest) {
+  // Open a temporary file that we can check for in the list of open files.
+  TemporaryFile tf;
+
+  // Get the list of open files for this process.
+  OpenFilesList list;
+  populate_open_files_list(getpid(), &list);
+
+  // Verify our open file is in the list.
+  bool found = false;
+  for (auto&  file : list) {
+    if (file.first == tf.fd) {
+      EXPECT_EQ(file.second, std::string(tf.path));
+      found = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(found);
+}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 1e47483..e76edb9 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -46,6 +46,7 @@
 #include "backtrace.h"
 #include "elf_utils.h"
 #include "machine.h"
+#include "open_files_list.h"
 #include "tombstone.h"
 
 #define STACK_WORDS 16
@@ -571,7 +572,7 @@
 
     if (log_entry.id() == LOG_ID_EVENTS) {
       if (!g_eventTagMap) {
-        g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        g_eventTagMap = android_openEventTagMap(NULL);
       }
       AndroidLogEntry e;
       char buf[512];
@@ -620,7 +621,8 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
+static void dump_crash(log_t* log, BacktraceMap* map,
+                       const OpenFilesList& open_files, 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
   bool want_logs = __android_log_is_debuggable();
@@ -639,6 +641,9 @@
     }
   }
 
+  _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
+  dump_open_files_list_to_log(open_files, log, "    ");
+
   if (want_logs) {
     dump_logs(log, pid, 0);
   }
@@ -697,7 +702,8 @@
   return fd;
 }
 
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
+                       const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
                        std::string* amfd_data) {
   log_t log;
@@ -711,5 +717,5 @@
 
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, pid, tid, siblings, abort_msg_address);
+  dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index e1c39c5..126f804 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -32,7 +32,8 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
+                       const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
                        std::string* amfd_data);
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index d820f0f..f7a3f73 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -70,7 +70,8 @@
   MAPS,
   MEMORY,
   STACK,
-  LOGS
+  LOGS,
+  OPEN_FILES
 };
 
 // Log information onto the tombstone.
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4cd423a..3f8bc8f 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));
     }
 }
 
@@ -1740,6 +1742,14 @@
         } else if(!strcmp(*argv, "set_active")) {
             require(2);
             std::string slot = verify_slot(transport, std::string(argv[1]), false);
+            // Legacy support: verify_slot() removes leading underscores, we need to put them back
+            // in for old bootloaders. Legacy bootloaders do not have the slot-count variable but
+            // do have slot-suffixes.
+            std::string var;
+            if (!fb_getvar(transport, "slot-count", &var) &&
+                    fb_getvar(transport, "slot-suffixes", &var)) {
+                slot = "_" + slot;
+            }
             fb_set_active(slot.c_str());
             skip(2);
         } else if(!strcmp(*argv, "oem")) {
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 6db1e27..cdab4f1 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -43,11 +43,15 @@
 #include <linux/version.h>
 #include <linux/usb/ch9.h>
 
+#include <chrono>
 #include <memory>
+#include <thread>
 
 #include "fastboot.h"
 #include "usb.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_RETRIES 5
 
 /* Timeout in seconds for usb_wait_for_disconnect.
@@ -426,7 +430,7 @@
         return -1;
     }
 
-    while(len > 0) {
+    while (len > 0) {
         int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
         bulk.ep = handle_->ep_in;
@@ -435,18 +439,17 @@
         bulk.timeout = 0;
         retry = 0;
 
-        do{
-           DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
-           n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
-           DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
+        do {
+            DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
+            n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
+            DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
 
-           if( n < 0 ) {
-            DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
-            if ( ++retry > MAX_RETRIES ) return -1;
-            sleep( 1 );
-           }
-        }
-        while( n < 0 );
+            if (n < 0) {
+                DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
+                if (++retry > MAX_RETRIES) return -1;
+                std::this_thread::sleep_for(1s);
+            }
+        } while (n < 0);
 
         count += n;
         len -= n;
@@ -488,9 +491,8 @@
 {
   double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
   while (now() < deadline) {
-    if (access(handle_->fname, F_OK))
-      return 0;
-    usleep(50000);
+    if (access(handle_->fname, F_OK)) return 0;
+    std::this_thread::sleep_for(50ms);
   }
   return -1;
 }
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 1cdeb32..3dab5ac 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -362,9 +362,3 @@
     std::unique_ptr<usb_handle> handle = find_usb_device(callback);
     return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
 }
-
-// called from fastboot.c
-void sleep(int seconds)
-{
-    Sleep(seconds * 1000);
-}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index b1511fe..6e6d69f 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>
@@ -38,6 +39,7 @@
 #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>
@@ -50,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)))
 
@@ -179,6 +183,166 @@
     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 int do_quota(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+    int force_check = 0;
+    if (!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 {
+            char* arg1 = NULL;
+            char* arg2 = NULL;
+            int status = 0;
+            int ret = 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;
+                }
+
+                int has_quota = (sb.s_feature_ro_compat
+                        & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
+                int want_quota = fs_mgr_is_quota(rec) != 0;
+
+                if (has_quota == want_quota) {
+                    INFO("Requested quota status is match on %s\n", blk_device);
+                    goto out;
+                } else if (want_quota) {
+                    INFO("Enabling quota on %s\n", blk_device);
+                    arg1 = "-Oquota";
+                    arg2 = "-Qusrquota,grpquota";
+                    force_check = 1;
+                } else {
+                    INFO("Disabling quota on %s\n", blk_device);
+                    arg1 = "-Q^usrquota,^grpquota";
+                    arg2 = "-O^quota";
+                }
+            } else {
+                ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+                return force_check;
+            }
+
+            char *tune2fs_argv[] = {
+                TUNE2FS_BIN,
+                arg1,
+                arg2,
+                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);
+        }
+    }
+    return force_check;
+}
+
+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;
@@ -241,7 +405,7 @@
     return ret;
 }
 
-static int fs_match(const char *in1, const char *in2)
+static int fs_match(char *in1, char *in2)
 {
     char *n1;
     char *n2;
@@ -320,10 +484,19 @@
                 continue;
             }
 
-            if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                                       &fstab->recs[i]);
+
+            if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
                 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;
@@ -651,7 +824,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, const char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
@@ -684,11 +857,18 @@
             wait_for_file(n_blk_device, WAIT_TIMEOUT);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+        int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                                   &fstab->recs[i]);
+
+        if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
             check_fs(n_blk_device, fstab->recs[i].fs_type,
                      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 (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
@@ -802,6 +982,18 @@
              * we can assume the device number is 0.
              */
             FILE *zram_fp;
+            FILE *zram_mcs_fp;
+
+            if (fstab->recs[i].max_comp_streams >= 0) {
+               zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
+              if (zram_mcs_fp == NULL) {
+                ERROR("Unable to open zram conf comp device %s\n", ZRAM_CONF_MCS);
+                ret = -1;
+                continue;
+              }
+              fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
+              fclose(zram_mcs_fp);
+            }
 
             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
             if (zram_fp == NULL) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 313bc5a..41fb746 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -31,12 +31,15 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
+    unsigned int file_encryption_mode;
 };
 
 struct flag_list {
     const char *name;
-    unsigned flag;
+    unsigned int flag;
 };
 
 static struct flag_list mount_flags[] = {
@@ -59,27 +62,40 @@
 };
 
 static struct flag_list fs_mgr_flags[] = {
-    { "wait",        MF_WAIT },
-    { "check",       MF_CHECK },
-    { "encryptable=",MF_CRYPT },
-    { "forceencrypt=",MF_FORCECRYPT },
-    { "fileencryption",MF_FILEENCRYPTION },
-    { "forcefdeorfbe=",MF_FORCEFDEORFBE },
-    { "nonremovable",MF_NONREMOVABLE },
-    { "voldmanaged=",MF_VOLDMANAGED},
-    { "length=",     MF_LENGTH },
-    { "recoveryonly",MF_RECOVERYONLY },
-    { "swapprio=",   MF_SWAPPRIO },
-    { "zramsize=",   MF_ZRAMSIZE },
-    { "verify",      MF_VERIFY },
-    { "noemulatedsd", MF_NOEMULATEDSD },
-    { "notrim",       MF_NOTRIM },
-    { "formattable", MF_FORMATTABLE },
-    { "slotselect",  MF_SLOTSELECT },
-    { "nofail",      MF_NOFAIL },
-    { "latemount",   MF_LATEMOUNT },
-    { "defaults",    0 },
-    { 0,             0 },
+    { "wait",               MF_WAIT },
+    { "check",              MF_CHECK },
+    { "encryptable=",       MF_CRYPT },
+    { "forceencrypt=",      MF_FORCECRYPT },
+    { "fileencryption=",    MF_FILEENCRYPTION },
+    { "forcefdeorfbe=",     MF_FORCEFDEORFBE },
+    { "nonremovable",       MF_NONREMOVABLE },
+    { "voldmanaged=",       MF_VOLDMANAGED},
+    { "length=",            MF_LENGTH },
+    { "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 },
+    { "formattable",        MF_FORMATTABLE },
+    { "slotselect",         MF_SLOTSELECT },
+    { "nofail",             MF_NOFAIL },
+    { "latemount",          MF_LATEMOUNT },
+    { "reservedsize=",      MF_RESERVEDSIZE },
+    { "quota",              MF_QUOTA },
+    { "defaults",           0 },
+    { 0,                    0 },
+};
+
+#define EM_SOFTWARE 1
+#define EM_ICE      2
+
+static struct flag_list encryption_modes[] = {
+    {"software", EM_SOFTWARE},
+    {"ice", EM_ICE},
+    {0, 0}
 };
 
 static uint64_t calculate_zram_size(unsigned int percentage)
@@ -95,6 +111,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)
@@ -148,6 +178,21 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                    flag_vals->file_encryption_mode = EM_SOFTWARE;
+                } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+                    /* The fileencryption flag is followed by an = and the
+                     * type of the encryption.  Get it and return it.
+                     */
+                    const struct flag_list *j;
+                    const char *mode = strchr(p, '=') + 1;
+                    for (j = encryption_modes; j->name; ++j) {
+                        if (!strcmp(mode, j->name)) {
+                            flag_vals->file_encryption_mode = j->flag;
+                        }
+                    }
+                    if (flag_vals->file_encryption_mode == 0) {
+                        ERROR("Unknown file encryption mode: %s\n", mode);
+                    }
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -180,6 +225,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);
@@ -187,6 +234,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;
             }
@@ -329,7 +381,10 @@
         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++;
     }
     /* If an A/B partition, modify block device to be the real block device */
@@ -488,6 +543,17 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab)
+{
+    const struct flag_list *j;
+    for (j = encryption_modes; j->name; ++j) {
+        if (fstab->file_encryption_mode == j->flag) {
+            return j->name;
+        }
+    }
+    return NULL;
+}
+
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
@@ -522,3 +588,8 @@
 {
     return fstab->fs_mgr_flags & MF_LATEMOUNT;
 }
+
+int fs_mgr_is_quota(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_QUOTA;
+}
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 4bfe202..33a7496 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,17 +14,12 @@
  * 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)
@@ -37,10 +32,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 * const argv[], int *a_flag, int *u_flag, int *n_flag,
-                     const char **n_name, const char **n_blk_dev)
+static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
+                     char **n_name, char **n_blk_dev)
 {
-    me = basename(argv[0]);
+    me = basename(strdup(argv[0]));
 
     if (argc <= 1) {
         usage();
@@ -80,14 +75,14 @@
     return;
 }
 
-int main(int argc, char * const argv[])
+int main(int argc, char *argv[])
 {
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    const char *n_name=NULL;
-    const char *n_blk_dev=NULL;
-    const char *fstab_file=NULL;
+    char *n_name=NULL;
+    char *n_blk_dev=NULL;
+    char *fstab_file=NULL;
     struct fstab *fstab=NULL;
 
     klog_set_level(6);
@@ -102,7 +97,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, (char *)n_blk_dev, 0);
+        return fs_mgr_do_mount(fstab, n_name, 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..db86afa 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -65,26 +65,30 @@
  *
  */
 
-#define MF_WAIT         0x1
-#define MF_CHECK        0x2
-#define MF_CRYPT        0x4
-#define MF_NONREMOVABLE 0x8
-#define MF_VOLDMANAGED  0x10
-#define MF_LENGTH       0x20
-#define MF_RECOVERYONLY 0x40
-#define MF_SWAPPRIO     0x80
-#define MF_ZRAMSIZE     0x100
-#define MF_VERIFY       0x200
-#define MF_FORCECRYPT   0x400
-#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
-                                 external storage */
-#define MF_NOTRIM       0x1000
-#define MF_FILEENCRYPTION 0x2000
-#define MF_FORMATTABLE  0x4000
-#define MF_SLOTSELECT   0x8000
-#define MF_FORCEFDEORFBE 0x10000
-#define MF_LATEMOUNT    0x20000
-#define MF_NOFAIL       0x40000
+#define MF_WAIT                  0x1
+#define MF_CHECK                 0x2
+#define MF_CRYPT                 0x4
+#define MF_NONREMOVABLE          0x8
+#define MF_VOLDMANAGED          0x10
+#define MF_LENGTH               0x20
+#define MF_RECOVERYONLY         0x40
+#define MF_SWAPPRIO             0x80
+#define MF_ZRAMSIZE            0x100
+#define MF_VERIFY              0x200
+#define MF_FORCECRYPT          0x400
+#define MF_NOEMULATEDSD        0x800 /* no emulated sdcard daemon, sd card is the only
+                                        external storage */
+#define MF_NOTRIM             0x1000
+#define MF_FILEENCRYPTION     0x2000
+#define MF_FORMATTABLE        0x4000
+#define MF_SLOTSELECT         0x8000
+#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 MF_QUOTA            0x400000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 67104cc..031b042 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -181,7 +181,7 @@
     return -1;
 }
 
-static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
+static void verity_ioctl_init(struct dm_ioctl *io, const char *name, unsigned flags)
 {
     memset(io, 0, DM_BUF_SIZE);
     io->data_size = DM_BUF_SIZE;
@@ -784,8 +784,9 @@
 int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
 {
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+    bool system_root = false;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-    char *mount_point;
+    const char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
     char *status;
     int fd = -1;
@@ -813,6 +814,9 @@
     property_get("ro.hardware", propbuf, "");
     snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
 
+    property_get("ro.build.system_root_image", propbuf, "");
+    system_root = !strcmp(propbuf, "true");
+
     fstab = fs_mgr_read_fstab(fstab_filename);
 
     if (!fstab) {
@@ -825,7 +829,12 @@
             continue;
         }
 
-        mount_point = basename(fstab->recs[i].mount_point);
+        if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+            mount_point = "system";
+        } else {
+            mount_point = basename(fstab->recs[i].mount_point);
+        }
+
         verity_ioctl_init(io, mount_point, 0);
 
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
@@ -836,7 +845,9 @@
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
-        callback(&fstab->recs[i], mount_point, mode, *status);
+        if (*status == 'C' || *status == 'V') {
+            callback(&fstab->recs[i], mount_point, mode, *status);
+        }
     }
 
     rc = 0;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b120f7c..e7a0a1d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -73,7 +73,10 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
+    unsigned int file_encryption_mode;
 };
 
 // Callback function for verity status
@@ -95,7 +98,8 @@
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
+
+int fs_mgr_do_mount(struct fstab *fstab, 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);
@@ -112,12 +116,14 @@
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
 int fs_mgr_is_nofail(struct fstab_rec *fstab);
 int fs_mgr_is_latemount(struct fstab_rec *fstab);
+int fs_mgr_is_quota(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index 8b15d72..cb02a6f 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -152,7 +152,7 @@
     }
 
     bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
-        uint64_t user_id = android::base::get_unaligned(&expected_handle->user_id);
+        uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
         FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
         if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
             return true;
diff --git a/healthd/Android.mk b/healthd/Android.mk
index deebed5..7c5e35b 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -21,6 +21,36 @@
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    healthd_mode_android.cpp \
+    healthd_mode_charger.cpp \
+    AnimationParser.cpp \
+    BatteryPropertiesRegistrar.cpp \
+
+LOCAL_MODULE := libhealthd_internal
+LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/include \
+
+LOCAL_STATIC_LIBRARIES := \
+    libbatterymonitor \
+    libbatteryservice \
+    libbinder \
+    libminui \
+    libpng \
+    libz \
+    libutils \
+    libbase \
+    libcutils \
+    liblog \
+    libm \
+    libc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
 
 ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
 LOCAL_CHARGER_NO_UI := true
@@ -32,7 +62,7 @@
 LOCAL_SRC_FILES := \
 	healthd.cpp \
 	healthd_mode_android.cpp \
-	BatteryPropertiesRegistrar.cpp
+	BatteryPropertiesRegistrar.cpp \
 
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 LOCAL_SRC_FILES += healthd_mode_charger.cpp
@@ -60,13 +90,28 @@
 
 LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
 
-LOCAL_STATIC_LIBRARIES := libbatterymonitor libbatteryservice libbinder libbase
+LOCAL_STATIC_LIBRARIES := \
+    libhealthd_internal \
+    libbatterymonitor \
+    libbatteryservice \
+    libbinder \
+    libbase \
 
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_STATIC_LIBRARIES += libminui libpng libz
+LOCAL_STATIC_LIBRARIES += \
+   libminui \
+   libpng \
+   libz \
+
 endif
 
-LOCAL_STATIC_LIBRARIES += libutils libcutils liblog libm libc
+
+LOCAL_STATIC_LIBRARIES += \
+    libutils \
+    libcutils \
+    liblog \
+    libm \
+    libc \
 
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
 LOCAL_STATIC_LIBRARIES += libsuspend
@@ -84,7 +129,7 @@
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 define _add-charger-image
 include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_$(notdir $(1))
+LOCAL_MODULE := system_core_charger_res_images_$(notdir $(1))
 LOCAL_MODULE_STEM := $(notdir $(1))
 _img_modules += $$(LOCAL_MODULE)
 LOCAL_SRC_FILES := $1
diff --git a/healthd/AnimationParser.cpp b/healthd/AnimationParser.cpp
new file mode 100644
index 0000000..864038b
--- /dev/null
+++ b/healthd/AnimationParser.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "AnimationParser.h"
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include <cutils/klog.h>
+
+#include "animation.h"
+
+#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
+#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
+#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+
+namespace android {
+
+// Lines consisting of only whitespace or whitespace followed by '#' can be ignored.
+bool can_ignore_line(const char* str) {
+    for (int i = 0; str[i] != '\0' && str[i] != '#'; i++) {
+        if (!isspace(str[i])) return false;
+    }
+    return true;
+}
+
+bool remove_prefix(const std::string& line, const char* prefix, const char** rest) {
+    const char* str = line.c_str();
+    int start;
+    char c;
+
+    std::string format = base::StringPrintf(" %s%%n%%c", prefix);
+    if (sscanf(str, format.c_str(), &start, &c) != 1) {
+        return false;
+    }
+
+    *rest = &str[start];
+    return true;
+}
+
+bool parse_text_field(const char* in, animation::text_field* field) {
+    int* x = &field->pos_x;
+    int* y = &field->pos_y;
+    int* r = &field->color_r;
+    int* g = &field->color_g;
+    int* b = &field->color_b;
+    int* a = &field->color_a;
+
+    int start = 0, end = 0;
+
+    if (sscanf(in, "c c %d %d %d %d %n%*s%n", r, g, b, a, &start, &end) == 4) {
+        *x = CENTER_VAL;
+        *y = CENTER_VAL;
+    } else if (sscanf(in, "c %d %d %d %d %d %n%*s%n", y, r, g, b, a, &start, &end) == 5) {
+        *x = CENTER_VAL;
+    } else if (sscanf(in, "%d c %d %d %d %d %n%*s%n", x, r, g, b, a, &start, &end) == 5) {
+        *y = CENTER_VAL;
+    } else if (sscanf(in, "%d %d %d %d %d %d %n%*s%n", x, y, r, g, b, a, &start, &end) != 6) {
+        return false;
+    }
+
+    if (end == 0) return false;
+
+    field->font_file.assign(&in[start], end - start);
+
+    return true;
+}
+
+bool parse_animation_desc(const std::string& content, animation* anim) {
+    static constexpr const char* animation_prefix = "animation: ";
+    static constexpr const char* fail_prefix = "fail: ";
+    static constexpr const char* clock_prefix = "clock_display: ";
+    static constexpr const char* percent_prefix = "percent_display: ";
+    static constexpr const char* frame_prefix = "frame: ";
+
+    std::vector<animation::frame> frames;
+
+    for (const auto& line : base::Split(content, "\n")) {
+        animation::frame frame;
+        const char* rest;
+
+        if (can_ignore_line(line.c_str())) {
+            continue;
+        } else if (remove_prefix(line, animation_prefix, &rest)) {
+            int start = 0, end = 0;
+            if (sscanf(rest, "%d %d %n%*s%n", &anim->num_cycles, &anim->first_frame_repeats,
+                    &start, &end) != 2 ||
+                end == 0) {
+                LOGE("Bad animation format: %s\n", line.c_str());
+                return false;
+            } else {
+                anim->animation_file.assign(&rest[start], end - start);
+            }
+        } else if (remove_prefix(line, fail_prefix, &rest)) {
+            anim->fail_file.assign(rest);
+        } else if (remove_prefix(line, clock_prefix, &rest)) {
+            if (!parse_text_field(rest, &anim->text_clock)) {
+                LOGE("Bad clock_display format: %s\n", line.c_str());
+                return false;
+            }
+        } else if (remove_prefix(line, percent_prefix, &rest)) {
+            if (!parse_text_field(rest, &anim->text_percent)) {
+                LOGE("Bad percent_display format: %s\n", line.c_str());
+                return false;
+            }
+        } else if (sscanf(line.c_str(), " frame: %d %d %d",
+                &frame.disp_time, &frame.min_level, &frame.max_level) == 3) {
+            frames.push_back(std::move(frame));
+        } else {
+            LOGE("Malformed animation description line: %s\n", line.c_str());
+            return false;
+        }
+    }
+
+    if (anim->animation_file.empty() || frames.empty()) {
+        LOGE("Bad animation description. Provide the 'animation: ' line and at least one 'frame: ' "
+             "line.\n");
+        return false;
+    }
+
+    anim->num_frames = frames.size();
+    anim->frames = new animation::frame[frames.size()];
+    std::copy(frames.begin(), frames.end(), anim->frames);
+
+    return true;
+}
+
+}  // namespace android
diff --git a/healthd/AnimationParser.h b/healthd/AnimationParser.h
new file mode 100644
index 0000000..bc00845
--- /dev/null
+++ b/healthd/AnimationParser.h
@@ -0,0 +1,31 @@
+/*
+ * 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 HEALTHD_ANIMATION_PARSER_H
+#define HEALTHD_ANIMATION_PARSER_H
+
+#include "animation.h"
+
+namespace android {
+
+bool parse_animation_desc(const std::string& content, animation* anim);
+
+bool can_ignore_line(const char* str);
+bool remove_prefix(const std::string& str, const char* prefix, const char** rest);
+bool parse_text_field(const char* in, animation::text_field* field);
+}  // namespace android
+
+#endif // HEALTHD_ANIMATION_PARSER_H
diff --git a/healthd/animation.h b/healthd/animation.h
new file mode 100644
index 0000000..562b689
--- /dev/null
+++ b/healthd/animation.h
@@ -0,0 +1,73 @@
+/*
+ * 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 HEALTHD_ANIMATION_H
+#define HEALTHD_ANIMATION_H
+
+#include <inttypes.h>
+#include <string>
+
+struct GRSurface;
+struct GRFont;
+
+namespace android {
+
+#define CENTER_VAL INT_MAX
+
+struct animation {
+    struct frame {
+        int disp_time;
+        int min_level;
+        int max_level;
+
+        GRSurface* surface;
+    };
+
+    struct text_field {
+        std::string font_file;
+        int pos_x;
+        int pos_y;
+        int color_r;
+        int color_g;
+        int color_b;
+        int color_a;
+
+        GRFont* font;
+    };
+
+    std::string animation_file;
+    std::string fail_file;
+
+    text_field text_clock;
+    text_field text_percent;
+
+    bool run;
+
+    frame* frames;
+    int cur_frame;
+    int num_frames;
+    int first_frame_repeats;  // Number of times to repeat the first frame in the current cycle
+
+    int cur_cycle;
+    int num_cycles;  // Number of cycles to complete before blanking the screen
+
+    int cur_level;  // current battery level being animated (0-100)
+    int cur_status;  // current battery status - see BatteryService.h for BATTERY_STATUS_*
+};
+
+}
+
+#endif // HEALTHD_ANIMATION_H
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 612885b..36c4664 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -30,6 +30,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
 #include <sys/socket.h>
 #include <linux/netlink.h>
 
@@ -44,10 +47,14 @@
 #include <suspend/autosuspend.h>
 #endif
 
+#include "animation.h"
+#include "AnimationParser.h"
 #include "minui/minui.h"
 
 #include <healthd/healthd.h>
 
+using namespace android;
+
 char *locale;
 
 #ifndef max
@@ -67,8 +74,6 @@
 #define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
 
-#define BATTERY_FULL_THRESH     95
-
 #define LAST_KMSG_PATH          "/proc/last_kmsg"
 #define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
 #define LAST_KMSG_MAX_SZ        (32 * 1024)
@@ -77,34 +82,14 @@
 #define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
 #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
 
+static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
+
 struct key_state {
     bool pending;
     bool down;
     int64_t timestamp;
 };
 
-struct frame {
-    int disp_time;
-    int min_capacity;
-    bool level_only;
-
-    GRSurface* surface;
-};
-
-struct animation {
-    bool run;
-
-    struct frame *frames;
-    int cur_frame;
-    int num_frames;
-
-    int cur_cycle;
-    int num_cycles;
-
-    /* current capacity being animated */
-    int capacity;
-};
-
 struct charger {
     bool have_battery_state;
     bool charger_connected;
@@ -119,54 +104,83 @@
     int boot_min_cap;
 };
 
-static struct frame batt_anim_frames[] = {
+static const struct animation BASE_ANIMATION = {
+    .text_clock = {
+        .pos_x = 0,
+        .pos_y = 0,
+
+        .color_r = 255,
+        .color_g = 255,
+        .color_b = 255,
+        .color_a = 255,
+
+        .font = nullptr,
+    },
+    .text_percent = {
+        .pos_x = 0,
+        .pos_y = 0,
+
+        .color_r = 255,
+        .color_g = 255,
+        .color_b = 255,
+        .color_a = 255,
+    },
+
+    .run = false,
+
+    .frames = nullptr,
+    .cur_frame = 0,
+    .num_frames = 0,
+    .first_frame_repeats = 2,
+
+    .cur_cycle = 0,
+    .num_cycles = 3,
+
+    .cur_level = 0,
+    .cur_status = BATTERY_STATUS_UNKNOWN,
+};
+
+
+static struct animation::frame default_animation_frames[] = {
     {
         .disp_time = 750,
-        .min_capacity = 0,
-        .level_only = false,
+        .min_level = 0,
+        .max_level = 19,
         .surface = NULL,
     },
     {
         .disp_time = 750,
-        .min_capacity = 20,
-        .level_only = false,
+        .min_level = 0,
+        .max_level = 39,
         .surface = NULL,
     },
     {
         .disp_time = 750,
-        .min_capacity = 40,
-        .level_only = false,
+        .min_level = 0,
+        .max_level = 59,
         .surface = NULL,
     },
     {
         .disp_time = 750,
-        .min_capacity = 60,
-        .level_only = false,
+        .min_level = 0,
+        .max_level = 79,
         .surface = NULL,
     },
     {
         .disp_time = 750,
-        .min_capacity = 80,
-        .level_only = true,
+        .min_level = 80,
+        .max_level = 95,
         .surface = NULL,
     },
     {
         .disp_time = 750,
-        .min_capacity = BATTERY_FULL_THRESH,
-        .level_only = false,
+        .min_level = 0,
+        .max_level = 100,
         .surface = NULL,
     },
 };
 
-static struct animation battery_animation = {
-    .run = false,
-    .frames = batt_anim_frames,
-    .cur_frame = 0,
-    .num_frames = ARRAY_SIZE(batt_anim_frames),
-    .cur_cycle = 0,
-    .num_cycles = 3,
-    .capacity = 0,
-};
+static struct animation battery_animation = BASE_ANIMATION;
 
 static struct charger charger_state;
 static struct healthd_config *healthd_config;
@@ -257,13 +271,13 @@
 
 static int draw_text(const char *str, int x, int y)
 {
-    int str_len_px = gr_measure(str);
+    int str_len_px = gr_measure(gr_sys_font(), str);
 
     if (x < 0)
         x = (gr_fb_width() - str_len_px) / 2;
     if (y < 0)
         y = (gr_fb_height() - char_height) / 2;
-    gr_text(x, y, str, 0);
+    gr_text(gr_sys_font(), x, y, str, 0);
 
     return y + char_height;
 }
@@ -273,8 +287,79 @@
     gr_color(0xa4, 0xc6, 0x39, 255);
 }
 
+// Negative x or y coordinates position the text away from the opposite edge that positive ones do.
+void determine_xy(const animation::text_field& field, const int length, int* x, int* y)
+{
+    *x = field.pos_x;
+    *y = field.pos_y;
+
+    int str_len_px = length * field.font->char_width;
+    if (field.pos_x == CENTER_VAL) {
+        *x = (gr_fb_width() - str_len_px) / 2;
+    } else if (field.pos_x >= 0) {
+        *x = field.pos_x;
+    } else {  // position from max edge
+        *x = gr_fb_width() + field.pos_x - str_len_px;
+    }
+
+    if (field.pos_y == CENTER_VAL) {
+        *y = (gr_fb_height() - field.font->char_height) / 2;
+    } else if (field.pos_y >= 0) {
+        *y = field.pos_y;
+    } else {  // position from max edge
+        *y = gr_fb_height() + field.pos_y - field.font->char_height;
+    }
+}
+
+static void draw_clock(const animation& anim)
+{
+    static constexpr char CLOCK_FORMAT[] = "%H:%M";
+    static constexpr int CLOCK_LENGTH = 6;
+
+    const animation::text_field& field = anim.text_clock;
+
+    if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
+
+    time_t rawtime;
+    time(&rawtime);
+    struct tm* time_info = localtime(&rawtime);
+
+    char clock_str[CLOCK_LENGTH];
+    size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
+    if (length != CLOCK_LENGTH - 1) {
+        LOGE("Could not format time\n");
+        return;
+    }
+
+    int x, y;
+    determine_xy(field, length, &x, &y);
+
+    LOGV("drawing clock %s %d %d\n", clock_str, x, y);
+    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+    gr_text(field.font, x, y, clock_str, false);
+}
+
+static void draw_percent(const animation& anim)
+{
+    if (anim.cur_level <= 0 || anim.cur_status != BATTERY_STATUS_CHARGING) 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);
+
+    int x, y;
+    determine_xy(field, str.size(), &x, &y);
+
+    LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
+    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+    gr_text(field.font, x, y, str.c_str(), false);
+}
+
 /* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger* /*charger*/, GRSurface* surface)
+static int draw_surface_centered(GRSurface* surface)
 {
     int w;
     int h;
@@ -295,7 +380,7 @@
 {
     int y;
     if (charger->surf_unknown) {
-        draw_surface_centered(charger, charger->surf_unknown);
+        draw_surface_centered(charger->surf_unknown);
     } else {
         android_green();
         y = draw_text("Charging!", -1, -1);
@@ -303,17 +388,19 @@
     }
 }
 
-static void draw_battery(struct charger *charger)
+static void draw_battery(const struct charger* charger)
 {
-    struct animation *batt_anim = charger->batt_anim;
-    struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
+    const struct animation& anim = *charger->batt_anim;
+    const struct animation::frame& frame = anim.frames[anim.cur_frame];
 
-    if (batt_anim->num_frames != 0) {
-        draw_surface_centered(charger, frame->surface);
+    if (anim.num_frames != 0) {
+        draw_surface_centered(frame.surface);
         LOGV("drawing frame #%d min_cap=%d time=%d\n",
-             batt_anim->cur_frame, frame->min_capacity,
-             frame->disp_time);
+             anim.cur_frame, frame.min_level,
+             frame.disp_time);
     }
+    draw_clock(anim);
+    draw_percent(anim);
 }
 
 static void redraw_screen(struct charger *charger)
@@ -323,7 +410,7 @@
     clear_screen();
 
     /* try to display *something* */
-    if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
+    if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
         draw_unknown(charger);
     else
         draw_battery(charger);
@@ -342,16 +429,33 @@
     anim->run = false;
 }
 
+static void init_status_display(struct animation* anim)
+{
+    int res;
+
+    if (!anim->text_clock.font_file.empty()) {
+        if ((res =
+                gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
+            LOGE("Could not load time font (%d)\n", res);
+        }
+    }
+
+    if (!anim->text_percent.font_file.empty()) {
+        if ((res =
+                gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
+            LOGE("Could not load percent font (%d)\n", res);
+        }
+    }
+}
+
 static void update_screen_state(struct charger *charger, int64_t now)
 {
     struct animation *batt_anim = charger->batt_anim;
     int disp_time;
 
-    if (!batt_anim->run || now < charger->next_screen_transition)
-        return;
+    if (!batt_anim->run || now < charger->next_screen_transition) return;
 
     if (!minui_inited) {
-
         if (healthd_config && healthd_config->screen_on) {
             if (!healthd_config->screen_on(batt_prop)) {
                 LOGV("[%" PRId64 "] leave screen off\n", now);
@@ -364,7 +468,8 @@
         }
 
         gr_init();
-        gr_font_size(&char_width, &char_height);
+        gr_font_size(gr_sys_font(), &char_width, &char_height);
+        init_status_display(batt_anim);
 
 #ifndef CHARGER_DISABLE_INIT_BLANK
         gr_fb_blank(true);
@@ -373,7 +478,7 @@
     }
 
     /* animation is over, blank screen and leave */
-    if (batt_anim->cur_cycle == batt_anim->num_cycles) {
+    if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
         reset_animation(batt_anim);
         charger->next_screen_transition = -1;
         gr_fb_blank(true);
@@ -389,21 +494,24 @@
     if (batt_anim->cur_frame == 0) {
 
         LOGV("[%" PRId64 "] animation starting\n", now);
-        if (batt_prop && batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
-            int i;
+        if (batt_prop) {
+            batt_anim->cur_level = batt_prop->batteryLevel;
+            batt_anim->cur_status = batt_prop->batteryStatus;
+            if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
+                /* find first frame given current battery level */
+                for (int i = 0; i < batt_anim->num_frames; i++) {
+                    if (batt_anim->cur_level >= batt_anim->frames[i].min_level &&
+                        batt_anim->cur_level <= batt_anim->frames[i].max_level) {
+                        batt_anim->cur_frame = i;
+                        break;
+                    }
+                }
 
-            /* find first frame given current capacity */
-            for (i = 1; i < batt_anim->num_frames; i++) {
-                if (batt_prop->batteryLevel < batt_anim->frames[i].min_capacity)
-                    break;
+                // repeat the first frame first_frame_repeats times
+                disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
+                    batt_anim->first_frame_repeats;
             }
-            batt_anim->cur_frame = i - 1;
-
-            /* show the first frame for twice as long */
-            disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
         }
-        if (batt_prop)
-            batt_anim->capacity = batt_prop->batteryLevel;
     }
 
     /* unblank the screen  on first cycle */
@@ -416,8 +524,8 @@
     /* if we don't have anim frames, we only have one image, so just bump
      * the cycle counter and exit
      */
-    if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
-        LOGV("[%" PRId64 "] animation missing or unknown battery status\n", now);
+    if (batt_anim->num_frames == 0 || batt_anim->cur_level < 0) {
+        LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
         batt_anim->cur_cycle++;
         return;
@@ -432,12 +540,11 @@
     if (charger->charger_connected) {
         batt_anim->cur_frame++;
 
-        /* if the frame is used for level-only, that is only show it when it's
-         * the current level, skip it during the animation.
-         */
         while (batt_anim->cur_frame < batt_anim->num_frames &&
-               batt_anim->frames[batt_anim->cur_frame].level_only)
+               (batt_anim->cur_level < batt_anim->frames[batt_anim->cur_frame].min_level ||
+                batt_anim->cur_level > batt_anim->frames[batt_anim->cur_frame].max_level)) {
             batt_anim->cur_frame++;
+        }
         if (batt_anim->cur_frame >= batt_anim->num_frames) {
             batt_anim->cur_cycle++;
             batt_anim->cur_frame = 0;
@@ -521,7 +628,7 @@
                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
                     property_set("sys.boot_from_charger_mode", "1");
                 } else {
-                    if (charger->batt_anim->capacity >= charger->boot_min_cap) {
+                    if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
                         LOGW("[%" PRId64 "] rebooting\n", now);
                         android_reboot(ANDROID_RB_RESTART, 0, 0);
                     } else {
@@ -672,6 +779,52 @@
         ev_dispatch();
 }
 
+animation* init_animation()
+{
+    bool parse_success;
+
+    std::string content;
+    if (base::ReadFileToString(animation_desc_path, &content)) {
+        parse_success = parse_animation_desc(content, &battery_animation);
+    } else {
+        LOGW("Could not open animation description at %s\n", animation_desc_path);
+        parse_success = false;
+    }
+
+    if (!parse_success) {
+        LOGW("Could not parse animation description. Using default animation.\n");
+        battery_animation = BASE_ANIMATION;
+        battery_animation.animation_file.assign("charger/battery_scale");
+        battery_animation.frames = default_animation_frames;
+        battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
+    }
+    if (battery_animation.fail_file.empty()) {
+        battery_animation.fail_file.assign("charger/battery_fail");
+    }
+
+    LOGV("Animation Description:\n");
+    LOGV("  animation: %d %d '%s' (%d)\n",
+        battery_animation.num_cycles, battery_animation.first_frame_repeats,
+        battery_animation.animation_file.c_str(), battery_animation.num_frames);
+    LOGV("  fail_file: '%s'\n", battery_animation.fail_file.c_str());
+    LOGV("  clock: %d %d %d %d %d %d '%s'\n",
+        battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
+        battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
+        battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
+        battery_animation.text_clock.font_file.c_str());
+    LOGV("  percent: %d %d %d %d %d %d '%s'\n",
+        battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
+        battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
+        battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
+        battery_animation.text_percent.font_file.c_str());
+    for (int i = 0; i < battery_animation.num_frames; i++) {
+        LOGV("  frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
+            battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
+    }
+
+    return &battery_animation;
+}
+
 void healthd_mode_charger_init(struct healthd_config* config)
 {
     int ret;
@@ -689,35 +842,39 @@
         healthd_register_event(epollfd, charger_event_handler);
     }
 
-    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
-    if (ret < 0) {
-        LOGE("Cannot load battery_fail image\n");
-        charger->surf_unknown = NULL;
-    }
+    struct animation* anim = init_animation();
+    charger->batt_anim = anim;
 
-    charger->batt_anim = &battery_animation;
+    ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
+    if (ret < 0) {
+        LOGE("Cannot load custom battery_fail image. Reverting to built in.\n");
+        ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
+        if (ret < 0) {
+            LOGE("Cannot load built in battery_fail image\n");
+            charger->surf_unknown = NULL;
+        }
+    }
 
     GRSurface** scale_frames;
     int scale_count;
     int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
                     // chunk). We are using hard-coded frame.disp_time instead.
-    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_fps,
-                                           &scale_frames);
+    ret = res_create_multi_display_surface(anim->animation_file.c_str(),
+        &scale_count, &scale_fps, &scale_frames);
     if (ret < 0) {
         LOGE("Cannot load battery_scale image\n");
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
-    } else if (scale_count != charger->batt_anim->num_frames) {
+        anim->num_frames = 0;
+        anim->num_cycles = 1;
+    } else if (scale_count != anim->num_frames) {
         LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
-             scale_count, charger->batt_anim->num_frames);
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
+             scale_count, anim->num_frames);
+        anim->num_frames = 0;
+        anim->num_cycles = 1;
     } else {
-        for (i = 0; i < charger->batt_anim->num_frames; i++) {
-            charger->batt_anim->frames[i].surface = scale_frames[i];
+        for (i = 0; i < anim->num_frames; i++) {
+            anim->frames[i].surface = scale_frames[i];
         }
     }
-
     ev_sync_key_state(set_key_callback, charger);
 
     charger->next_screen_transition = -1;
diff --git a/healthd/tests/Android.mk b/healthd/tests/Android.mk
new file mode 100644
index 0000000..87e8862
--- /dev/null
+++ b/healthd/tests/Android.mk
@@ -0,0 +1,21 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AnimationParser_test.cpp \
+
+LOCAL_MODULE := healthd_test
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_LIBRARIES := \
+	libhealthd_internal \
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libbase \
+	libcutils \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/healthd/tests/AnimationParser_test.cpp b/healthd/tests/AnimationParser_test.cpp
new file mode 100644
index 0000000..2fc3185
--- /dev/null
+++ b/healthd/tests/AnimationParser_test.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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 "AnimationParser.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+TEST(AnimationParserTest, Test_can_ignore_line) {
+    EXPECT_TRUE(can_ignore_line(""));
+    EXPECT_TRUE(can_ignore_line("     "));
+    EXPECT_TRUE(can_ignore_line("#"));
+    EXPECT_TRUE(can_ignore_line("   # comment"));
+
+    EXPECT_FALSE(can_ignore_line("text"));
+    EXPECT_FALSE(can_ignore_line("text # comment"));
+    EXPECT_FALSE(can_ignore_line("     text"));
+    EXPECT_FALSE(can_ignore_line("     text # comment"));
+}
+
+TEST(AnimationParserTest, Test_remove_prefix) {
+    static const char TEST_STRING[] = "abcdef";
+    const char* rest = nullptr;
+    EXPECT_FALSE(remove_prefix(TEST_STRING, "def", &rest));
+    // Ignore strings that only consist of the prefix
+    EXPECT_FALSE(remove_prefix(TEST_STRING, TEST_STRING, &rest));
+
+    EXPECT_TRUE(remove_prefix(TEST_STRING, "abc", &rest));
+    EXPECT_STREQ("def", rest);
+
+    EXPECT_TRUE(remove_prefix("  abcdef", "abc", &rest));
+    EXPECT_STREQ("def", rest);
+}
+
+TEST(AnimationParserTest, Test_parse_text_field) {
+    static const char TEST_FILE_NAME[] = "font_file";
+    static const int TEST_X = 3;
+    static const int TEST_Y = 6;
+    static const int TEST_R = 1;
+    static const int TEST_G = 2;
+    static const int TEST_B = 4;
+    static const int TEST_A = 8;
+
+    static const char TEST_XCENT_YCENT[] = "c c 1 2 4 8  font_file ";
+    static const char TEST_XCENT_YVAL[]  = "c 6 1 2 4 8  font_file ";
+    static const char TEST_XVAL_YCENT[]  = "3 c 1 2 4 8  font_file ";
+    static const char TEST_XVAL_YVAL[]   = "3 6 1 2 4 8  font_file ";
+    static const char TEST_BAD_MISSING[] = "c c 1 2 4 font_file";
+    static const char TEST_BAD_NO_FILE[] = "c c 1 2 4 8";
+
+    animation::text_field out;
+
+    EXPECT_TRUE(parse_text_field(TEST_XCENT_YCENT, &out));
+    EXPECT_EQ(CENTER_VAL, out.pos_x);
+    EXPECT_EQ(CENTER_VAL, out.pos_y);
+    EXPECT_EQ(TEST_R, out.color_r);
+    EXPECT_EQ(TEST_G, out.color_g);
+    EXPECT_EQ(TEST_B, out.color_b);
+    EXPECT_EQ(TEST_A, out.color_a);
+    EXPECT_STREQ(TEST_FILE_NAME, out.font_file.c_str());
+
+    EXPECT_TRUE(parse_text_field(TEST_XCENT_YVAL, &out));
+    EXPECT_EQ(CENTER_VAL, out.pos_x);
+    EXPECT_EQ(TEST_Y, out.pos_y);
+    EXPECT_EQ(TEST_R, out.color_r);
+    EXPECT_EQ(TEST_G, out.color_g);
+    EXPECT_EQ(TEST_B, out.color_b);
+    EXPECT_EQ(TEST_A, out.color_a);
+    EXPECT_STREQ(TEST_FILE_NAME, out.font_file.c_str());
+
+    EXPECT_TRUE(parse_text_field(TEST_XVAL_YCENT, &out));
+    EXPECT_EQ(TEST_X, out.pos_x);
+    EXPECT_EQ(CENTER_VAL, out.pos_y);
+    EXPECT_EQ(TEST_R, out.color_r);
+    EXPECT_EQ(TEST_G, out.color_g);
+    EXPECT_EQ(TEST_B, out.color_b);
+    EXPECT_EQ(TEST_A, out.color_a);
+    EXPECT_STREQ(TEST_FILE_NAME, out.font_file.c_str());
+
+    EXPECT_TRUE(parse_text_field(TEST_XVAL_YVAL, &out));
+    EXPECT_EQ(TEST_X, out.pos_x);
+    EXPECT_EQ(TEST_Y, out.pos_y);
+    EXPECT_EQ(TEST_R, out.color_r);
+    EXPECT_EQ(TEST_G, out.color_g);
+    EXPECT_EQ(TEST_B, out.color_b);
+    EXPECT_EQ(TEST_A, out.color_a);
+    EXPECT_STREQ(TEST_FILE_NAME, out.font_file.c_str());
+
+    EXPECT_FALSE(parse_text_field(TEST_BAD_MISSING, &out));
+    EXPECT_FALSE(parse_text_field(TEST_BAD_NO_FILE, &out));
+}
+
+TEST(AnimationParserTest, Test_parse_animation_desc_basic) {
+    static const char TEST_ANIMATION[] = R"desc(
+        # Basic animation
+        animation: 5 1 test/animation_file
+        frame: 1000 0 100
+    )desc";
+    animation anim;
+
+    EXPECT_TRUE(parse_animation_desc(TEST_ANIMATION, &anim));
+}
+
+TEST(AnimationParserTest, Test_parse_animation_desc_bad_no_animation_line) {
+    static const char TEST_ANIMATION[] = R"desc(
+        # Bad animation
+        frame: 1000 90  10
+    )desc";
+    animation anim;
+
+    EXPECT_FALSE(parse_animation_desc(TEST_ANIMATION, &anim));
+}
+
+TEST(AnimationParserTest, Test_parse_animation_desc_bad_no_frame) {
+    static const char TEST_ANIMATION[] = R"desc(
+        # Bad animation
+        animation: 5 1 test/animation_file
+    )desc";
+    animation anim;
+
+    EXPECT_FALSE(parse_animation_desc(TEST_ANIMATION, &anim));
+}
+
+TEST(AnimationParserTest, Test_parse_animation_desc_bad_animation_line_format) {
+    static const char TEST_ANIMATION[] = R"desc(
+        # Bad animation
+        animation: 5 1
+        frame: 1000 90  10
+    )desc";
+    animation anim;
+
+    EXPECT_FALSE(parse_animation_desc(TEST_ANIMATION, &anim));
+}
+
+TEST(AnimationParserTest, Test_parse_animation_desc_full) {
+    static const char TEST_ANIMATION[] = R"desc(
+        # Full animation
+        animation: 5 1 test/animation_file
+        clock_display:    11 12 13 14 15 16 test/time_font
+        percent_display:  21 22 23 24 25 26 test/percent_font
+
+        frame: 10 20 30
+        frame: 40 50 60
+    )desc";
+    animation anim;
+
+    EXPECT_TRUE(parse_animation_desc(TEST_ANIMATION, &anim));
+
+    EXPECT_EQ(5, anim.num_cycles);
+    EXPECT_EQ(1, anim.first_frame_repeats);
+    EXPECT_STREQ("test/animation_file", anim.animation_file.c_str());
+
+    EXPECT_EQ(11, anim.text_clock.pos_x);
+    EXPECT_EQ(12, anim.text_clock.pos_y);
+    EXPECT_EQ(13, anim.text_clock.color_r);
+    EXPECT_EQ(14, anim.text_clock.color_g);
+    EXPECT_EQ(15, anim.text_clock.color_b);
+    EXPECT_EQ(16, anim.text_clock.color_a);
+    EXPECT_STREQ("test/time_font", anim.text_clock.font_file.c_str());
+
+    EXPECT_EQ(21, anim.text_percent.pos_x);
+    EXPECT_EQ(22, anim.text_percent.pos_y);
+    EXPECT_EQ(23, anim.text_percent.color_r);
+    EXPECT_EQ(24, anim.text_percent.color_g);
+    EXPECT_EQ(25, anim.text_percent.color_b);
+    EXPECT_EQ(26, anim.text_percent.color_a);
+    EXPECT_STREQ("test/percent_font", anim.text_percent.font_file.c_str());
+
+    EXPECT_EQ(2, anim.num_frames);
+
+    EXPECT_EQ(10, anim.frames[0].disp_time);
+    EXPECT_EQ(20, anim.frames[0].min_level);
+    EXPECT_EQ(30, anim.frames[0].max_level);
+
+    EXPECT_EQ(40, anim.frames[1].disp_time);
+    EXPECT_EQ(50, anim.frames[1].min_level);
+    EXPECT_EQ(60, anim.frames[1].max_level);
+}
diff --git a/include/cutils/files.h b/include/cutils/android_get_control_file.h
similarity index 87%
rename from include/cutils/files.h
rename to include/cutils/android_get_control_file.h
index 0210e30..ed8fbf8 100644
--- a/include/cutils/files.h
+++ b/include/cutils/android_get_control_file.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H
+#define __CUTILS_ANDROID_GET_CONTROL_FILE_H
 
 #define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
 
@@ -34,4 +34,4 @@
 }
 #endif
 
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
index 7e7f815..4f23776 100644
--- a/include/cutils/multiuser.h
+++ b/include/cutils/multiuser.h
@@ -23,19 +23,19 @@
 extern "C" {
 #endif
 
-// NOTE: keep in sync with android.os.UserId
-
-#define MULTIUSER_APP_PER_USER_RANGE 100000
-#define MULTIUSER_FIRST_SHARED_APPLICATION_GID 50000
-#define MULTIUSER_FIRST_APPLICATION_UID 10000
-
 typedef uid_t userid_t;
 typedef uid_t appid_t;
 
 extern userid_t multiuser_get_user_id(uid_t uid);
 extern appid_t multiuser_get_app_id(uid_t uid);
-extern uid_t multiuser_get_uid(userid_t userId, appid_t appId);
-extern appid_t multiuser_get_shared_app_gid(uid_t uid);
+
+extern uid_t multiuser_get_uid(userid_t user_id, appid_t app_id);
+
+extern gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id);
+extern gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id);
+
+/* TODO: switch callers over to multiuser_get_shared_gid() */
+extern gid_t multiuser_get_shared_app_gid(uid_t uid);
 
 #ifdef __cplusplus
 }
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 4626e7a..d724dd6 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -35,6 +35,7 @@
 #else
 
 #include <sys/socket.h>
+#include <netinet/in.h>
 
 typedef int cutils_socket_t;
 #define INVALID_SOCKET (-1)
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index dc3833f..fcbdc9b 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -70,7 +70,9 @@
 #define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
 #define ATRACE_TAG_SYSTEM_SERVER    (1<<19)
 #define ATRACE_TAG_DATABASE         (1<<20)
-#define ATRACE_TAG_LAST             ATRACE_TAG_DATABASE
+#define ATRACE_TAG_NETWORK          (1<<21)
+#define ATRACE_TAG_ADB              (1<<22)
+#define ATRACE_TAG_LAST             ATRACE_TAG_ADB
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/include/log/log.h b/include/log/log.h
index a44aba8..d6f0eb5 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -27,15 +27,8 @@
 #include <time.h>    /* clock_gettime */
 #include <unistd.h>
 
-#include <log/uio.h> /* helper to define iovec for portability */
-
-#if (defined(__cplusplus) && defined(_USING_LIBCXX))
-extern "C++" {
-#include <string>
-}
-#endif
-
 #include <android/log.h>
+#include <log/uio.h> /* helper to define iovec for portability */
 
 #ifdef __cplusplus
 extern "C" {
@@ -774,207 +767,6 @@
 
 /* --------------------------------------------------------------------- */
 
-#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-#ifndef __ANDROID_API__
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#elif __ANDROID_API__ > 23 /* > Marshmallow */
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
-#else
-#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
-#endif
-#endif
-
-#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-#ifndef __android_log_context_defined
-#define __android_log_context_defined
-typedef struct android_log_context_internal* android_log_context;
-#endif
-
-/*
- * Elements returned when reading a list of events.
- */
-#ifndef __android_log_list_element_defined
-#define __android_log_list_element_defined
-typedef struct {
-    AndroidEventLogType type;
-    uint16_t complete;
-    uint16_t len;
-    union {
-        int32_t int32;
-        int64_t int64;
-        char* string;
-        float float32;
-    } data;
-} android_log_list_element;
-#endif
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- *     elements, we will manufacturer a list to embrace it for your API
- *     convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx,
-                                  const char* value, size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char* msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-#ifndef __class_android_log_event_context
-#define __class_android_log_event_context
-/* android_log_context C++ helpers */
-extern "C++" {
-class android_log_event_context {
-    android_log_context ctx;
-    int ret;
-
-    android_log_event_context(const android_log_event_context&) = delete;
-    void operator =(const android_log_event_context&) = delete;
-
-public:
-    explicit android_log_event_context(int tag) : ret(0) {
-        ctx = create_android_logger(static_cast<uint32_t>(tag));
-    }
-    explicit android_log_event_context(log_msg& log_msg) : ret(0) {
-        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
-                                        log_msg.entry.len - sizeof(uint32_t));
-    }
-    ~android_log_event_context() { android_log_destroy(&ctx); }
-
-    int close() {
-        int retval = android_log_destroy(&ctx);
-        if (retval < 0) ret = retval;
-        return retval;
-    }
-
-    /* To allow above C calls to use this class as parameter */
-    operator android_log_context() const { return ctx; }
-
-    int status() const { return ret; }
-
-    int begin() {
-        int retval = android_log_write_list_begin(ctx);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-    int end() {
-        int retval = android_log_write_list_end(ctx);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-
-    android_log_event_context& operator <<(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(uint32_t value) {
-        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(uint64_t value) {
-        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-    android_log_event_context& operator <<(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-#if defined(_USING_LIBCXX)
-    android_log_event_context& operator <<(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx,
-                                                   value.data(),
-                                                   value.length());
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-#endif
-    android_log_event_context& operator <<(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) ret = retval;
-        return *this;
-    }
-
-    int write(log_id_t id = LOG_ID_EVENTS) {
-        int retval = android_log_write_list(ctx, id);
-        if (retval < 0) ret = retval;
-        return ret;
-    }
-
-    int operator <<(log_id_t id) {
-        int retval = android_log_write_list(ctx, id);
-        if (retval < 0) ret = retval;
-        android_log_destroy(&ctx);
-        return ret;
-    }
-
-    /*
-     * Append should be a lesser-used interface, but adds
-     * access to string with length. So we offer all types.
-     */
-    template <typename Tvalue>
-    bool Append(Tvalue value) { *this << value; return ret >= 0; }
-
-    bool Append(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) ret = retval;
-        return ret >= 0;
-    }
-
-    android_log_list_element read() { return android_log_read_next(ctx); }
-    android_log_list_element peek() { return android_log_peek_next(ctx); }
-
-};
-}
-#endif
-#endif
-
-#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
-
-/* --------------------------------------------------------------------- */
-
 #ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
 #ifndef __ANDROID_API__
 #define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
diff --git a/include/log/log_event_list.h b/include/log/log_event_list.h
new file mode 100644
index 0000000..31d49b2
--- /dev/null
+++ b/include/log/log_event_list.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2005-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_LOG_EVENT_LIST_H
+#define _LIBS_LOG_EVENT_LIST_H
+
+#include <stdint.h>
+
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+#ifndef __android_log_context_defined
+#define __android_log_context_defined
+typedef struct android_log_context_internal* android_log_context;
+#endif
+
+/*
+ * Elements returned when reading a list of events.
+ */
+#ifndef __android_log_list_element_defined
+#define __android_log_list_element_defined
+typedef struct {
+    AndroidEventLogType type;
+    uint16_t complete;
+    uint16_t len;
+    union {
+        int32_t int32;
+        int64_t int64;
+        char* string;
+        float float32;
+    } data;
+} android_log_list_element;
+#endif
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ *     elements, we will manufacturer a list to embrace it for your API
+ *     convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char* value);
+int android_log_write_string8_len(android_log_context ctx,
+                                  const char* value, size_t maxlen);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char* msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context* ctx);
+
+#ifdef __cplusplus
+#ifndef __class_android_log_event_list_defined
+#define __class_android_log_event_list_defined
+/* android_log_list C++ helpers */
+extern "C++" {
+class android_log_event_list {
+friend class __android_log_event_list;
+
+private:
+    android_log_context ctx;
+    int ret;
+
+    android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const android_log_event_list&) = delete;
+
+public:
+    explicit android_log_event_list(int tag) : ret(0) {
+        ctx = create_android_logger(static_cast<uint32_t>(tag));
+    }
+    explicit android_log_event_list(log_msg& log_msg) : ret(0) {
+        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+                                        log_msg.entry.len - sizeof(uint32_t));
+    }
+    ~android_log_event_list() { android_log_destroy(&ctx); }
+
+    int close() {
+        int retval = android_log_destroy(&ctx);
+        if (retval < 0) ret = retval;
+        return retval;
+    }
+
+    /* To allow above C calls to use this class as parameter */
+    operator android_log_context() const { return ctx; }
+
+    int status() const { return ret; }
+
+    int begin() {
+        int retval = android_log_write_list_begin(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+    int end() {
+        int retval = android_log_write_list_end(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    android_log_event_list& operator <<(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint32_t value) {
+        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint64_t value) {
+        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+#if defined(_USING_LIBCXX)
+    android_log_event_list& operator <<(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+#endif
+
+    android_log_event_list& operator <<(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    int write(log_id_t id = LOG_ID_EVENTS) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    int operator <<(log_id_t id) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        android_log_destroy(&ctx);
+        return ret;
+    }
+
+    /*
+     * Append<Type> methods removes any integer promotion
+     * confusion, and adds access to string with length.
+     * Append methods are also added for all types for
+     * convenience.
+     */
+
+    bool AppendInt(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendLong(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+#if defined(_USING_LIBCXX)
+    bool AppendString(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    bool Append(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+#endif
+
+    bool AppendFloat(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    template <typename Tvalue>
+    bool Append(Tvalue value) { *this << value; return ret >= 0; }
+
+    bool Append(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    android_log_list_element read() { return android_log_read_next(ctx); }
+    android_log_list_element peek() { return android_log_peek_next(ctx); }
+
+};
+}
+#endif
+#endif
+
+#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index c364317..f7cf9b8 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -19,6 +19,33 @@
 ** by the device side of adb.
 */
 
+/*
+ * This file is consumed by build/tools/fs_config and is used
+ * for generating various files. Anything #define AID_<name>
+ * becomes the mapping for getpwnam/getpwuid, etc. The <name>
+ * field is lowercased.
+ * For example:
+ * #define AID_FOO_BAR 6666 becomes a friendly name of "foo_bar"
+ *
+ * The above holds true with the exception of:
+ *   mediacodec
+ *   mediaex
+ *   mediadrm
+ * Whose friendly names do not match the #define statements.
+ *
+ * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END
+ * can be used to define reserved OEM ranges used for sanity checks
+ * during the build process. The rules are, they must end with START/END
+ * The proper convention is incrementing a number like so:
+ * AID_OEM_RESERVED_START
+ * AID_OEM_RESERVED_1_START
+ * AID_OEM_RESERVED_2_START
+ * ...
+ * The same applies to the END.
+ * They are not required to be in order, but must not overlap each other and
+ * must define a START and END'ing range. START must be smaller than END.
+ */
+
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
 #define _ANDROID_FILESYSTEM_CONFIG_H_
 
@@ -96,6 +123,9 @@
 #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 */
+#define AID_MEDIA_AUDIO   1055 /* GID for audio files on internal media storage */
+#define AID_MEDIA_VIDEO   1056 /* GID for video files on internal media storage */
+#define AID_MEDIA_IMAGE   1057 /* GID for image files on internal media storage */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
@@ -127,15 +157,21 @@
 #define AID_MISC          9998  /* access to misc storage */
 #define AID_NOBODY        9999
 
-#define AID_APP          10000  /* first app user */
+#define AID_APP              10000 /* TODO: switch users over to AID_APP_START */
+#define AID_APP_START        10000 /* first app user */
+#define AID_APP_END          19999 /* last app user */
 
-#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
-#define AID_ISOLATED_END   99999 /* end of uids for fully isolated sandboxed processes */
-
-#define AID_USER        100000  /* offset for uid ranges for each user */
+#define AID_CACHE_GID_START  20000 /* start of gids for apps to mark cached data */
+#define AID_CACHE_GID_END    29999 /* end of gids for apps to mark cached data */
 
 #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
-#define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */
+#define AID_SHARED_GID_END   59999 /* end of gids for apps in each user to share */
+
+#define AID_ISOLATED_START   99000 /* start of uids for fully isolated sandboxed processes */
+#define AID_ISOLATED_END     99999 /* end of uids for fully isolated sandboxed processes */
+
+#define AID_USER            100000 /* TODO: switch users over to AID_USER_OFFSET */
+#define AID_USER_OFFSET     100000 /* offset for uid ranges for each user */
 
 #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
 /*
@@ -210,6 +246,9 @@
     { "dns_tether",    AID_DNS_TETHER, },
     { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
     { "vehicle_network", AID_VEHICLE_NETWORK, },
+    { "media_audio",   AID_MEDIA_AUDIO, },
+    { "media_video",   AID_MEDIA_VIDEO, },
+    { "media_image",   AID_MEDIA_IMAGE, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index f3c6cf7..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -25,6 +25,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log_event_list.h>
 #include <log/log.h>
 
 #define LOGGER_MAGIC 'l'
@@ -146,6 +153,40 @@
 unsigned long __android_logger_get_buffer_size(log_id_t logId);
 bool __android_logger_valid_buffer_size(unsigned long value);
 
+/* Retrieve the composed event buffer */
+int android_log_write_list_buffer(android_log_context ctx, const char** msg);
+
+#ifdef __cplusplus
+#ifdef __class_android_log_event_list_defined
+#ifndef __class_android_log_event_list_private_defined
+#define __class_android_log_event_list_private_defined
+/* android_log_context C++ helpers */
+extern "C++" {
+class __android_log_event_list : public android_log_event_list {
+    __android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const __android_log_event_list&) = delete;
+
+public:
+    explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
+    explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+
+#if defined(_USING_LIBCXX)
+    operator std::string() {
+        if (ret) return std::string("");
+        const char* cp = NULL;
+        ssize_t len = android_log_write_list_buffer(ctx, &cp);
+        if (len < 0) ret = len;
+        if (!cp || (len <= 0)) return std::string("");
+        return std::string(cp, len);
+    }
+#endif
+
+};
+}
+#endif
+#endif
+#endif
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/system/window.h b/include/system/window.h
index 49ab4dc..f439705 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -287,6 +287,16 @@
      * age will be 0.
      */
     NATIVE_WINDOW_BUFFER_AGE = 13,
+
+    /*
+     * Returns the duration of the last dequeueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
+
+    /*
+     * Returns the duration of the last queueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -323,6 +333,7 @@
     NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
     NATIVE_WINDOW_SET_SHARED_BUFFER_MODE    = 21,
     NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
+    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 23,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -985,6 +996,18 @@
     return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
 }
 
+static inline int native_window_get_frame_timestamps(
+        struct ANativeWindow* window, uint32_t framesAgo,
+        int64_t* outPostedTime, int64_t* outAcquireTime,
+        int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime,
+        int64_t* outDisplayRetireTime, int64_t* outReleaseTime)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
+            framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+}
+
+
 __END_DECLS
 
 #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index 18049cd..2137069 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -32,6 +32,7 @@
     int mCommandCount;
     bool mWithSeq;
     FrameworkCommandCollection *mCommands;
+    bool mSkipToNextNullByte;
 
 public:
     FrameworkListener(const char *socketName);
diff --git a/include/utils/FastStrcmp.h b/include/utils/FastStrcmp.h
new file mode 100644
index 0000000..3844e7d
--- /dev/null
+++ b/include/utils/FastStrcmp.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014-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_UTILS_FASTSTRCMP_H__
+#define _ANDROID_UTILS_FASTSTRCMP_H__
+
+#ifdef __cplusplus
+
+// Optimized for instruction cache locality
+//
+// Template class fastcmp used to create more time-efficient str*cmp
+// functions by pre-checking the first character before resorting
+// to calling the underlying string function.  Profiled with a
+// measurable speedup when used in hot code.  Usage is of the form:
+//
+//  fastcmp<strncmp>(str1, str2, len)
+//
+// NB: Does not work for the case insensitive str*cmp functions.
+// NB: Returns boolean, do not use if expecting to check negative value.
+//     Thus not semantically identical to the expected function behavior.
+
+template <int (*cmp)(const char *l, const char *r, const size_t s)>
+static inline int fastcmp(const char *l, const char *r, const size_t s) {
+    return (*l != *r) || cmp(l + 1, r + 1, s - 1);
+}
+
+template <int (*cmp)(const void *l, const void *r, const size_t s)>
+static inline int fastcmp(const void *lv, const void *rv, const size_t s) {
+    const char *l = static_cast<const char *>(lv);
+    const char *r = static_cast<const char *>(rv);
+    return (*l != *r) || cmp(l + 1, r + 1, s - 1);
+}
+
+template <int (*cmp)(const char *l, const char *r)>
+static inline int fastcmp(const char *l, const char *r) {
+    return (*l != *r) || cmp(l + 1, r + 1);
+}
+
+#endif
+
+#endif // _ANDROID_UTILS_FASTSTRCMP_H__
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index 8c4683c..d106185 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -64,13 +64,18 @@
     status_t    tryLock();
 
 #if defined(__ANDROID__)
-    // lock the mutex, but don't wait longer than timeoutMilliseconds.
+    // Lock the mutex, but don't wait longer than timeoutNs (relative time).
     // Returns 0 on success, TIMED_OUT for failure due to timeout expiration.
     //
     // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep
     // capabilities consistent across host OSes, this method is only available
     // when building Android binaries.
-    status_t    timedLock(nsecs_t timeoutMilliseconds);
+    //
+    // FIXME?: pthread_mutex_timedlock is based on CLOCK_REALTIME,
+    // which is subject to NTP adjustments, and includes time during suspend,
+    // so a timeout may occur even though no processes could run.
+    // Not holding a partial wakelock may lead to a system suspend.
+    status_t    timedLock(nsecs_t timeoutNs);
 #endif
 
     // Manages the mutex automatically. It'll be locked when Autolock is
@@ -134,6 +139,7 @@
 }
 #if defined(__ANDROID__)
 inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
+    timeoutNs += systemTime(SYSTEM_TIME_REALTIME);
     const struct timespec ts = {
         /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
         /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 6ba68f6..eeba40d 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -33,10 +33,10 @@
 
 // See <cutils/trace.h> for more ATRACE_* macros.
 
-// ATRACE_NAME traces the beginning and end of the current scope.  To trace
-// the correct start and end times this macro should be declared first in the
-// scope body.
-#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name)
+// ATRACE_NAME traces from its location until the end of its enclosing scope.
+#define _PASTE(x, y) x ## y
+#define PASTE(x, y) _PASTE(x,y)
+#define ATRACE_NAME(name) android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name)
 // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
 #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
 
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index fc845a4..54946fc 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -195,7 +195,8 @@
  * Uncompress and write an entry to an open file identified by |fd|.
  * |entry->uncompressed_length| bytes will be written to the file at
  * its current offset, and the file will be truncated at the end of
- * the uncompressed data.
+ * the uncompressed data (no truncation if |fd| references a block
+ * device).
  *
  * Returns 0 on success and negative values on failure.
  */
diff --git a/init/Android.mk b/init/Android.mk
index 442a5f3..ecdf5db 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -126,7 +126,6 @@
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
     libbase \
-    libselinux \
 
 LOCAL_STATIC_LIBRARIES := libinit
 LOCAL_SANITIZE := integer
diff --git a/init/action.cpp b/init/action.cpp
index a12f225..65bf292 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,7 +121,7 @@
     Timer t;
     int result = command.InvokeFunc();
 
-    double duration_ms = t.duration() * 1000;
+    double duration_ms = t.duration_s() * 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) {
@@ -154,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";
@@ -183,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 8fb55f0..7a8a3d5 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -34,29 +34,25 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 
-#define LOG_ROOT        "/data/bootchart"
-#define LOG_STAT        LOG_ROOT"/proc_stat.log"
-#define LOG_PROCS       LOG_ROOT"/proc_ps.log"
-#define LOG_DISK        LOG_ROOT"/proc_diskstats.log"
-#define LOG_HEADER      LOG_ROOT"/header"
-#define LOG_ACCT        LOG_ROOT"/kernel_pacct"
+using android::base::StringPrintf;
 
-#define LOG_STARTFILE   LOG_ROOT"/start"
-#define LOG_STOPFILE    LOG_ROOT"/stop"
+static constexpr const char* LOG_STAT = "/data/bootchart/proc_stat.log";
+static constexpr const char* LOG_PROC = "/data/bootchart/proc_ps.log";
+static constexpr const char* LOG_DISK = "/data/bootchart/proc_diskstats.log";
+static constexpr const char* LOG_HEADER = "/data/bootchart/header";
 
 // Polling period in ms.
-static const int BOOTCHART_POLLING_MS = 200;
-
-// Max polling time in seconds.
-static const int BOOTCHART_MAX_TIME_SEC = 10*60;
+static constexpr int BOOTCHART_POLLING_MS = 200;
 
 static long long g_last_bootchart_time;
-static int g_remaining_samples;
 
-static FILE* log_stat;
-static FILE* log_procs;
-static FILE* log_disks;
+static bool g_bootcharting = false;
+
+static FILE* g_stat_log;
+static FILE* g_proc_log;
+static FILE* g_disk_log;
 
 static long long get_uptime_jiffies() {
     std::string uptime;
@@ -99,12 +95,12 @@
     fclose(out);
 }
 
-static void do_log_uptime(FILE* log) {
+static void log_uptime(FILE* log) {
     fprintf(log, "%lld\n", get_uptime_jiffies());
 }
 
-static void do_log_file(FILE* log, const char* procfile) {
-    do_log_uptime(log);
+static void log_file(FILE* log, const char* procfile) {
+    log_uptime(log);
 
     std::string content;
     if (android::base::ReadFileToString(procfile, &content)) {
@@ -112,161 +108,115 @@
     }
 }
 
-static void do_log_procs(FILE* log) {
-    do_log_uptime(log);
+static void log_processes() {
+    log_uptime(g_proc_log);
 
     std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
     struct dirent* entry;
     while ((entry = readdir(dir.get())) != NULL) {
         // Only match numeric values.
-        char* end;
-        int pid = strtol(entry->d_name, &end, 10);
-        if (end != NULL && end > entry->d_name && *end == 0) {
-            char filename[32];
+        int pid = atoi(entry->d_name);
+        if (pid == 0) continue;
 
-            // /proc/<pid>/stat only has truncated task names, so get the full
-            // name from /proc/<pid>/cmdline.
-            snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
-            std::string cmdline;
-            android::base::ReadFileToString(filename, &cmdline);
-            const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
-
-            // Read process stat line.
-            snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
-            std::string stat;
-            if (android::base::ReadFileToString(filename, &stat)) {
-                if (!cmdline.empty()) {
-                    // Substitute the process name with its real name.
-                    size_t open = stat.find('(');
-                    size_t close = stat.find_last_of(')');
-                    if (open != std::string::npos && close != std::string::npos) {
-                        stat.replace(open + 1, close - open - 1, full_name);
-                    }
-                }
-                fputs(stat.c_str(), log);
-            }
-        }
-    }
-
-    fputc('\n', log);
-}
-
-static int bootchart_init() {
-    int timeout = 0;
-
-    std::string start;
-    android::base::ReadFileToString(LOG_STARTFILE, &start);
-    if (!start.empty()) {
-        timeout = atoi(start.c_str());
-    } else {
-        // When running with emulator, androidboot.bootchart=<timeout>
-        // might be passed by as kernel parameters to specify the bootchart
-        // timeout. this is useful when using -wipe-data since the /data
-        // partition is fresh.
+        // /proc/<pid>/stat only has truncated task names, so get the full
+        // name from /proc/<pid>/cmdline.
         std::string cmdline;
-        const char* s;
-        android::base::ReadFileToString("/proc/cmdline", &cmdline);
-#define KERNEL_OPTION  "androidboot.bootchart="
-        if ((s = strstr(cmdline.c_str(), KERNEL_OPTION)) != NULL) {
-            timeout = atoi(s + sizeof(KERNEL_OPTION) - 1);
+        android::base::ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline);
+        const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
+
+        // Read process stat line.
+        std::string stat;
+        if (android::base::ReadFileToString(StringPrintf("/proc/%d/stat", pid), &stat)) {
+            if (!cmdline.empty()) {
+                // Substitute the process name with its real name.
+                size_t open = stat.find('(');
+                size_t close = stat.find_last_of(')');
+                if (open != std::string::npos && close != std::string::npos) {
+                    stat.replace(open + 1, close - open - 1, full_name);
+                }
+            }
+            fputs(stat.c_str(), g_proc_log);
         }
     }
-    if (timeout == 0)
+
+    fputc('\n', g_proc_log);
+}
+
+static int do_bootchart_start() {
+    // We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
+    std::string start;
+    if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
+        LOG(VERBOSE) << "Not bootcharting";
         return 0;
+    }
 
-    if (timeout > BOOTCHART_MAX_TIME_SEC)
-        timeout = BOOTCHART_MAX_TIME_SEC;
-
-    int count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
-
-    log_stat = fopen(LOG_STAT, "we");
-    if (log_stat == NULL) {
+    // Open log files.
+    std::unique_ptr<FILE, decltype(&fclose)> stat_log(fopen(LOG_STAT, "we"), fclose);
+    if (!stat_log) {
+        PLOG(ERROR) << "Bootcharting couldn't open " << LOG_STAT;
         return -1;
     }
-    log_procs = fopen(LOG_PROCS, "we");
-    if (log_procs == NULL) {
-        fclose(log_stat);
+    std::unique_ptr<FILE, decltype(&fclose)> proc_log(fopen(LOG_PROC, "we"), fclose);
+    if (!proc_log) {
+        PLOG(ERROR) << "Bootcharting couldn't open " << LOG_PROC;
         return -1;
     }
-    log_disks = fopen(LOG_DISK, "we");
-    if (log_disks == NULL) {
-        fclose(log_stat);
-        fclose(log_procs);
+    std::unique_ptr<FILE, decltype(&fclose)> disk_log(fopen(LOG_DISK, "we"), fclose);
+    if (!disk_log) {
+        PLOG(ERROR) << "Bootcharting couldn't open " << LOG_DISK;
         return -1;
     }
 
-    // Create kernel process accounting file.
-    close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
-    acct(LOG_ACCT);
-
+    LOG(INFO) << "Bootcharting started";
+    g_stat_log = stat_log.release();
+    g_proc_log = proc_log.release();
+    g_disk_log = disk_log.release();
+    g_bootcharting = true;
     log_header();
-    return count;
-}
-
-int do_bootchart_init(const std::vector<std::string>& args) {
-    g_remaining_samples = bootchart_init();
-    if (g_remaining_samples < 0) {
-        PLOG(ERROR) << "Bootcharting initialization failed";
-    } else if (g_remaining_samples > 0) {
-        LOG(INFO) << "Bootcharting started (will run for "
-                  << ((g_remaining_samples * BOOTCHART_POLLING_MS) / 1000) << " s).";
-    } else {
-        LOG(VERBOSE) << "Not bootcharting.";
-    }
-    return 0;
-}
-
-static int bootchart_step() {
-    do_log_file(log_stat,   "/proc/stat");
-    do_log_file(log_disks,  "/proc/diskstats");
-    do_log_procs(log_procs);
-
-    // Stop if /data/bootchart/stop contains 1.
-    std::string stop;
-    if (android::base::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
-        return -1;
-    }
 
     return 0;
 }
 
-/* called to get time (in ms) used by bootchart */
-static long long bootchart_gettime() {
-    return 10LL*get_uptime_jiffies();
+static void do_bootchart_step() {
+    log_file(g_stat_log, "/proc/stat");
+    log_file(g_disk_log, "/proc/diskstats");
+    log_processes();
 }
 
-static void bootchart_finish() {
-    unlink(LOG_STOPFILE);
-    fclose(log_stat);
-    fclose(log_disks);
-    fclose(log_procs);
-    acct(NULL);
+static int do_bootchart_stop() {
+    if (!g_bootcharting) return 0;
+
     LOG(INFO) << "Bootcharting finished";
+    g_bootcharting = false;
+    fclose(g_stat_log);
+    fclose(g_disk_log);
+    fclose(g_proc_log);
+    return 0;
+}
+
+int do_bootchart(const std::vector<std::string>& args) {
+    if (args[1] == "start") return do_bootchart_start();
+    return do_bootchart_stop();
 }
 
 void bootchart_sample(int* timeout) {
     // Do we have any more bootcharting to do?
-    if (g_remaining_samples <= 0) {
-        return;
-    }
+    if (!g_bootcharting) return;
 
-    long long current_time = bootchart_gettime();
+    long long current_time = 10LL * get_uptime_jiffies();
     int elapsed_time = current_time - g_last_bootchart_time;
 
     if (elapsed_time >= BOOTCHART_POLLING_MS) {
-        // 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.
+
         g_last_bootchart_time = current_time;
-        if (bootchart_step() < 0 || g_remaining_samples <= 0) {
-            bootchart_finish();
-            g_remaining_samples = 0;
-        }
+        do_bootchart_step();
     }
-    if (g_remaining_samples > 0) {
+
+    // Schedule another?
+    if (g_bootcharting) {
         int remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
         if (*timeout < 0 || *timeout > remaining_time) {
             *timeout = remaining_time;
diff --git a/init/bootchart.h b/init/bootchart.h
index 47eda7a..1e8d0f8 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -20,7 +20,7 @@
 #include <string>
 #include <vector>
 
-int do_bootchart_init(const std::vector<std::string>& args);
+int do_bootchart(const std::vector<std::string>& args);
 void bootchart_sample(int* timeout);
 
 #endif /* _BOOTCHART_H */
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3e50f4d..812ac3c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -38,6 +38,9 @@
 #include <linux/loop.h>
 #include <linux/module.h>
 
+#include <thread>
+
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
@@ -65,10 +68,9 @@
 #include "util.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
-#define UNMOUNT_CHECK_MS 5000
 #define UNMOUNT_CHECK_TIMES 10
 
-static const int kTerminateServiceDelayMicroSeconds = 50000;
+static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
 
 static int insmod(const char *filename, const char *options, int flags) {
     int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
@@ -144,8 +146,7 @@
         LOG(ERROR) << "failed to set bootloader message: " << err;
         return -1;
     }
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (1) { pause(); }  // never reached
+    reboot("recovery");
 }
 
 static void unmount_and_fsck(const struct mntent *entry) {
@@ -192,11 +193,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. */
@@ -346,6 +345,11 @@
     return 0;
 }
 
+/* umount <path> */
+static int do_umount(const std::vector<std::string>& args) {
+  return umount(args[1].c_str());
+}
+
 static struct {
     const char *name;
     unsigned flag;
@@ -444,7 +448,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;
         }
@@ -555,7 +559,7 @@
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
         PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
-        ret = wipe_data_via_recovery("wipe_data_via_recovery");
+        ret = wipe_data_via_recovery("fs_mgr_mount_all");
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
@@ -590,9 +594,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;
@@ -727,7 +731,7 @@
         ServiceManager::GetInstance().ForEachService(
             [] (Service* s) { s->Terminate(); });
 
-        while (t.duration() < delay) {
+        while (t.duration_s() < delay) {
             ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
             int service_count = 0;
@@ -749,13 +753,12 @@
             }
 
             // 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";
+        LOG(VERBOSE) << "Terminating running services took " << t;
     }
 
-    return android_reboot_with_callback(cmd, 0, reboot_target,
-                                        callback_on_ro_remount);
+    return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount);
 }
 
 static int do_trigger(const std::vector<std::string>& args) {
@@ -905,21 +908,49 @@
 static int do_restorecon(const std::vector<std::string>& args) {
     int ret = 0;
 
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon(it->c_str()) < 0)
-            ret = -errno;
+    struct flag_type {const char* name; int value;};
+    static const flag_type flags[] = {
+        {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
+        {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
+        {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
+        {0, 0}
+    };
+
+    int flag = 0;
+
+    bool in_flags = true;
+    for (size_t i = 1; i < args.size(); ++i) {
+        if (android::base::StartsWith(args[i], "--")) {
+            if (!in_flags) {
+                LOG(ERROR) << "restorecon - flags must precede paths";
+                return -1;
+            }
+            bool found = false;
+            for (size_t j = 0; flags[j].name; ++j) {
+                if (args[i] == flags[j].name) {
+                    flag |= flags[j].value;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                LOG(ERROR) << "restorecon - bad flag " << args[i];
+                return -1;
+            }
+        } else {
+            in_flags = false;
+            if (restorecon(args[i].c_str(), flag) < 0) {
+                ret = -errno;
+            }
+        }
     }
     return ret;
 }
 
 static int do_restorecon_recursive(const std::vector<std::string>& args) {
-    int ret = 0;
-
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon_recursive(it->c_str()) < 0)
-            ret = -errno;
-    }
-    return ret;
+    std::vector<std::string> non_const_args(args);
+    non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
+    return do_restorecon(non_const_args);
 }
 
 static int do_loglevel(const std::vector<std::string>& args) {
@@ -956,11 +987,11 @@
 
 static int do_wait(const std::vector<std::string>& args) {
     if (args.size() == 2) {
-        return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
+        return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
     } else if (args.size() == 3) {
         int timeout;
         if (android::base::ParseInt(args[2], &timeout)) {
-            return wait_for_file(args[1].c_str(), timeout);
+            return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
         }
     }
     return -1;
@@ -997,7 +1028,7 @@
 BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
     static const Map builtin_functions = {
-        {"bootchart_init",          {0,     0,    do_bootchart_init}},
+        {"bootchart",               {1,     1,    do_bootchart}},
         {"chmod",                   {2,     2,    do_chmod}},
         {"chown",                   {2,     3,    do_chown}},
         {"class_reset",             {1,     1,    do_class_reset}},
@@ -1019,6 +1050,7 @@
         {"mkdir",                   {1,     4,    do_mkdir}},
         {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
+        {"umount",                  {1,     1,    do_umount}},
         {"powerctl",                {1,     1,    do_powerctl}},
         {"restart",                 {1,     1,    do_restart}},
         {"restorecon",              {1,     kMax, do_restorecon}},
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 4592adc..b8a9ec0 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -25,8 +25,7 @@
 
 #define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
 
-namespace {
-const std::map<std::string, int> cap_map = {
+static const std::map<std::string, int> cap_map = {
     CAP_MAP_ENTRY(CHOWN),
     CAP_MAP_ENTRY(DAC_OVERRIDE),
     CAP_MAP_ENTRY(DAC_READ_SEARCH),
@@ -69,9 +68,30 @@
 
 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)) {
+static bool ComputeCapAmbientSupported() {
+    return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) >= 0;
+}
+
+static unsigned int ComputeLastValidCap() {
+    // Android does not support kernels < 3.8. 'CAP_WAKE_ALARM' has been present since 3.0, see
+    // http://lxr.free-electrons.com/source/include/linux/capability.h?v=3.0#L360.
+    unsigned int last_valid_cap = CAP_WAKE_ALARM;
+    for (; prctl(PR_CAPBSET_READ, last_valid_cap, 0, 0, 0) >= 0; ++last_valid_cap);
+
+    // |last_valid_cap| will be the first failing value.
+    return last_valid_cap - 1;
+}
+
+static bool DropBoundingSet(const CapSet& to_keep) {
+    unsigned int last_valid_cap = GetLastValidCap();
+    // When dropping the bounding set, attempt to drop capabilities reported at
+    // run-time, not at compile-time.
+    // If the run-time kernel is older than the compile-time headers, this
+    // avoids dropping an invalid capability. If the run-time kernel is newer
+    // than the headers, this guarantees all capabilities (even those unknown at
+    // compile time) will be dropped.
+    for (size_t cap = 0; cap <= last_valid_cap; ++cap) {
+        if (cap < to_keep.size() && to_keep.test(cap)) {
             // No need to drop this capability.
             continue;
         }
@@ -83,14 +103,14 @@
     return true;
 }
 
-bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+static 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) {
+    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 ||
@@ -117,7 +137,7 @@
     return true;
 }
 
-bool SetAmbientCaps(const CapSet& to_raise) {
+static 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) {
@@ -129,8 +149,6 @@
     return true;
 }
 
-}  // namespace anonymous
-
 int LookupCap(const std::string& cap_name) {
     auto e = cap_map.find(cap_name);
     if (e != cap_map.end()) {
@@ -140,6 +158,16 @@
     }
 }
 
+bool CapAmbientSupported() {
+    static bool cap_ambient_supported = ComputeCapAmbientSupported();
+    return cap_ambient_supported;
+}
+
+unsigned int GetLastValidCap() {
+    static unsigned int last_valid_cap = ComputeLastValidCap();
+    return last_valid_cap;
+}
+
 bool SetCapsForExec(const CapSet& to_keep) {
     // Need to keep SETPCAP to drop bounding set below.
     bool add_setpcap = true;
diff --git a/init/capabilities.h b/init/capabilities.h
index 368178d..abd7fb2 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#ifndef _INIT_CAPABILITIES_H
+#define _INIT_CAPABILITIES_H
+
 #include <linux/capability.h>
 
 #include <bitset>
@@ -20,4 +23,8 @@
 using CapSet = std::bitset<CAP_LAST_CAP + 1>;
 
 int LookupCap(const std::string& cap_name);
+bool CapAmbientSupported();
+unsigned int GetLastValidCap();
 bool SetCapsForExec(const CapSet& to_keep);
+
+#endif  // _INIT_CAPABILITIES_H
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 10aae88..6e457cd 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -23,7 +23,8 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <cutils/files.h>
+#include <android-base/unique_fd.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
 #include "init.h"
@@ -89,14 +90,34 @@
 
 FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
                    gid_t gid, int perm, const std::string& context)
+        // defaults OK for uid,..., they are ignored for this class.
         : 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());
+int FileInfo::Create(const std::string&) const {
+  int flags = (type() == "r") ? O_RDONLY :
+              (type() == "w") ? O_WRONLY :
+                                O_RDWR;
+
+  // Make sure we do not block on open (eg: devices can chose to block on
+  // carrier detect).  Our intention is never to delay launch of a service
+  // for such a condition.  The service can perform its own blocking on
+  // carrier detect.
+  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name().c_str(),
+                                                      flags | O_NONBLOCK)));
+
+  if (fd < 0) {
+    PLOG(ERROR) << "Failed to open file '" << name().c_str() << "'";
+    return -1;
+  }
+
+  // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
+  fcntl(fd, F_SETFL, flags);
+
+  LOG(INFO) << "Opened file '" << name().c_str() << "'"
+            << ", flags " << std::oct << flags << std::dec;
+
+  return fd.release();
 }
 
 const std::string FileInfo::key() const {
diff --git a/init/devices.cpp b/init/devices.cpp
index 1a6912f..6af237c 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/sendfile.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -34,6 +35,7 @@
 #include <linux/netlink.h>
 
 #include <memory>
+#include <thread>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
@@ -109,13 +111,18 @@
         return -ENOMEM;
 
     node->dp.name = strdup(name);
-    if (!node->dp.name)
+    if (!node->dp.name) {
+        free(node);
         return -ENOMEM;
+    }
 
     if (attr) {
         node->dp.attr = strdup(attr);
-        if (!node->dp.attr)
+        if (!node->dp.attr) {
+            free(node->dp.name);
+            free(node);
             return -ENOMEM;
+        }
     }
 
     node->dp.perm = perm;
@@ -183,7 +190,7 @@
 
     if (access(path.c_str(), F_OK) == 0) {
         LOG(VERBOSE) << "restorecon_recursive: " << path;
-        restorecon_recursive(path.c_str());
+        restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
     }
 }
 
@@ -784,139 +791,87 @@
     }
 }
 
-static int load_firmware(int fw_fd, int loading_fd, int data_fd)
-{
-    struct stat st;
-    long len_to_copy;
-    int ret = 0;
+static void load_firmware(uevent* uevent, const std::string& root,
+                          int fw_fd, size_t fw_size,
+                          int loading_fd, int data_fd) {
+    // Start transfer.
+    android::base::WriteFully(loading_fd, "1", 1);
 
-    if(fstat(fw_fd, &st) < 0)
-        return -1;
-    len_to_copy = st.st_size;
-
-    write(loading_fd, "1", 1);  /* start transfer */
-
-    while (len_to_copy > 0) {
-        char buf[PAGE_SIZE];
-        ssize_t nr;
-
-        nr = read(fw_fd, buf, sizeof(buf));
-        if(!nr)
-            break;
-        if(nr < 0) {
-            ret = -1;
-            break;
-        }
-        if (!android::base::WriteFully(data_fd, buf, nr)) {
-            ret = -1;
-            break;
-        }
-        len_to_copy -= nr;
+    // Copy the firmware.
+    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
+    if (rc == -1) {
+        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
     }
 
-    if(!ret)
-        write(loading_fd, "0", 1);  /* successful end of transfer */
-    else
-        write(loading_fd, "-1", 2); /* abort transfer */
-
-    return ret;
+    // Tell the firmware whether to abort or commit.
+    const char* response = (rc != -1) ? "0" : "-1";
+    android::base::WriteFully(loading_fd, response, strlen(response));
 }
 
-static int is_booting(void)
-{
+static int is_booting() {
     return access("/dev/.booting", F_OK) == 0;
 }
 
-static void process_firmware_event(struct uevent *uevent)
-{
-    char *root, *loading, *data;
-    int l, loading_fd, data_fd, fw_fd;
-    size_t i;
+static void process_firmware_event(uevent* uevent) {
     int booting = is_booting();
 
     LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
 
-    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
-    if (l == -1)
+    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+    std::string loading = root + "/loading";
+    std::string data = root + "/data";
+
+    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
+    if (loading_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
         return;
+    }
 
-    l = asprintf(&loading, "%sloading", root);
-    if (l == -1)
-        goto root_free_out;
-
-    l = asprintf(&data, "%sdata", root);
-    if (l == -1)
-        goto loading_free_out;
-
-    loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
-    if(loading_fd < 0)
-        goto data_free_out;
-
-    data_fd = open(data, O_WRONLY|O_CLOEXEC);
-    if(data_fd < 0)
-        goto loading_close_out;
+    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
+    if (data_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
+        return;
+    }
 
 try_loading_again:
-    for (i = 0; i < arraysize(firmware_dirs); i++) {
-        char *file = NULL;
-        l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
-        if (l == -1)
-            goto data_free_out;
-        fw_fd = open(file, O_RDONLY|O_CLOEXEC);
-        free(file);
-        if (fw_fd >= 0) {
-            if (!load_firmware(fw_fd, loading_fd, data_fd)) {
-                LOG(INFO) << "firmware: copy success { '" << root << "', '" << uevent->firmware << "' }";
-            } else {
-                LOG(ERROR) << "firmware: copy failure { '" << root << "', '" << uevent->firmware << "' }";
-            }
-            break;
+    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
+        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
+        struct stat sb;
+        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
+            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
+            return;
         }
     }
-    if (fw_fd < 0) {
-        if (booting) {
-            /* If we're not fully booted, we may be missing
-             * filesystems needed for firmware, wait and retry.
-             */
-            usleep(100000);
-            booting = is_booting();
-            goto try_loading_again;
-        }
-        PLOG(ERROR) << "firmware: could not open '" << uevent->firmware << "'";
-        write(loading_fd, "-1", 2);
-        goto data_close_out;
-    }
 
-    close(fw_fd);
-data_close_out:
-    close(data_fd);
-loading_close_out:
-    close(loading_fd);
-data_free_out:
-    free(data);
-loading_free_out:
-    free(loading);
-root_free_out:
-    free(root);
+    if (booting) {
+        // If we're not fully booted, we may be missing
+        // filesystems needed for firmware, wait and retry.
+        std::this_thread::sleep_for(100ms);
+        booting = is_booting();
+        goto try_loading_again;
+    }
+
+    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
+
+    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
+    write(loading_fd, "-1", 2);
 }
 
-static void handle_firmware_event(struct uevent *uevent)
-{
-    pid_t pid;
+static void handle_firmware_event(uevent* uevent) {
+    if (strcmp(uevent->subsystem, "firmware")) return;
+    if (strcmp(uevent->action, "add")) return;
 
-    if(strcmp(uevent->subsystem, "firmware"))
-        return;
-
-    if(strcmp(uevent->action, "add"))
-        return;
-
-    /* we fork, to avoid making large memory allocations in init proper */
-    pid = fork();
-    if (!pid) {
+    // Loading the firmware in a child means we can do that in parallel...
+    // (We ignore SIGCHLD rather than wait for our children.)
+    pid_t pid = fork();
+    if (pid == 0) {
+        Timer t;
         process_firmware_event(uevent);
+        LOG(INFO) << "loading " << uevent->path << " took " << t;
         _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;
     }
 }
 
@@ -1088,10 +1043,9 @@
     coldboot("/sys/block");
     coldboot("/sys/devices");
     close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
-    LOG(INFO) << "Coldboot took " << t.duration() << "s.";
+    LOG(INFO) << "Coldboot took " << t;
 }
 
-int get_device_fd()
-{
+int get_device_fd() {
     return device_fd;
 }
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index d6082aa..c4ff6df 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -11,7 +11,7 @@
 LOGROOT=/data/bootchart
 TARBALL=bootchart.tgz
 
-FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
+FILES="header proc_stat.log proc_ps.log proc_diskstats.log"
 
 for f in $FILES; do
     adb "${@}" pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
diff --git a/init/init.cpp b/init/init.cpp
index 7c37d28..2d474c7 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -42,13 +43,13 @@
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/android_reboot.h>
 #include <cutils/fs.h>
 #include <cutils/iosched_policy.h>
 #include <cutils/list.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 
+#include <fstream>
 #include <memory>
 
 #include "action.h"
@@ -67,6 +68,8 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::StringPrintf;
+
 struct selabel_handle *sehandle;
 struct selabel_handle *sehandle_prop;
 
@@ -75,7 +78,7 @@
 static char qemu[32];
 
 std::string default_console = "/dev/console";
-static time_t process_needs_restart;
+static time_t process_needs_restart_at;
 
 const char *ENV[32];
 
@@ -132,11 +135,10 @@
 
 static void restart_processes()
 {
-    process_needs_restart = 0;
-    ServiceManager::GetInstance().
-        ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {
-                s->RestartIfNeeded(process_needs_restart);
-            });
+    process_needs_restart_at = 0;
+    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
+        s->RestartIfNeeded(&process_needs_restart_at);
+    });
 }
 
 void handle_control_message(const std::string& msg, const std::string& name) {
@@ -161,14 +163,21 @@
     Timer t;
 
     LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
-    // 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)) {
+
+    // Historically we had a 1s timeout here because we weren't otherwise
+    // tracking boot time, and many OEMs made their sepolicy regular
+    // expressions too expensive (http://b/19899875).
+
+    // Now we're tracking boot time, just log the time taken to a system
+    // property. We still panic if it takes more than a minute though,
+    // because any build that slow isn't likely to boot at all, and we'd
+    // rather any test lab devices fail back to the bootloader.
+    if (wait_for_file(COLDBOOT_DONE, 60s) < 0) {
         LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
+        panic();
     }
 
-    LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE " took " << t.duration() << "s.";
+    property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration_ns()).c_str());
     return 0;
 }
 
@@ -248,6 +257,108 @@
     return result;
 }
 
+static void security_failure() {
+    LOG(ERROR) << "Security failure...";
+    panic();
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+    std::string path;
+    if (compat) {
+        path = MMAP_RND_COMPAT_PATH;
+    } else {
+        path = MMAP_RND_PATH;
+    }
+    std::ifstream inf(path, std::fstream::in);
+    if (!inf) {
+        LOG(ERROR) << "Cannot open for reading: " << path;
+        return false;
+    }
+    while (start >= min) {
+        // try to write out new value
+        std::string str_val = std::to_string(start);
+        std::ofstream of(path, std::fstream::out);
+        if (!of) {
+            LOG(ERROR) << "Cannot open for writing: " << path;
+            return false;
+        }
+        of << str_val << std::endl;
+        of.close();
+
+        // check to make sure it was recorded
+        inf.seekg(0);
+        std::string str_rec;
+        inf >> str_rec;
+        if (str_val.compare(str_rec) == 0) {
+            break;
+        }
+        start--;
+    }
+    inf.close();
+    if (start < min) {
+        LOG(ERROR) << "Unable to set minimum required entropy " << min << " in " << path;
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Set /proc/sys/vm/mmap_rnd_bits and potentially
+ * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+ * Returns -1 if unable to set these to an acceptable value.
+ *
+ * To support this sysctl, the following upstream commits are needed:
+ *
+ * d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
+ * e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
+ * 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
+ * 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
+ * ec9ee4acd97c drivers: char: random: add get_random_long()
+ * 5ef11c35ce86 mm: ASLR: use get_random_long()
+ */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
+{
+    int ret = -1;
+
+    /* values are arch-dependent */
+#if defined(__aarch64__)
+    /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
+    if (set_mmap_rnd_bits_min(33, 24, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__x86_64__)
+    /* x86_64 supports 28 - 32 bits */
+    if (set_mmap_rnd_bits_min(32, 32, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__arm__) || defined(__i386__)
+    /* check to see if we're running on 64-bit kernel */
+    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+    /* supported 32-bit architecture must have 16 bits set */
+    if (set_mmap_rnd_bits_min(16, 16, h64)) {
+        ret = 0;
+    }
+#elif defined(__mips__) || defined(__mips64__)
+    // TODO: add mips support b/27788820
+    ret = 0;
+#else
+    LOG(ERROR) << "Unknown architecture";
+#endif
+
+    if (ret == -1) {
+        LOG(ERROR) << "Unable to set adequate mmap entropy value!";
+        security_failure();
+    }
+    return ret;
+}
+
 static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
@@ -268,15 +379,14 @@
 
     if (for_emulator) {
         // In the emulator, export any kernel option with the "ro.kernel." prefix.
-        property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
+        property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
         return;
     }
 
     if (key == "qemu") {
         strlcpy(qemu, value.c_str(), sizeof(qemu));
     } else if (android::base::StartsWith(key, "androidboot.")) {
-        property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
-                     value.c_str());
+        property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());
     }
 }
 
@@ -314,7 +424,7 @@
 static void process_kernel_dt() {
     static const char android_dir[] = "/proc/device-tree/firmware/android";
 
-    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+    std::string file_name = StringPrintf("%s/compatible", android_dir);
 
     std::string dt_file;
     android::base::ReadFileToString(file_name, &dt_file);
@@ -332,12 +442,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());
     }
 }
@@ -350,11 +460,17 @@
     if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
 }
 
+static int property_enable_triggers_action(const std::vector<std::string>& args)
+{
+    /* Enable property triggers. */
+    property_triggers_enabled = 1;
+    return 0;
+}
+
 static int queue_property_triggers_action(const std::vector<std::string>& args)
 {
+    ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
     ActionManager::GetInstance().QueueAllPropertyTriggers();
-    /* enable property triggers */
-    property_triggers_enabled = 1;
     return 0;
 }
 
@@ -401,12 +517,6 @@
     return 0;
 }
 
-static void security_failure() {
-    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (true) { pause(); }  // never reached
-}
-
 static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
@@ -436,8 +546,8 @@
             security_failure();
         }
 
-        LOG(INFO) << "(Initializing SELinux " << (is_enforcing ? "enforcing" : "non-enforcing")
-                  << " took " << t.duration() << "s.)";
+        // init's first stage can't set properties, so pass the time to the second stage.
+        setenv("INIT_SELINUX_TOOK", std::to_string(t.duration_ns()).c_str(), 1);
     } else {
         selinux_init_all_handles();
     }
@@ -566,12 +676,14 @@
         return watchdogd_main(argc, argv);
     }
 
+    boot_clock::time_point start_time = boot_clock::now();
+
     // Clear the umask.
     umask(0);
 
     add_environment("PATH", _PATH_DEFPATH);
 
-    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
 
     // Don't expose the raw commandline to unprivileged processes.
     chmod("/proc/cmdline", 0440);
@@ -590,38 +702,42 @@
         mount("sysfs", "/sys", "sysfs", 0, NULL);
         mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
         mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
+        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
     }
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
     // talk to the outside world...
     InitKernelLogging(argv);
 
-    if (is_first_stage) {
-        LOG(INFO) << "init first stage started!";
+    LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
 
+    if (is_first_stage) {
         // Mount devices defined in android.early.* kernel commandline
         early_mount();
 
-        // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+        // Set up SELinux, loading the SELinux policy.
         selinux_initialize(true);
 
-        // If we're in the kernel domain, re-exec init to transition to the init domain now
+        // We're in the kernel domain, so re-exec init to transition to the init domain now
         // that the SELinux policy has been loaded.
-
         if (restorecon("/init") == -1) {
             PLOG(ERROR) << "restorecon failed";
             security_failure();
         }
+
+        setenv("INIT_SECOND_STAGE", "true", 1);
+
+        uint64_t start_ns = start_time.time_since_epoch().count();
+        setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1);
+
         char* path = argv[0];
-        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+        char* args[] = { path, nullptr };
         if (execv(path, args) == -1) {
             PLOG(ERROR) << "execv(\"" << path << "\") failed";
             security_failure();
         }
-
     } else {
-        LOG(INFO) << "init second stage started!";
-
         // Indicate that booting is in progress to background fw loaders, etc.
         close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
@@ -636,7 +752,16 @@
         // used by init as well as the current required properties.
         export_kernel_boot_props();
 
-        // Now set up SELinux for second stage
+        // Make the time that init started available for bootstat to log.
+        property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
+        property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
+
+        // Clean up our environment.
+        unsetenv("INIT_SECOND_STAGE");
+        unsetenv("INIT_STARTED_AT");
+        unsetenv("INIT_SELINUX_TOOK");
+
+        // Now set up SELinux for second stage.
         selinux_initialize(false);
     }
 
@@ -647,10 +772,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);
@@ -683,6 +810,7 @@
     am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
@@ -710,21 +838,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 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;
-        }
+        // If there's more work to do, wake up again immediately.
+        if (am.HasMoreCommands()) epoll_timeout_ms = 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 d017390..406b339 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -110,7 +110,7 @@
     // Nexus 9 boot time, so it's disabled by default.
     if (false) DumpState();
 
-    LOG(VERBOSE) << "(Parsing " << path << " took " << t.duration() << "s.)";
+    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
     return true;
 }
 
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 1cfdd80..3dbb2f0 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -78,11 +78,13 @@
     if (adb_enabled == "running") {
         Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
-            LOG(INFO) << "Starting service " << svc->name() << " from keychord...";
+            LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
             svc->Start();
         } else {
-            LOG(ERROR) << "service for keychord " << id << " not found";
+            LOG(ERROR) << "Service for keychord " << id << " not found";
         }
+    } else {
+        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
     }
 }
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e7176c6..498a5a1 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>
 
@@ -168,62 +169,53 @@
     return true;
 }
 
-static int property_set_impl(const char* name, const char* value) {
+int property_set(const char* name, const char* value) {
     size_t valuelen = strlen(value);
 
-    if (!is_legal_property_name(name)) return -1;
-    if (valuelen >= PROP_VALUE_MAX) return -1;
+    if (!is_legal_property_name(name)) {
+        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
+        return -1;
+    }
+    if (valuelen >= PROP_VALUE_MAX) {
+        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
+                   << "value too long";
+        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;
         }
     }
 
     prop_info* pi = (prop_info*) __system_property_find(name);
-
-    if(pi != 0) {
-        /* ro.* properties may NEVER be modified once set */
-        if(!strncmp(name, "ro.", 3)) return -1;
+    if (pi != nullptr) {
+        // ro.* properties are actually "write-once".
+        if (!strncmp(name, "ro.", 3)) {
+            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
+                       << "property already set";
+            return -1;
+        }
 
         __system_property_update(pi, value, valuelen);
     } else {
         int rc = __system_property_add(name, strlen(name), value, valuelen);
         if (rc < 0) {
+            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
+                       << "__system_property_add failed";
             return rc;
         }
     }
-    /* If name starts with "net." treat as a DNS property. */
-    if (strncmp("net.", name, strlen("net.")) == 0)  {
-        if (strcmp("net.change", name) == 0) {
-            return 0;
-        }
-       /*
-        * The 'net.change' property is a special property used track when any
-        * 'net.*' property name is updated. It is _ONLY_ updated here. Its value
-        * contains the last updated 'net.*' property.
-        */
-        property_set("net.change", name);
-    } else if (persistent_properties_loaded &&
-            strncmp("persist.", name, strlen("persist.")) == 0) {
-        /*
-         * Don't write properties to disk until after we have read all default properties
-         * to prevent them from being overwritten by default values.
-         */
+
+    // Don't write properties to disk until after we have read all default
+    // properties to prevent them from being overwritten by default values.
+    if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) {
         write_persistent_property(name, value);
     }
     property_changed(name, value);
     return 0;
 }
 
-int property_set(const char* name, const char* value) {
-    int rc = property_set_impl(name, value);
-    if (rc == -1) {
-        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed";
-    }
-    return rc;
-}
-
 static void handle_property_set_fd()
 {
     prop_msg msg;
@@ -387,7 +379,7 @@
     }
     data.push_back('\n');
     load_properties(&data[0], filter);
-    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t.duration() << "s.)";
+    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
 }
 
 static void load_persistent_properties() {
diff --git a/init/readme.txt b/init/readme.txt
index 500b1d8..530b392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -148,13 +148,10 @@
   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().
+file <path> <type>
+  Open a file path and pass its fd to the launched process.  <type> must be
+  "r", "w" or "rw".  For native executables see libcutils
+  android_get_control_file().
 
 user <username>
   Change to 'username' before exec'ing this service.
@@ -256,9 +253,10 @@
 Commands
 --------
 
-bootchart_init
-   Start bootcharting if configured (see below).
-   This is included in the default init.rc.
+bootchart [start|stop]
+   Start/stop bootcharting. These are present in the default init.rc files,
+   but bootcharting is only active if the file /data/bootchart/enabled exists;
+   otherwise bootchart start/stop are no-ops.
 
 chmod <octal-mode> <path>
    Change file access permissions.
@@ -398,6 +396,9 @@
    Trigger an event.  Used to queue an action from another
    action.
 
+umount <path>
+   Unmount the filesystem mounted at that path.
+
 verity_load_state
    Internal implementation detail used to load dm-verity state.
 
@@ -441,7 +442,26 @@
 for via the below properties.
 
 init.svc.<name>
-   State of a named service ("stopped", "stopping", "running", "restarting")
+  State of a named service ("stopped", "stopping", "running", "restarting")
+
+
+Boot timing
+-----------
+Init records some boot timing information in system properties.
+
+ro.boottime.init
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first
+  stage of init started.
+
+ro.boottime.init.selinux
+  How long it took the first stage to initialize SELinux.
+
+ro.boottime.init.cold_boot_wait
+  How long init waited for ueventd's coldboot phase to end.
+
+ro.boottime.<service-name>
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was
+  first started.
 
 
 Bootcharting
@@ -452,19 +472,11 @@
 On the emulator, use the -bootchart <timeout> option to boot with bootcharting
 activated for <timeout> seconds.
 
-On a device, create /data/bootchart/start with a command like the following:
+On a device:
 
-  adb shell 'echo $TIMEOUT > /data/bootchart/start'
+  adb shell 'touch /data/bootchart/enabled'
 
-Where the value of $TIMEOUT corresponds to the desired bootcharted period in
-seconds. Bootcharting will stop after that many seconds have elapsed.
-You can also stop the bootcharting at any moment by doing the following:
-
-  adb shell 'echo 1 > /data/bootchart/stop'
-
-Note that /data/bootchart/stop is deleted automatically by init at the end of
-the bootcharting. This is not the case with /data/bootchart/start, so don't
-forget to delete it when you're done collecting data.
+Don't forget to delete this file when you're done collecting data!
 
 The log files are written to /data/bootchart/. A script is provided to
 retrieve them and create a bootchart.tgz file that can be used with the
@@ -537,10 +549,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 f093dd9..7cff348 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,7 @@
 #include "service.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <linux/securebits.h>
 #include <sched.h>
 #include <sys/mount.h>
@@ -35,7 +36,6 @@
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/android_reboot.h>
 #include <system/thread_defs.h>
 
 #include <processgroup/processgroup.h>
@@ -51,9 +51,6 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
-#define CRITICAL_CRASH_THRESHOLD    4       // if we crash >4 times ...
-#define CRITICAL_CRASH_WINDOW       (4*60)  // ... in 4 minutes, goto recovery
-
 static std::string ComputeContextFromExecutable(std::string& service_name,
                                                 const std::string& service_path) {
     std::string computed_context;
@@ -154,8 +151,8 @@
 
 Service::Service(const std::string& name, const std::string& classname,
                  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
-      time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
+    : name_(name), classname_(classname), flags_(0), pid_(0),
+      crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
       seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
       priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
@@ -168,7 +165,7 @@
                  const std::string& seclabel,
                  const std::vector<std::string>& args)
     : name_(name), classname_(classname), flags_(flags), pid_(0),
-      time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
+      crash_count_(0), uid_(uid), gid_(gid),
       supp_gids_(supp_gids), capabilities_(capabilities),
       namespace_flags_(namespace_flags), seclabel_(seclabel),
       ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
@@ -190,6 +187,12 @@
     }
 
     property_set(prop_name.c_str(), new_state.c_str());
+
+    if (new_state == "running") {
+        uint64_t start_ns = time_started_.time_since_epoch().count();
+        property_set(StringPrintf("ro.boottime.%s", name_.c_str()).c_str(),
+                     StringPrintf("%" PRIu64, start_ns).c_str());
+    }
 }
 
 void Service::KillProcessGroup(int signal) {
@@ -274,20 +277,17 @@
         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; "
-                           << "rebooting into recovery mode";
-                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-                return false;
+        if (now < time_crashed_ + 4min) {
+            if (++crash_count_ > 4) {
+                LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
+                panic();
             }
         } else {
             time_crashed_ = now;
-            nr_crashed_ = 1;
+            crash_count_ = 1;
         }
     }
 
@@ -312,13 +312,28 @@
 bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
     capabilities_ = 0;
 
+    if (!CapAmbientSupported()) {
+        *err = "capabilities requested but the kernel does not support ambient capabilities";
+        return false;
+    }
+
+    unsigned int last_valid_cap = GetLastValidCap();
+    if (last_valid_cap >= capabilities_.size()) {
+        LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
+    }
+
     for (size_t i = 1; i < args.size(); i++) {
         const std::string& arg = args[i];
-        int cap = LookupCap(arg);
-        if (cap == -1) {
+        int res = LookupCap(arg);
+        if (res < 0) {
             *err = StringPrintf("invalid capability '%s'", arg.c_str());
             return false;
         }
+        unsigned int cap = static_cast<unsigned int>(res);  // |res| is >= 0.
+        if (cap > last_valid_cap) {
+            *err = StringPrintf("capability '%s' not supported by the kernel", arg.c_str());
+            return false;
+        }
         capabilities_[cap] = true;
     }
     return true;
@@ -526,7 +541,7 @@
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
-        {"file",        {2,     6,    &Service::ParseFile}},
+        {"file",        {2,     2,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
@@ -553,7 +568,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
@@ -568,9 +582,9 @@
             console_ = default_console;
         }
 
-        bool have_console = (open(console_.c_str(), O_RDWR | O_CLOEXEC) != -1);
+        bool have_console = (access(console_.c_str(), R_OK | W_OK) != -1);
         if (!have_console) {
-            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
+            PLOG(ERROR) << "service '" << name_ << "' cannot gain read/write access to console '" << console_ << "'";
             flags_ |= SVC_DISABLED;
             return false;
         }
@@ -667,7 +681,7 @@
         }
     }
 
-    time_started_ = gettime();
+    time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
 
@@ -731,18 +745,19 @@
     } /* else: Service is restarting anyways. */
 }
 
-void Service::RestartIfNeeded(time_t& process_needs_restart) {
-    time_t next_start_time = time_started_ + 5;
-
-    if (next_start_time <= gettime()) {
+void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
+    boot_clock::time_point now = boot_clock::now();
+    boot_clock::time_point next_start = time_started_ + 5s;
+    if (now > next_start) {
         flags_ &= (~SVC_RESTARTING);
         Start();
         return;
     }
 
-    if ((next_start_time < process_needs_restart) ||
-        (process_needs_restart == 0)) {
-        process_needs_restart = next_start_time;
+    time_t next_start_time_t = time(nullptr) +
+        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
+    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
+        *process_needs_restart_at = next_start_time_t;
     }
 }
 
diff --git a/init/service.h b/init/service.h
index d9e8f57..013e65f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -30,6 +30,7 @@
 #include "descriptors.h"
 #include "init_parser.h"
 #include "keyword_map.h"
+#include "util.h"
 
 #define SVC_DISABLED       0x001  // do not autostart with class
 #define SVC_ONESHOT        0x002  // do not restart on exit
@@ -75,7 +76,7 @@
     void Stop();
     void Terminate();
     void Restart();
-    void RestartIfNeeded(time_t& process_needs_restart);
+    void RestartIfNeeded(time_t* process_needs_restart_at);
     bool Reap();
     void DumpState() const;
 
@@ -134,9 +135,9 @@
 
     unsigned flags_;
     pid_t pid_;
-    time_t time_started_;    // time of last start
-    time_t time_crashed_;    // first crash within inspection window
-    int nr_crashed_;         // number of times crashed within window
+    boot_clock::time_point time_started_; // time of last start
+    boot_clock::time_point time_crashed_; // first crash within inspection window
+    int crash_count_;                     // number of times crashed within window
 
     uid_t uid_;
     gid_t gid_;
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 0dea3e0..1041b82 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -24,7 +24,6 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <cutils/android_reboot.h>
 #include <cutils/list.h>
 #include <cutils/sockets.h>
 
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 ff46e4f..a79a419 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,11 +34,15 @@
 #include <sys/types.h>
 #include <sys/un.h>
 
+#include <thread>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+
+#include <cutils/android_reboot.h>
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
 
@@ -156,69 +160,6 @@
     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();
 
@@ -258,16 +199,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)
@@ -325,16 +261,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,
@@ -373,14 +308,9 @@
     return rc;
 }
 
-int restorecon(const char* pathname)
+int restorecon(const char* pathname, int flags)
 {
-    return selinux_android_restorecon(pathname, 0);
-}
-
-int restorecon_recursive(const char* pathname)
-{
-    return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
+    return selinux_android_restorecon(pathname, flags);
 }
 
 /*
@@ -481,3 +411,22 @@
 
     return true;
 }
+
+void reboot(const char* destination) {
+    android_reboot(ANDROID_RB_RESTART2, 0, destination);
+    // We're init, so android_reboot will actually have been a syscall so there's nothing
+    // to wait for. If android_reboot returns, just abort so that the kernel will reboot
+    // itself when init dies.
+    PLOG(FATAL) << "reboot failed";
+    abort();
+}
+
+void panic() {
+    LOG(ERROR) << "panic: rebooting to bootloader";
+    reboot("bootloader");
+}
+
+std::ostream& operator<<(std::ostream& os, const Timer& t) {
+    os << t.duration_s() << " seconds";
+    return os;
+}
diff --git a/init/util.h b/init/util.h
index 12ab173..e63c469 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,46 +20,65 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <string>
+#include <chrono>
 #include <functional>
+#include <ostream>
+#include <string>
 
 #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;
+  double duration_s() const {
+    typedef std::chrono::duration<double> double_duration;
+    return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
+  }
+
+  int64_t duration_ns() const {
+    return (boot_clock::now() - start_).count();
   }
 
  private:
-  uint64_t t0;
+  boot_clock::time_point start_;
 };
 
+std::ostream& operator<<(std::ostream& os, const Timer& t);
+
 unsigned int decode_uid(const char *s);
 
 int mkdir_recursive(const char *pathname, mode_t mode);
 void sanitize(char *p);
-int wait_for_file(const char *filename, int timeout);
+int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
 void import_kernel_cmdline(bool in_qemu,
                            const std::function<void(const std::string&, const std::string&, bool)>&);
 int make_dir(const char *path, mode_t mode);
-int restorecon(const char *pathname);
-int restorecon_recursive(const char *pathname);
+int restorecon(const char *pathname, int flags = 0);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
+
+void reboot(const char* destination) __attribute__((__noreturn__));
+void panic() __attribute__((__noreturn__));
+
 #endif
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 6ecbf90..24c75c4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -17,15 +17,8 @@
 #include "util.h"
 
 #include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-#include <cutils/files.h>
 #include <gtest/gtest.h>
-#include <selinux/android.h>
 
 TEST(util, read_file_ENOENT) {
   std::string s("hello");
@@ -49,51 +42,3 @@
   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();
-
-  static const char path[] = "/data/local/tmp/util.create_file.test";
-  static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test";
-  EXPECT_EQ(unsetenv(key), 0);
-  unlink(path);
-
-  int fd;
-  uid_t uid = decode_uid("logd");
-  gid_t gid = decode_uid("system");
-  mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
-  static const char context[] = "u:object_r:misc_logd_file:s0";
-  EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
-  if (fd < 0) return;
-  static const char hello[] = "hello world\n";
-  static const ssize_t len = strlen(hello);
-  EXPECT_EQ(write(fd, hello, len), len);
-  char buffer[sizeof(hello)];
-  memset(buffer, 0, sizeof(buffer));
-  EXPECT_GE(lseek(fd, 0, SEEK_SET), 0);
-  EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len);
-  EXPECT_EQ(strcmp(hello, buffer), 0);
-  char val[32];
-  snprintf(val, sizeof(val), "%d", fd);
-  EXPECT_EQ(android_get_control_file(path), -1);
-  setenv(key, val, true);
-  EXPECT_EQ(android_get_control_file(path), fd);
-  close(fd);
-  EXPECT_EQ(android_get_control_file(path), -1);
-  EXPECT_EQ(unsetenv(key), 0);
-  struct stat st;
-  EXPECT_EQ(stat(path, &st), 0);
-  EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
-  EXPECT_EQ(st.st_uid, uid);
-  EXPECT_EQ(st.st_gid, gid);
-  security_context_t con;
-  EXPECT_GE(getfilecon(path, &con), 0);
-  EXPECT_NE(con, static_cast<security_context_t>(NULL));
-  if (con) {
-    EXPECT_EQ(context, std::string(con));
-  }
-  freecon(con);
-  EXPECT_EQ(unlink(path), 0);
-}
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index 8b46154..f729faf 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -15,12 +15,20 @@
     name: "libappfuse",
     defaults: ["libappfuse_defaults"],
     export_include_dirs: ["include"],
-    srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
+    srcs: [
+        "FuseAppLoop.cc",
+        "FuseBuffer.cc",
+        "FuseBridgeLoop.cc",
+    ]
 }
 
 cc_test {
     name: "libappfuse_test",
     defaults: ["libappfuse_defaults"],
     shared_libs: ["libappfuse"],
-    srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
+    srcs: [
+        "tests/FuseAppLoopTest.cc",
+        "tests/FuseBridgeLoopTest.cc",
+        "tests/FuseBufferTest.cc",
+    ]
 }
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
new file mode 100644
index 0000000..a31880e
--- /dev/null
+++ b/libappfuse/FuseAppLoop.cc
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/stat.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+namespace {
+
+void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  // AppFuse does not support directory structure now.
+  // It can lookup only files under the mount point.
+  if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
+    LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  // Ensure that the filename ends with 0.
+  const size_t filename_length =
+      buffer->request.header.len - sizeof(fuse_in_header);
+  if (buffer->request.lookup_name[filename_length - 1] != 0) {
+    LOG(ERROR) << "File name does not end with 0.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const uint64_t inode =
+      static_cast<uint64_t>(atol(buffer->request.lookup_name));
+  if (inode == 0 || inode == LONG_MAX) {
+    LOG(ERROR) << "Invalid filename";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const int64_t size = callback->OnGetSize(inode);
+  if (size < 0) {
+    buffer->response.Reset(0, size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_entry_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.entry_out.nodeid = inode;
+  buffer->response.entry_out.attr_valid = 10;
+  buffer->response.entry_out.entry_valid = 10;
+  buffer->response.entry_out.attr.ino = inode;
+  buffer->response.entry_out.attr.mode = S_IFREG | 0777;
+  buffer->response.entry_out.attr.size = size;
+}
+
+void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  int64_t size;
+  uint32_t mode;
+  if (nodeid == FUSE_ROOT_ID) {
+    size = 0;
+    mode = S_IFDIR | 0777;
+  } else {
+    size = callback->OnGetSize(buffer->request.header.nodeid);
+    if (size < 0) {
+      buffer->response.Reset(0, size, buffer->request.header.unique);
+      return;
+    }
+    mode = S_IFREG | 0777;
+  }
+
+  buffer->response.Reset(sizeof(fuse_attr_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.attr_out.attr_valid = 10;
+  buffer->response.attr_out.attr.ino = nodeid;
+  buffer->response.attr_out.attr.mode = mode;
+  buffer->response.attr_out.attr.size = size;
+}
+
+void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
+  if (file_handle < 0) {
+    buffer->response.Reset(0, file_handle, buffer->request.header.unique);
+    return;
+  }
+  buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
+                         buffer->request.header.unique);
+  buffer->response.open_out.fh = file_handle;
+}
+
+void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.read_in.offset;
+  const uint32_t size = buffer->request.read_in.size;
+
+  if (size > kFuseMaxRead) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t read_size = callback->OnRead(nodeid, offset, size,
+                                             buffer->response.read_data);
+  if (read_size < 0) {
+    buffer->response.Reset(0, read_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
+}
+
+void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.write_in.offset;
+  const uint32_t size = buffer->request.write_in.size;
+
+  if (size > kFuseMaxWrite) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t write_size = callback->OnWrite(nodeid, offset, size,
+                                               buffer->request.write_data);
+  if (write_size < 0) {
+    buffer->response.Reset(0, write_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
+  buffer->response.write_out.size = write_size;
+}
+
+} // namespace
+
+bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
+  base::unique_fd fd(raw_fd);
+  FuseBuffer buffer;
+
+  LOG(DEBUG) << "Start fuse loop.";
+  while (callback->IsActive()) {
+    if (!buffer.request.Read(fd)) {
+      return false;
+    }
+
+    const uint32_t opcode = buffer.request.header.opcode;
+    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+    switch (opcode) {
+      case FUSE_FORGET:
+        // Do not reply to FUSE_FORGET.
+        continue;
+
+      case FUSE_LOOKUP:
+        HandleLookUp(&buffer, callback);
+        break;
+
+      case FUSE_GETATTR:
+        HandleGetAttr(&buffer, callback);
+        break;
+
+      case FUSE_OPEN:
+        HandleOpen(&buffer, callback);
+        break;
+
+      case FUSE_READ:
+        HandleRead(&buffer, callback);
+        break;
+
+      case FUSE_WRITE:
+        HandleWrite(&buffer, callback);
+        break;
+
+      case FUSE_RELEASE:
+        HandleRelease(&buffer, callback);
+        break;
+
+      case FUSE_FSYNC:
+        HandleFsync(&buffer, callback);
+        break;
+
+      default:
+        buffer.HandleNotImpl();
+        break;
+    }
+
+    if (!buffer.response.Write(fd)) {
+      LOG(ERROR) << "Failed to write a response to the device.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 332556d..2386bf8 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -20,19 +20,22 @@
 #include <android-base/unique_fd.h>
 
 namespace android {
+namespace fuse {
 
-bool FuseBridgeLoop::Start(
-    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
+bool StartFuseBridgeLoop(
+    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) {
   base::unique_fd dev_fd(raw_dev_fd);
   base::unique_fd proxy_fd(raw_proxy_fd);
+  FuseBuffer buffer;
+  size_t open_count = 0;
 
   LOG(DEBUG) << "Start fuse loop.";
   while (true) {
-    if (!buffer_.request.Read(dev_fd)) {
+    if (!buffer.request.Read(dev_fd)) {
       return false;
     }
 
-    const uint32_t opcode = buffer_.request.header.opcode;
+    const uint32_t opcode = buffer.request.header.opcode;
     LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
     switch (opcode) {
       case FUSE_FORGET:
@@ -45,35 +48,54 @@
       case FUSE_READ:
       case FUSE_WRITE:
       case FUSE_RELEASE:
-      case FUSE_FLUSH:
-        if (!buffer_.request.Write(proxy_fd)) {
+      case FUSE_FSYNC:
+        if (!buffer.request.Write(proxy_fd)) {
           LOG(ERROR) << "Failed to write a request to the proxy.";
           return false;
         }
-        if (!buffer_.response.Read(proxy_fd)) {
+        if (!buffer.response.Read(proxy_fd)) {
           LOG(ERROR) << "Failed to read a response from the proxy.";
           return false;
         }
         break;
 
       case FUSE_INIT:
-        buffer_.HandleInit();
+        buffer.HandleInit();
         break;
 
       default:
-        buffer_.HandleNotImpl();
+        buffer.HandleNotImpl();
         break;
     }
 
-    if (!buffer_.response.Write(dev_fd)) {
+    if (!buffer.response.Write(dev_fd)) {
       LOG(ERROR) << "Failed to write a response to the device.";
       return false;
     }
 
-    if (opcode == FUSE_INIT) {
-      callback->OnMount();
+    switch (opcode) {
+      case FUSE_INIT:
+        callback->OnMount();
+        break;
+      case FUSE_OPEN:
+        if (buffer.response.header.error == fuse::kFuseSuccess) {
+          open_count++;
+        }
+        break;
+      case FUSE_RELEASE:
+        if (open_count != 0) {
+            open_count--;
+        } else {
+            LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
+            break;
+        }
+        if (open_count == 0) {
+          return true;
+        }
+        break;
     }
   }
 }
 
+}  // namespace fuse
 }  // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 45280a5..8fb2dbc 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -21,52 +21,91 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <type_traits>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 
 namespace android {
+namespace fuse {
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckHeaderLength() const {
-  if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+static_assert(
+    std::is_standard_layout<FuseBuffer>::value,
+    "FuseBuffer must be standard layout union.");
+
+template <typename T>
+bool FuseMessage<T>::CheckHeaderLength(const char* name) const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (header.len >= sizeof(header) && header.len <= sizeof(T)) {
     return true;
   } else {
-    LOG(ERROR) << "Packet size is invalid=" << header.len;
+    LOG(ERROR) << "Invalid header length is found in " << name << ": " <<
+        header.len;
     return false;
   }
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckResult(
-    int result, const char* operation_name) const {
-  if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
-    return true;
-  } else {
-    PLOG(ERROR) << "Failed to " << operation_name
-        << " a packet from FD. result=" << result << " header.len="
-        << header.len;
+template <typename T>
+bool FuseMessage<T>::Read(int fd) {
+  char* const buf = reinterpret_cast<char*>(this);
+  const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, buf, sizeof(T)));
+  if (result < 0) {
+    PLOG(ERROR) << "Failed to read a FUSE message";
     return false;
   }
-}
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Read(int fd) {
-  const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
-  return CheckHeaderLength() && CheckResult(result, "read");
-}
-
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Write(int fd) const {
-  if (!CheckHeaderLength()) {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (result < static_cast<ssize_t>(sizeof(header))) {
+    LOG(ERROR) << "Read bytes " << result << " are shorter than header size " <<
+        sizeof(header);
     return false;
   }
-  const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
-  return CheckResult(result, "write");
+
+  if (!CheckHeaderLength("Read")) {
+    return false;
+  }
+
+  if (static_cast<uint32_t>(result) > header.len) {
+    LOG(ERROR) << "Read bytes " << result << " are longer than header.len " <<
+        header.len;
+    return false;
+  }
+
+  if (!base::ReadFully(fd, buf + result, header.len - result)) {
+    PLOG(ERROR) << "ReadFully failed";
+    return false;
+  }
+
+  return true;
 }
 
-template struct FuseMessage<FuseRequest, fuse_in_header>;
-template struct FuseMessage<FuseResponse, fuse_out_header>;
+template <typename T>
+bool FuseMessage<T>::Write(int fd) const {
+  if (!CheckHeaderLength("Write")) {
+    return false;
+  }
+
+  const char* const buf = reinterpret_cast<const char*>(this);
+  const auto& header = static_cast<const T*>(this)->header;
+  if (!base::WriteFully(fd, buf, header.len)) {
+    PLOG(ERROR) << "WriteFully failed";
+    return false;
+  }
+
+  return true;
+}
+
+template class FuseMessage<FuseRequest>;
+template class FuseMessage<FuseResponse>;
+
+void FuseRequest::Reset(
+    uint32_t data_length, uint32_t opcode, uint64_t unique) {
+  memset(this, 0, sizeof(fuse_in_header) + data_length);
+  header.len = sizeof(fuse_in_header) + data_length;
+  header.opcode = opcode;
+  header.unique = unique;
+}
 
 void FuseResponse::ResetHeader(
     uint32_t data_length, int32_t error, uint64_t unique) {
@@ -101,23 +140,18 @@
     return;
   }
 
-  // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
-  size_t response_size = sizeof(fuse_init_out);
+  // We limit ourselves to minor=15 because we don't handle BATCH_FORGET yet.
+  // Thus we need to use FUSE_COMPAT_22_INIT_OUT_SIZE.
 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
   // FUSE_KERNEL_VERSION >= 23.
-
-  // If the kernel only works on minor revs older than or equal to 22,
-  // then use the older structure size since this code only uses the 7.22
-  // version of the structure.
-  if (minor <= 22) {
-    response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-  }
+  const size_t response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+#else
+  const size_t response_size = sizeof(fuse_init_out);
 #endif
 
   response.Reset(response_size, kFuseSuccess, unique);
   fuse_init_out* const out = &response.init_out;
   out->major = FUSE_KERNEL_VERSION;
-  // We limit ourselves to 15 because we don't handle BATCH_FORGET yet.
   out->minor = std::min(minor, 15u);
   out->max_readahead = max_readahead;
   out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
@@ -133,4 +167,5 @@
   response.Reset(0, -ENOSYS, unique);
 }
 
+}  // namespace fuse
 }  // namespace android
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h
new file mode 100644
index 0000000..c3edfcc
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseAppLoop.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseAppLoopCallback {
+ public:
+  virtual bool IsActive() = 0;
+  virtual int64_t OnGetSize(uint64_t inode) = 0;
+  virtual int32_t OnFsync(uint64_t inode) = 0;
+  virtual int32_t OnWrite(
+      uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
+  virtual int32_t OnRead(
+      uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
+  virtual int32_t OnOpen(uint64_t inode) = 0;
+  virtual int32_t OnRelease(uint64_t inode) = 0;
+  virtual ~FuseAppLoopCallback() = default;
+};
+
+bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);
+
+}  // namespace fuse
+}  // namespace android
+
+#endif  // ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
index 2006532..1f71cf2 100644
--- a/libappfuse/include/libappfuse/FuseBridgeLoop.h
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -20,21 +20,18 @@
 #include "libappfuse/FuseBuffer.h"
 
 namespace android {
+namespace fuse {
 
-class FuseBridgeLoop {
+class FuseBridgeLoopCallback {
  public:
-  class Callback {
-   public:
-    virtual void OnMount() = 0;
-    virtual ~Callback() = default;
-  };
-
-  bool Start(int dev_fd, int proxy_fd, Callback* callback);
-
- private:
-  FuseBuffer buffer_;
+  virtual void OnMount() = 0;
+  virtual ~FuseBridgeLoopCallback() = default;
 };
 
+bool StartFuseBridgeLoop(
+    int dev_fd, int proxy_fd, FuseBridgeLoopCallback* callback);
+
+}  // namespace fuse
 }  // namespace android
 
 #endif  // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 071b777..7abd2fa 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -20,6 +20,7 @@
 #include <linux/fuse.h>
 
 namespace android {
+namespace fuse {
 
 // The numbers came from sdcard.c.
 // Maximum number of bytes to write/read in one request/one reply.
@@ -27,43 +28,62 @@
 constexpr size_t kFuseMaxRead = 128 * 1024;
 constexpr int32_t kFuseSuccess = 0;
 
-template<typename T, typename Header>
-struct FuseMessage {
-  Header header;
+template<typename T>
+class FuseMessage {
+ public:
   bool Read(int fd);
   bool Write(int fd) const;
  private:
-  bool CheckHeaderLength() const;
-  bool CheckResult(int result, const char* operation_name) const;
+  bool CheckHeaderLength(const char* name) const;
 };
 
-struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
+// FuseRequest represents file operation requests from /dev/fuse. It starts
+// from fuse_in_header. The body layout depends on the operation code.
+struct FuseRequest : public FuseMessage<FuseRequest> {
+  fuse_in_header header;
   union {
+    // for FUSE_WRITE
     struct {
       fuse_write_in write_in;
       char write_data[kFuseMaxWrite];
     };
+    // for FUSE_OPEN
     fuse_open_in open_in;
+    // for FUSE_INIT
     fuse_init_in init_in;
+    // for FUSE_READ
     fuse_read_in read_in;
+    // for FUSE_LOOKUP
     char lookup_name[0];
   };
+  void Reset(uint32_t data_length, uint32_t opcode, uint64_t unique);
 };
 
-struct FuseResponse : public FuseMessage<FuseResponse, fuse_out_header> {
+// FuseResponse represents file operation responses to /dev/fuse. It starts
+// from fuse_out_header. The body layout depends on the operation code.
+struct FuseResponse : public FuseMessage<FuseResponse> {
+  fuse_out_header header;
   union {
+    // for FUSE_INIT
     fuse_init_out init_out;
+    // for FUSE_LOOKUP
     fuse_entry_out entry_out;
+    // for FUSE_GETATTR
     fuse_attr_out attr_out;
+    // for FUSE_OPEN
     fuse_open_out open_out;
+    // for FUSE_READ
     char read_data[kFuseMaxRead];
+    // for FUSE_WRITE
     fuse_write_out write_out;
   };
   void Reset(uint32_t data_length, int32_t error, uint64_t unique);
   void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique);
 };
 
-union FuseBuffer {
+// To reduce memory usage, FuseBuffer shares the memory region for request and
+// response.
+union FuseBuffer final {
   FuseRequest request;
   FuseResponse response;
 
@@ -71,19 +91,7 @@
   void HandleNotImpl();
 };
 
-class FuseProxyLoop {
-  class IFuseProxyLoopCallback {
-   public:
-    virtual void OnMount() = 0;
-    virtual ~IFuseProxyLoopCallback() = default;
-  };
-
-  bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
-
- private:
-  FuseBuffer buffer_;
-};
-
+}  // namespace fuse
 }  // namespace android
 
 #endif  // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
new file mode 100644
index 0000000..25906cf
--- /dev/null
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/socket.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+namespace fuse {
+namespace {
+
+constexpr unsigned int kTestFileSize = 1024;
+
+struct CallbackRequest {
+  uint32_t code;
+  uint64_t inode;
+};
+
+class Callback : public FuseAppLoopCallback {
+ public:
+  std::vector<CallbackRequest> requests;
+
+  bool IsActive() override {
+    return true;
+  }
+
+  int64_t OnGetSize(uint64_t inode) override {
+    if (inode == FUSE_ROOT_ID) {
+      return 0;
+    } else {
+      return kTestFileSize;
+    }
+  }
+
+  int32_t OnFsync(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_FSYNC,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnWrite(uint64_t inode,
+                  uint64_t offset ATTRIBUTE_UNUSED,
+                  uint32_t size ATTRIBUTE_UNUSED,
+                  const void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_WRITE,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRead(uint64_t inode,
+                 uint64_t offset ATTRIBUTE_UNUSED,
+                 uint32_t size ATTRIBUTE_UNUSED,
+                 void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_READ,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnOpen(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_OPEN,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRelease(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_RELEASE,
+      .inode = inode
+    });
+    return 0;
+  }
+};
+
+class FuseAppLoopTest : public ::testing::Test {
+ private:
+  std::thread thread_;
+
+ protected:
+  base::unique_fd sockets_[2];
+  Callback callback_;
+  FuseRequest request_;
+  FuseResponse response_;
+
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets));
+    sockets_[0].reset(sockets[0]);
+    sockets_[1].reset(sockets[1]);
+    thread_ = std::thread([this] {
+      StartFuseAppLoop(sockets_[1].release(), &callback_);
+    });
+  }
+
+  void CheckCallback(
+      size_t data_size, uint32_t code, size_t expected_out_size) {
+    request_.Reset(data_size, code, 1);
+    request_.header.nodeid = 10;
+
+    ASSERT_TRUE(request_.Write(sockets_[0]));
+    ASSERT_TRUE(response_.Read(sockets_[0]));
+
+    Close();
+
+    EXPECT_EQ(kFuseSuccess, response_.header.error);
+    EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
+              response_.header.len);
+    EXPECT_EQ(1u, response_.header.unique);
+
+    ASSERT_EQ(1u, callback_.requests.size());
+    EXPECT_EQ(code, callback_.requests[0].code);
+    EXPECT_EQ(10u, callback_.requests[0].inode);
+  }
+
+  void Close() {
+    sockets_[0].reset();
+    sockets_[1].reset();
+    if (thread_.joinable()) {
+      thread_.join();
+    }
+  }
+
+  void TearDown() override {
+    Close();
+  }
+};
+
+}  // namespace
+
+TEST_F(FuseAppLoopTest, LookUp) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "10");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.entry_out.nodeid);
+  EXPECT_EQ(0u, response_.entry_out.generation);
+  EXPECT_EQ(10u, response_.entry_out.entry_valid);
+  EXPECT_EQ(10u, response_.entry_out.attr_valid);
+  EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
+  EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.entry_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
+  EXPECT_EQ(0u, response_.entry_out.attr.blocks);
+  EXPECT_EQ(0u, response_.entry_out.attr.atime);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtime);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctime);
+  EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
+  EXPECT_EQ(0u, response_.entry_out.attr.nlink);
+  EXPECT_EQ(0u, response_.entry_out.attr.uid);
+  EXPECT_EQ(0u, response_.entry_out.attr.gid);
+  EXPECT_EQ(0u, response_.entry_out.attr.rdev);
+  EXPECT_EQ(0u, response_.entry_out.attr.blksize);
+  EXPECT_EQ(0u, response_.entry_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "aa");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
+  request_.Reset(21u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "18446744073709551616");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = 10;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.attr_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr_Root) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
+  EXPECT_EQ(0u, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, Open) {
+  CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
+}
+
+TEST_F(FuseAppLoopTest, Fsync) {
+  CheckCallback(0u, FUSE_FSYNC, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Release) {
+  CheckCallback(0u, FUSE_RELEASE, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Read) {
+  CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Write) {
+  CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
index 31e3690..e74d9e7 100644
--- a/libappfuse/tests/FuseBridgeLoopTest.cc
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -21,11 +21,15 @@
 #include <sstream>
 #include <thread>
 
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 
 namespace android {
+namespace fuse {
+namespace {
 
-class Callback : public FuseBridgeLoop::Callback {
+class Callback : public FuseBridgeLoopCallback {
  public:
   bool mounted;
   Callback() : mounted(false) {}
@@ -36,20 +40,28 @@
 
 class FuseBridgeLoopTest : public ::testing::Test {
  protected:
-  int dev_sockets_[2];
-  int proxy_sockets_[2];
+  base::unique_fd dev_sockets_[2];
+  base::unique_fd proxy_sockets_[2];
   Callback callback_;
   std::thread thread_;
 
   FuseRequest request_;
   FuseResponse response_;
 
-  void SetUp() {
-    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
-    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int dev_sockets[2];
+    int proxy_sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets));
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets));
+    dev_sockets_[0].reset(dev_sockets[0]);
+    dev_sockets_[1].reset(dev_sockets[1]);
+    proxy_sockets_[0].reset(proxy_sockets[0]);
+    proxy_sockets_[1].reset(proxy_sockets[1]);
+
     thread_ = std::thread([this] {
-      FuseBridgeLoop loop;
-      loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
+      StartFuseBridgeLoop(
+          dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
     });
   }
 
@@ -103,20 +115,22 @@
   }
 
   void Close() {
-    close(dev_sockets_[0]);
-    close(dev_sockets_[1]);
-    close(proxy_sockets_[0]);
-    close(proxy_sockets_[1]);
+    dev_sockets_[0].reset();
+    dev_sockets_[1].reset();
+    proxy_sockets_[0].reset();
+    proxy_sockets_[1].reset();
     if (thread_.joinable()) {
       thread_.join();
     }
   }
 
-  void TearDown() {
+  void TearDown() override {
     Close();
   }
 };
 
+} //  namespace
+
 TEST_F(FuseBridgeLoopTest, FuseInit) {
   SendInitRequest(1u);
 
@@ -156,11 +170,11 @@
   CheckNotImpl(FUSE_RENAME);
   CheckNotImpl(FUSE_LINK);
   CheckNotImpl(FUSE_STATFS);
-  CheckNotImpl(FUSE_FSYNC);
   CheckNotImpl(FUSE_SETXATTR);
   CheckNotImpl(FUSE_GETXATTR);
   CheckNotImpl(FUSE_LISTXATTR);
   CheckNotImpl(FUSE_REMOVEXATTR);
+  CheckNotImpl(FUSE_FLUSH);
   CheckNotImpl(FUSE_OPENDIR);
   CheckNotImpl(FUSE_READDIR);
   CheckNotImpl(FUSE_RELEASEDIR);
@@ -186,11 +200,17 @@
 TEST_F(FuseBridgeLoopTest, Proxy) {
   CheckProxy(FUSE_LOOKUP);
   CheckProxy(FUSE_GETATTR);
-  CheckProxy(FUSE_OPEN);
   CheckProxy(FUSE_READ);
   CheckProxy(FUSE_WRITE);
+  CheckProxy(FUSE_FSYNC);
+
+  // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
+  CheckProxy(FUSE_OPEN);
   CheckProxy(FUSE_RELEASE);
-  CheckProxy(FUSE_FLUSH);
+
+  // Ensure the loop exits.
+  Close();
 }
 
-}  // android
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index 1aacfe3..db35d33 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -20,10 +20,13 @@
 #include <string.h>
 #include <sys/socket.h>
 
+#include <thread>
+
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 
 namespace android {
+namespace fuse {
 
 constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
 
@@ -109,6 +112,30 @@
   TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
 }
 
+TEST(FuseMessageTest, ShortWriteAndRead) {
+  int raw_fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, raw_fds));
+
+  android::base::unique_fd fds[2];
+  fds[0].reset(raw_fds[0]);
+  fds[1].reset(raw_fds[1]);
+
+  const int send_buffer_size = 1024;
+  ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &send_buffer_size,
+                          sizeof(int)));
+
+  bool succeed = false;
+  const int sender_fd = fds[0].get();
+  std::thread thread([sender_fd, &succeed] {
+    FuseRequest request;
+    request.header.len = 1024 * 4;
+    succeed = request.Write(sender_fd);
+  });
+  thread.detach();
+  FuseRequest request;
+  ASSERT_TRUE(request.Read(fds[1]));
+}
+
 TEST(FuseResponseTest, Reset) {
   FuseResponse response;
   // Write 1 to the first ten bytes.
@@ -163,7 +190,7 @@
 
   buffer.HandleInit();
 
-  ASSERT_EQ(sizeof(fuse_out_header) + sizeof(fuse_init_out),
+  ASSERT_EQ(sizeof(fuse_out_header) + FUSE_COMPAT_22_INIT_OUT_SIZE,
             buffer.response.header.len);
   EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
   EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
@@ -183,5 +210,6 @@
   ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
   EXPECT_EQ(-ENOSYS, buffer.response.header.error);
 }
-}
-  // namespace android
+
+} // namespace fuse
+} // namespace android
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 5c72234..684e611 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -22,9 +22,9 @@
         "-Werror",
     ],
 
+    // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
     clang_cflags: ["-Wno-inline-asm"],
 
-    // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
     include_dirs: ["external/libunwind/include/tdep"],
 
     // TODO: LLVM_DEVICE_BUILD_MK
@@ -117,4 +117,108 @@
     },
     cflags: ["-O0"],
     srcs: ["backtrace_testlib.c"],
+
+    target: {
+        linux: {
+            shared_libs: [
+                "libunwind",
+            ],
+        },
+        android: {
+            shared_libs: [
+                "libunwind",
+            ],
+        },
+    }
+}
+
+//-------------------------------------------------------------------------
+// The libbacktrace_offline static library.
+//-------------------------------------------------------------------------
+cc_library_static {
+    name: "libbacktrace_offline",
+    defaults: ["libbacktrace_common"],
+    host_supported: true,
+    srcs: ["BacktraceOffline.cpp"],
+
+    cflags: [
+        "-D__STDC_CONSTANT_MACROS",
+        "-D__STDC_LIMIT_MACROS",
+        "-D__STDC_FORMAT_MACROS",
+    ],
+
+    header_libs: ["llvm-headers"],
+
+    // Use shared libraries so their headers get included during build.
+    shared_libs = [
+        "libbase",
+        "libunwind",
+    ],
+}
+
+//-------------------------------------------------------------------------
+// The backtrace_test executable.
+//-------------------------------------------------------------------------
+cc_test {
+    name: "backtrace_test",
+    defaults: ["libbacktrace_common"],
+    host_supported: true,
+    srcs: [
+        "backtrace_offline_test.cpp",
+        "backtrace_test.cpp",
+        "GetPss.cpp",
+        "thread_utils.c",
+    ],
+
+    cflags: [
+        "-fno-builtin",
+        "-O0",
+        "-g",
+    ],
+
+    shared_libs: [
+        "libbacktrace_test",
+        "libbacktrace",
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libunwind",
+    ],
+
+    group_static_libs: true,
+
+    // Statically link LLVMlibraries to remove dependency on llvm shared library.
+    static_libs = [
+        "libbacktrace_offline",
+        "libLLVMObject",
+        "libLLVMBitReader",
+        "libLLVMMC",
+        "libLLVMMCParser",
+        "libLLVMCore",
+        "libLLVMSupport",
+
+        "libziparchive",
+        "libz",
+    ],
+
+    header_libs: ["llvm-headers"],
+
+    target: {
+        android: {
+            cflags: ["-DENABLE_PSS_TESTS"],
+            shared_libs: [
+                "libdl",
+                "libutils",
+            ],
+        },
+        linux: {
+            host_ldlibs: [
+                "-lpthread",
+                "-lrt",
+                "-ldl",
+                "-lncurses",
+            ],
+            static_libs: ["libutils"],
+        },
+    },
 }
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
deleted file mode 100644
index 2467f3e..0000000
--- a/libbacktrace/Android.build.mk
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := $(module)
-LOCAL_MODULE_TAGS := $(module_tag)
-LOCAL_MULTILIB := $($(module)_multilib)
-ifeq ($(LOCAL_MULTILIB),both)
-ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRARY))
-  LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-  LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-endif
-endif
-
-ifeq ($(build_type),target)
-  include $(LLVM_DEVICE_BUILD_MK)
-else
-  include $(LLVM_HOST_BUILD_MK)
-endif
-
-LOCAL_ADDITIONAL_DEPENDENCIES += \
-    $(LOCAL_PATH)/Android.mk \
-    $(LOCAL_PATH)/Android.build.mk \
-
-LOCAL_CFLAGS += \
-    $(libbacktrace_common_cflags) \
-    $($(module)_cflags) \
-    $($(module)_cflags_$(build_type)) \
-
-LOCAL_CLANG_CFLAGS += \
-    $(libbacktrace_common_clang_cflags) \
-
-LOCAL_CONLYFLAGS += \
-    $(libbacktrace_common_conlyflags) \
-    $($(module)_conlyflags) \
-    $($(module)_conlyflags_$(build_type)) \
-
-LOCAL_CPPFLAGS += \
-    $(libbacktrace_common_cppflags) \
-    $($(module)_cppflags) \
-    $($(module)_cppflags_$(build_type)) \
-
-LOCAL_C_INCLUDES += \
-    $(libbacktrace_common_c_includes) \
-    $($(module)_c_includes) \
-    $($(module)_c_includes_$(build_type)) \
-
-LOCAL_SRC_FILES := \
-    $($(module)_src_files) \
-    $($(module)_src_files_$(build_type)) \
-
-LOCAL_STATIC_LIBRARIES += \
-    $($(module)_static_libraries) \
-    $($(module)_static_libraries_$(build_type)) \
-
-LOCAL_SHARED_LIBRARIES += \
-    $($(module)_shared_libraries) \
-    $($(module)_shared_libraries_$(build_type)) \
-
-LOCAL_LDLIBS += \
-    $($(module)_ldlibs) \
-    $($(module)_ldlibs_$(build_type)) \
-
-LOCAL_STRIP_MODULE := $($(module)_strip_module)
-
-ifeq ($(build_type),target)
-  include $(BUILD_$(build_target))
-endif
-
-ifeq ($(build_type),host)
-  # Only build if host builds are supported.
-  ifeq ($(build_host),true)
-    # -fno-omit-frame-pointer should be set for host build. Because currently
-    # libunwind can't recognize .debug_frame using dwarf version 4, and it relies
-    # on stack frame pointer to do unwinding on x86.
-    # $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
-    # must be after the include.
-    LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer
-    include $(BUILD_HOST_$(build_target))
-  endif
-endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
deleted file mode 100644
index bb17325..0000000
--- a/libbacktrace/Android.mk
+++ /dev/null
@@ -1,148 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-libbacktrace_common_cflags := \
-	-Wall \
-	-Werror \
-
-libbacktrace_common_c_includes := \
-	external/libunwind/include/tdep \
-
-# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
-libbacktrace_common_clang_cflags += \
-    -Wno-inline-asm
-
-build_host := false
-ifeq ($(HOST_OS),linux)
-ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
-build_host := true
-endif
-endif
-
-LLVM_ROOT_PATH := external/llvm
-include $(LLVM_ROOT_PATH)/llvm.mk
-
-#-------------------------------------------------------------------------
-# The libbacktrace_offline shared library.
-#-------------------------------------------------------------------------
-libbacktrace_offline_src_files := \
-	BacktraceOffline.cpp \
-
-# Use shared llvm library on device to save space.
-libbacktrace_offline_shared_libraries_target := \
-	libbacktrace \
-	libbase \
-	liblog \
-	libunwind \
-	libutils \
-	libLLVM \
-
-libbacktrace_offline_static_libraries_target := \
-	libziparchive \
-	libz \
-
-# Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
-# which is not included in the prebuilt.
-libbacktrace_offline_static_libraries_host := \
-	libbacktrace \
-	libunwind \
-	libziparchive \
-	libz \
-	libbase \
-	liblog \
-	libutils \
-	libLLVMObject \
-	libLLVMBitReader \
-	libLLVMMC \
-	libLLVMMCParser \
-	libLLVMCore \
-	libLLVMSupport \
-
-module := libbacktrace_offline
-build_type := target
-build_target := STATIC_LIBRARY
-libbacktrace_offline_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
-
-#-------------------------------------------------------------------------
-# The backtrace_test executable.
-#-------------------------------------------------------------------------
-backtrace_test_cflags := \
-	-fno-builtin \
-	-O0 \
-	-g \
-
-backtrace_test_cflags_target := \
-	-DENABLE_PSS_TESTS \
-
-backtrace_test_src_files := \
-	backtrace_offline_test.cpp \
-	backtrace_test.cpp \
-	GetPss.cpp \
-	thread_utils.c \
-
-backtrace_test_ldlibs_host := \
-	-lpthread \
-	-lrt \
-
-backtrace_test_shared_libraries := \
-	libbacktrace_test \
-	libbacktrace \
-	libbase \
-	libcutils \
-	liblog \
-	libunwind \
-
-backtrace_test_shared_libraries_target += \
-	libdl \
-	libutils \
-	libLLVM \
-
-backtrace_test_static_libraries := \
-	libbacktrace_offline \
-
-backtrace_test_static_libraries_target := \
-	libziparchive \
-	libz \
-
-backtrace_test_static_libraries_host := \
-	libziparchive \
-	libz \
-	libutils \
-	libLLVMObject \
-	libLLVMBitReader \
-	libLLVMMC \
-	libLLVMMCParser \
-	libLLVMCore \
-	libLLVMSupport \
-
-backtrace_test_ldlibs_host += \
-	-ldl \
-
-backtrace_test_strip_module := false
-
-module := backtrace_test
-module_tag := debug
-build_type := target
-build_target := NATIVE_TEST
-backtrace_test_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index a05a6d8..5e54328 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -34,6 +34,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 #include <ziparchive/zip_archive.h>
@@ -50,6 +51,48 @@
 
 #include "BacktraceLog.h"
 
+struct EhFrame {
+  uint64_t hdr_vaddr;
+  uint64_t vaddr;
+  uint64_t fde_table_offset;
+  uintptr_t min_func_vaddr;
+  std::vector<uint8_t> hdr_data;
+  std::vector<uint8_t> data;
+};
+
+struct ArmIdxEntry {
+  uint32_t func_offset;
+  uint32_t value;
+};
+
+struct ArmExidx {
+  uint64_t exidx_vaddr;
+  uint64_t extab_vaddr;
+  std::vector<ArmIdxEntry> exidx_data;
+  std::vector<uint8_t> extab_data;
+  // There is a one-to-one map from exidx_data.func_offset to func_vaddr_array.
+  std::vector<uint32_t> func_vaddr_array;
+};
+
+struct DebugFrameInfo {
+  bool has_arm_exidx;
+  bool has_eh_frame;
+  bool has_debug_frame;
+  bool has_gnu_debugdata;
+
+  EhFrame eh_frame;
+  ArmExidx arm_exidx;
+
+  uint64_t min_vaddr;
+  uint64_t text_end_vaddr;
+
+  DebugFrameInfo() : has_arm_exidx(false), has_eh_frame(false),
+      has_debug_frame(false), has_gnu_debugdata(false) { }
+};
+
+static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>& g_debug_frames =
+    *new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
+
 void Space::Clear() {
   start = 0;
   end = 0;
@@ -207,23 +250,18 @@
   if (read_size != 0) {
     return read_size;
   }
+  read_size = arm_exidx_space_.Read(addr, buffer, bytes);
+  if (read_size != 0) {
+    return read_size;
+  }
+  read_size = arm_extab_space_.Read(addr, buffer, bytes);
+  if (read_size != 0) {
+    return read_size;
+  }
   read_size = stack_space_.Read(addr, buffer, bytes);
   return read_size;
 }
 
-static bool FileOffsetToVaddr(
-    const std::vector<DebugFrameInfo::EhFrame::ProgramHeader>& program_headers,
-    uint64_t file_offset, uint64_t* vaddr) {
-  for (auto& header : program_headers) {
-    if (file_offset >= header.file_offset && file_offset < header.file_offset + header.file_size) {
-      // TODO: Consider load_bias?
-      *vaddr = file_offset - header.file_offset + header.vaddr;
-      return true;
-    }
-  }
-  return false;
-}
-
 bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip,
                                     unw_proc_info_t* proc_info, int need_unwind_info) {
   backtrace_map_t map;
@@ -236,45 +274,90 @@
   if (debug_frame == nullptr) {
     return false;
   }
-  if (debug_frame->is_eh_frame) {
-    uint64_t ip_offset = ip - map.start + map.offset;
-    uint64_t ip_vaddr;  // vaddr in the elf file.
-    bool result = FileOffsetToVaddr(debug_frame->eh_frame.program_headers, ip_offset, &ip_vaddr);
-    if (!result) {
-      return false;
-    }
-    // Calculate the addresses where .eh_frame_hdr and .eh_frame stay when the process was running.
-    eh_frame_hdr_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_hdr_vaddr;
-    eh_frame_hdr_space_.end =
-        eh_frame_hdr_space_.start + debug_frame->eh_frame.eh_frame_hdr_data.size();
-    eh_frame_hdr_space_.data = debug_frame->eh_frame.eh_frame_hdr_data.data();
-
-    eh_frame_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_vaddr;
-    eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.eh_frame_data.size();
-    eh_frame_space_.data = debug_frame->eh_frame.eh_frame_data.data();
-
-    unw_dyn_info di;
-    memset(&di, '\0', sizeof(di));
-    di.start_ip = map.start;
-    di.end_ip = map.end;
-    di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
-    di.u.rti.name_ptr = 0;
-    di.u.rti.segbase = eh_frame_hdr_space_.start;
-    di.u.rti.table_data =
-        eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr;
-    di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t);
-    int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
-    return ret == 0;
-  }
 
   eh_frame_hdr_space_.Clear();
   eh_frame_space_.Clear();
-  unw_dyn_info_t di;
-  unw_word_t segbase = map.start - map.offset;
-  int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
-  if (found == 1) {
-    int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
-    return ret == 0;
+  arm_exidx_space_.Clear();
+  arm_extab_space_.Clear();
+
+  // vaddr in the elf file.
+  uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
+  if (debug_frame->has_arm_exidx) {
+    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
+    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
+      // Use binary search to find the correct function.
+      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
+                                 static_cast<uint32_t>(ip_vaddr));
+      if (it != func_vaddrs.begin()) {
+        --it;
+        // Found the exidx entry.
+        size_t index = it - func_vaddrs.begin();
+
+        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+        proc_info->unwind_info = reinterpret_cast<void*>(
+            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
+                                   debug_frame->arm_exidx.exidx_vaddr +
+                                   debug_frame->min_vaddr));
+
+        // Prepare arm_exidx space and arm_extab space.
+        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
+        arm_exidx_space_.end = arm_exidx_space_.start +
+            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
+        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
+            debug_frame->arm_exidx.exidx_data.data());
+
+        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
+        arm_extab_space_.end = arm_extab_space_.start +
+            debug_frame->arm_exidx.extab_data.size();
+        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
+        return true;
+      }
+    }
+  }
+
+  if (debug_frame->has_eh_frame) {
+    if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
+        ip_vaddr < debug_frame->text_end_vaddr) {
+      // Prepare eh_frame_hdr space and eh_frame space.
+      eh_frame_hdr_space_.start = ip - ip_vaddr + debug_frame->eh_frame.hdr_vaddr;
+      eh_frame_hdr_space_.end =
+          eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
+      eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
+
+      eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
+      eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
+      eh_frame_space_.data = debug_frame->eh_frame.data.data();
+
+      unw_dyn_info di;
+      memset(&di, '\0', sizeof(di));
+      di.start_ip = map.start;
+      di.end_ip = map.end;
+      di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
+      di.u.rti.name_ptr = 0;
+      di.u.rti.segbase = eh_frame_hdr_space_.start;
+      di.u.rti.table_data =
+          eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset;
+      di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t);
+      // TODO: Do it ourselves is more efficient than calling this function.
+      int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
+      if (ret == 0) {
+        return true;
+      }
+    }
+  }
+
+  if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
+    unw_dyn_info_t di;
+    unw_word_t segbase = map.start - map.offset;
+    // TODO: http://b/32916571
+    // TODO: Do it ourselves is more efficient than calling libunwind functions.
+    int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
+    if (found == 1) {
+      int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
+      if (ret == 0) {
+        return true;
+      }
+    }
   }
   return false;
 }
@@ -452,6 +535,10 @@
     default:
       result = false;
   }
+#else
+  UNUSED(reg);
+  UNUSED(value);
+  result = false;
 #endif
   return result;
 }
@@ -462,33 +549,18 @@
   return "";
 }
 
-std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>> BacktraceOffline::debug_frames_;
-std::unordered_set<std::string> BacktraceOffline::debug_frame_missing_files_;
-
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
 
 DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
   if (cache_file_) {
-    auto it = debug_frames_.find(filename);
-    if (it != debug_frames_.end()) {
+    auto it = g_debug_frames.find(filename);
+    if (it != g_debug_frames.end()) {
       return it->second.get();
     }
-    if (debug_frame_missing_files_.find(filename) != debug_frame_missing_files_.end()) {
-      return nullptr;
-    }
   }
   DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
   if (cache_file_) {
-    if (debug_frame != nullptr) {
-      debug_frames_.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
-    } else {
-      debug_frame_missing_files_.insert(filename);
-    }
-  } else {
-    if (last_debug_frame_ != nullptr) {
-      delete last_debug_frame_;
-    }
-    last_debug_frame_ = debug_frame;
+      g_debug_frames.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
   }
   return debug_frame;
 }
@@ -556,72 +628,106 @@
   return true;
 }
 
-using ProgramHeader = DebugFrameInfo::EhFrame::ProgramHeader;
-
 template <class ELFT>
 DebugFrameInfo* ReadDebugFrameFromELFFile(const llvm::object::ELFFile<ELFT>* elf) {
+  DebugFrameInfo* result = new DebugFrameInfo;
+  result->text_end_vaddr = std::numeric_limits<uint64_t>::max();
+
   bool has_eh_frame_hdr = false;
-  uint64_t eh_frame_hdr_vaddr = 0;
-  std::vector<uint8_t> eh_frame_hdr_data;
   bool has_eh_frame = false;
-  uint64_t eh_frame_vaddr = 0;
-  std::vector<uint8_t> eh_frame_data;
 
   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
     llvm::ErrorOr<llvm::StringRef> name = elf->getSectionName(&*it);
     if (name) {
-      if (name.get() == ".debug_frame") {
-        DebugFrameInfo* debug_frame = new DebugFrameInfo;
-        debug_frame->is_eh_frame = false;
-        return debug_frame;
-      }
-      if (name.get() == ".eh_frame_hdr") {
-        has_eh_frame_hdr = true;
-        eh_frame_hdr_vaddr = it->sh_addr;
+      std::string s = name.get();
+      if (s == ".debug_frame") {
+        result->has_debug_frame = true;
+      } else if (s == ".gnu_debugdata") {
+        result->has_gnu_debugdata = true;
+      } else if (s == ".eh_frame_hdr") {
+        result->eh_frame.hdr_vaddr = it->sh_addr;
         llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
         if (data) {
-          eh_frame_hdr_data.insert(eh_frame_hdr_data.begin(), data->data(),
-                                   data->data() + data->size());
-        } else {
-          return nullptr;
+          result->eh_frame.hdr_data.insert(result->eh_frame.hdr_data.end(),
+              data->data(), data->data() + data->size());
+
+          uint64_t fde_table_offset;
+          if (GetFdeTableOffsetInEhFrameHdr(result->eh_frame.hdr_data,
+                                             &fde_table_offset)) {
+            result->eh_frame.fde_table_offset = fde_table_offset;
+            // Make sure we have at least one entry in fde_table.
+            if (fde_table_offset + 2 * sizeof(int32_t) <= data->size()) {
+              intptr_t eh_frame_hdr_vaddr = it->sh_addr;
+              int32_t sdata;
+              uint8_t* p = result->eh_frame.hdr_data.data() + fde_table_offset;
+              memcpy(&sdata, p, sizeof(sdata));
+              result->eh_frame.min_func_vaddr = eh_frame_hdr_vaddr + sdata;
+              has_eh_frame_hdr = true;
+            }
+          }
         }
-      } else if (name.get() == ".eh_frame") {
-        has_eh_frame = true;
-        eh_frame_vaddr = it->sh_addr;
+      } else if (s == ".eh_frame") {
+        result->eh_frame.vaddr = it->sh_addr;
         llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
         if (data) {
-          eh_frame_data.insert(eh_frame_data.begin(), data->data(), data->data() + data->size());
-        } else {
-          return nullptr;
+          result->eh_frame.data.insert(result->eh_frame.data.end(),
+                                                data->data(), data->data() + data->size());
+          has_eh_frame = true;
         }
+      } else if (s == ".ARM.exidx") {
+        result->arm_exidx.exidx_vaddr = it->sh_addr;
+        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
+        if (data) {
+          size_t entry_count = data->size() / sizeof(ArmIdxEntry);
+          result->arm_exidx.exidx_data.resize(entry_count);
+          memcpy(result->arm_exidx.exidx_data.data(), data->data(),
+                 entry_count * sizeof(ArmIdxEntry));
+          if (entry_count > 0u) {
+            // Change IdxEntry.func_offset into vaddr.
+            result->arm_exidx.func_vaddr_array.reserve(entry_count);
+            uint32_t vaddr = it->sh_addr;
+            for (auto& entry : result->arm_exidx.exidx_data) {
+              uint32_t func_offset = entry.func_offset + vaddr;
+              // Clear bit 31 for the prel31 offset.
+              // Arm sets bit 0 to mark it as thumb code, remove the flag.
+              result->arm_exidx.func_vaddr_array.push_back(
+                  func_offset & 0x7ffffffe);
+              vaddr += 8;
+            }
+            result->has_arm_exidx = true;
+          }
+        }
+      } else if (s == ".ARM.extab") {
+        result->arm_exidx.extab_vaddr = it->sh_addr;
+        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
+        if (data) {
+          result->arm_exidx.extab_data.insert(result->arm_exidx.extab_data.end(),
+                                              data->data(), data->data() + data->size());
+        }
+      } else if (s == ".text") {
+        result->text_end_vaddr = it->sh_addr + it->sh_size;
       }
     }
   }
-  if (!(has_eh_frame_hdr && has_eh_frame)) {
-    return nullptr;
-  }
-  uint64_t fde_table_offset;
-  if (!GetFdeTableOffsetInEhFrameHdr(eh_frame_hdr_data, &fde_table_offset)) {
-    return nullptr;
+
+  if (has_eh_frame_hdr && has_eh_frame) {
+    result->has_eh_frame = true;
   }
 
-  std::vector<ProgramHeader> program_headers;
+  result->min_vaddr = std::numeric_limits<uint64_t>::max();
   for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
-    ProgramHeader header;
-    header.vaddr = it->p_vaddr;
-    header.file_offset = it->p_offset;
-    header.file_size = it->p_filesz;
-    program_headers.push_back(header);
+    if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
+      if (it->p_vaddr < result->min_vaddr) {
+        result->min_vaddr = it->p_vaddr;
+      }
+    }
   }
-  DebugFrameInfo* debug_frame = new DebugFrameInfo;
-  debug_frame->is_eh_frame = true;
-  debug_frame->eh_frame.eh_frame_hdr_vaddr = eh_frame_hdr_vaddr;
-  debug_frame->eh_frame.eh_frame_vaddr = eh_frame_vaddr;
-  debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr = fde_table_offset;
-  debug_frame->eh_frame.eh_frame_hdr_data = std::move(eh_frame_hdr_data);
-  debug_frame->eh_frame.eh_frame_data = std::move(eh_frame_data);
-  debug_frame->eh_frame.program_headers = program_headers;
-  return debug_frame;
+  if (!result->has_eh_frame && !result->has_arm_exidx && !result->has_debug_frame &&
+      !result->has_gnu_debugdata) {
+    delete result;
+    return nullptr;
+  }
+  return result;
 }
 
 static bool IsValidElfPath(const std::string& filename) {
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
index 42f826d..c0b686e 100644
--- a/libbacktrace/BacktraceOffline.h
+++ b/libbacktrace/BacktraceOffline.h
@@ -40,22 +40,7 @@
   size_t Read(uint64_t addr, uint8_t* buffer, size_t size);
 };
 
-struct DebugFrameInfo {
-  bool is_eh_frame;
-  struct EhFrame {
-    uint64_t eh_frame_hdr_vaddr;
-    uint64_t eh_frame_vaddr;
-    uint64_t fde_table_offset_in_eh_frame_hdr;
-    std::vector<uint8_t> eh_frame_hdr_data;
-    std::vector<uint8_t> eh_frame_data;
-    struct ProgramHeader {
-      uint64_t vaddr;
-      uint64_t file_offset;
-      uint64_t file_size;
-    };
-    std::vector<ProgramHeader> program_headers;
-  } eh_frame;
-};
+struct DebugFrameInfo;
 
 class BacktraceOffline : public Backtrace {
  public:
@@ -63,18 +48,13 @@
                    bool cache_file)
       : Backtrace(pid, tid, map),
         cache_file_(cache_file),
-        context_(nullptr),
-        last_debug_frame_(nullptr) {
+        context_(nullptr) {
     stack_space_.start = stack.start;
     stack_space_.end = stack.end;
     stack_space_.data = stack.data;
   }
 
-  virtual ~BacktraceOffline() {
-    if (last_debug_frame_ != nullptr) {
-      delete last_debug_frame_;
-    }
-  }
+  virtual ~BacktraceOffline() = default;
 
   bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
 
@@ -91,15 +71,13 @@
   std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
   DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
 
-  static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>> debug_frames_;
-  static std::unordered_set<std::string> debug_frame_missing_files_;
-
   bool cache_file_;
   ucontext_t* context_;
   Space eh_frame_hdr_space_;
   Space eh_frame_space_;
+  Space arm_extab_space_;
+  Space arm_exidx_space_;
   Space stack_space_;
-  DebugFrameInfo* last_debug_frame_;
 };
 
 #endif  // _LIBBACKTRACE_BACKTRACE_OFFLINE_H
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index 148c418..fd8b713 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -17,7 +17,6 @@
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
-#include <sys/uio.h>
 #include <sys/param.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
@@ -73,20 +72,42 @@
   if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
     return 0;
   }
+
   bytes = MIN(map.end - addr, bytes);
-
-  struct iovec local_io;
-  local_io.iov_base = buffer;
-  local_io.iov_len = bytes;
-
-  struct iovec remote_io;
-  remote_io.iov_base = reinterpret_cast<void*>(addr);
-  remote_io.iov_len = bytes;
-
-  ssize_t bytes_read = process_vm_readv(Tid(), &local_io, 1, &remote_io, 1, 0);
-  if (bytes_read == -1) {
-    return 0;
+  size_t bytes_read = 0;
+  word_t data_word;
+  size_t align_bytes = addr & (sizeof(word_t) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
+      return 0;
+    }
+    size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    buffer += copy_bytes;
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
   }
-  return static_cast<size_t>(bytes_read);
+
+  size_t num_words = bytes / sizeof(word_t);
+  for (size_t i = 0; i < num_words; i++) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, sizeof(word_t));
+    buffer += sizeof(word_t);
+    addr += sizeof(word_t);
+    bytes_read += sizeof(word_t);
+  }
+
+  size_t left_over = bytes & (sizeof(word_t) - 1);
+  if (left_over) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
 #endif
 }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index d6dc2c9..49fcb29 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
 #include <libunwind.h>
 #include <pthread.h>
 #include <stdint.h>
@@ -9,6 +26,9 @@
 #include <utility>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 #include <cutils/threads.h>
@@ -22,29 +42,7 @@
 int test_level_three(int, int, int, int, void (*)(void*), void*);
 int test_level_four(int, int, int, int, void (*)(void*), void*);
 int test_recursive_call(int, void (*)(void*), void*);
-}
-
-static volatile bool g_exit_flag = false;
-
-static void GetContextAndExit(void* arg) {
-  unw_context_t* unw_context = reinterpret_cast<unw_context_t*>(arg);
-  unw_getcontext(unw_context);
-  // Don't touch the stack anymore.
-  while (!g_exit_flag) {
-  }
-}
-
-struct OfflineThreadArg {
-  unw_context_t unw_context;
-  pid_t tid;
-  std::function<int(void (*)(void*), void*)> function;
-};
-
-static void* OfflineThreadFunc(void* arg) {
-  OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
-  fn_arg->tid = gettid();
-  fn_arg->function(GetContextAndExit, &fn_arg->unw_context);
-  return nullptr;
+void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag);
 }
 
 static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) {
@@ -73,11 +71,68 @@
   return ucontext;
 }
 
-static void OfflineBacktraceFunctionCall(const std::function<int(void (*)(void*), void*)>& function,
-                                         std::vector<uintptr_t>* pc_values) {
+struct FunctionSymbol {
+  std::string name;
+  uintptr_t start;
+  uintptr_t end;
+};
+
+static std::vector<FunctionSymbol> GetFunctionSymbols() {
+  std::vector<FunctionSymbol> symbols = {
+      {"unknown_start", 0, 0},
+      {"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0},
+      {"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0},
+      {"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0},
+      {"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0},
+      {"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0},
+      {"test_get_context_and_wait", reinterpret_cast<uintptr_t>(&test_get_context_and_wait), 0},
+      {"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)},
+  };
+  std::sort(
+      symbols.begin(), symbols.end(),
+      [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; });
+  for (size_t i = 0; i + 1 < symbols.size(); ++i) {
+    symbols[i].end = symbols[i + 1].start;
+  }
+  return symbols;
+}
+
+static std::string RawDataToHexString(const void* data, size_t size) {
+  const uint8_t* p = static_cast<const uint8_t*>(data);
+  std::string s;
+  for (size_t i = 0; i < size; ++i) {
+    s += android::base::StringPrintf("%02x", p[i]);
+  }
+  return s;
+}
+
+static void HexStringToRawData(const char* s, void* data, size_t size) {
+  uint8_t* p = static_cast<uint8_t*>(data);
+  for (size_t i = 0; i < size; ++i) {
+    int value;
+    sscanf(s, "%02x", &value);
+    *p++ = static_cast<uint8_t>(value);
+    s += 2;
+  }
+}
+
+struct OfflineThreadArg {
+  unw_context_t unw_context;
+  pid_t tid;
+  volatile int exit_flag;
+};
+
+static void* OfflineThreadFunc(void* arg) {
+  OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
+  fn_arg->tid = gettid();
+  test_get_context_and_wait(&fn_arg->unw_context, &fn_arg->exit_flag);
+  return nullptr;
+}
+
+// This test is disable because it is for generating test data.
+TEST(libbacktrace, DISABLED_generate_offline_testdata) {
   // Create a thread to generate the needed stack and registers information.
-  g_exit_flag = false;
-  const size_t stack_size = 1024 * 1024;
+  const size_t stack_size = 16 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, stack);
   uintptr_t stack_addr = reinterpret_cast<uintptr_t>(stack);
@@ -86,18 +141,17 @@
   ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
   pthread_t thread;
   OfflineThreadArg arg;
-  arg.function = function;
+  arg.exit_flag = 0;
   ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
   // Wait for the offline thread to generate the stack and unw_context information.
   sleep(1);
   // Copy the stack information.
   std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
                                   reinterpret_cast<uint8_t*>(stack) + stack_size);
-  g_exit_flag = true;
+  arg.exit_flag = 1;
   ASSERT_EQ(0, pthread_join(thread, nullptr));
   ASSERT_EQ(0, munmap(stack, stack_size));
 
-  // Do offline backtrace.
   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
   ASSERT_TRUE(map != nullptr);
 
@@ -106,47 +160,44 @@
   stack_info.end = stack_addr + stack_size;
   stack_info.data = stack_data.data();
 
-  std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(getpid(), arg.tid, map.get(), stack_info));
-  ASSERT_TRUE(backtrace != nullptr);
-
-  ucontext_t ucontext = GetUContextFromUnwContext(arg.unw_context);
-  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
-  // Collect pc values of the call stack frames.
-  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
-    pc_values->push_back(backtrace->GetFrame(i)->pc);
+  // Generate offline testdata.
+  std::string testdata;
+  // 1. Dump pid, tid
+  testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid);
+  // 2. Dump maps
+  for (auto it = map->begin(); it != map->end(); ++it) {
+    testdata += android::base::StringPrintf(
+        "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
+        " load_base: %" PRIxPTR " flags: %d name: %s\n",
+        it->start, it->end, it->offset, it->load_base, it->flags, it->name.c_str());
   }
+  // 3. Dump registers
+  testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
+  testdata += RawDataToHexString(&arg.unw_context, sizeof(arg.unw_context));
+  testdata.push_back('\n');
+
+  // 4. Dump stack
+  testdata += android::base::StringPrintf(
+      "stack: start: %" PRIx64 " end: %" PRIx64 " size: %zu ",
+      stack_info.start, stack_info.end, stack_data.size());
+  testdata += RawDataToHexString(stack_data.data(), stack_data.size());
+  testdata.push_back('\n');
+
+  // 5. Dump function symbols
+  std::vector<FunctionSymbol> function_symbols = GetFunctionSymbols();
+  for (const auto& symbol : function_symbols) {
+    testdata += android::base::StringPrintf(
+        "function: start: %" PRIxPTR " end: %" PRIxPTR" name: %s\n",
+        symbol.start, symbol.end, symbol.name.c_str());
+  }
+
+  ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata"));
 }
 
 // Return the name of the function which matches the address. Although we don't know the
 // exact end of each function, it is accurate enough for the tests.
-static std::string FunctionNameForAddress(uintptr_t addr) {
-  struct FunctionSymbol {
-    std::string name;
-    uintptr_t start;
-    uintptr_t end;
-  };
-
-  static std::vector<FunctionSymbol> symbols;
-  if (symbols.empty()) {
-    symbols = std::vector<FunctionSymbol>{
-        {"unknown_start", 0, 0},
-        {"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0},
-        {"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0},
-        {"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0},
-        {"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0},
-        {"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0},
-        {"GetContextAndExit", reinterpret_cast<uintptr_t>(&GetContextAndExit), 0},
-        {"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)},
-    };
-    std::sort(
-        symbols.begin(), symbols.end(),
-        [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; });
-    for (size_t i = 0; i + 1 < symbols.size(); ++i) {
-      symbols[i].end = symbols[i + 1].start;
-    }
-  }
+static std::string FunctionNameForAddress(uintptr_t addr,
+                                          const std::vector<FunctionSymbol>& symbols) {
   for (auto& symbol : symbols) {
     if (addr >= symbol.start && addr < symbol.end) {
       return symbol.name;
@@ -155,35 +206,136 @@
   return "";
 }
 
-TEST(libbacktrace, offline) {
-  std::function<int(void (*)(void*), void*)> function =
-      std::bind(test_level_one, 1, 2, 3, 4, std::placeholders::_1, std::placeholders::_2);
+static std::string GetArch() {
+#if defined(__arm__)
+  return "arm";
+#elif defined(__aarch64__)
+  return "aarch64";
+#elif defined(__i386__)
+  return "x86";
+#elif defined(__x86_64__)
+  return "x86_64";
+#else
+  return "";
+#endif
+}
+
+static void BacktraceOfflineTest(const std::string& testlib_name) {
+  const std::string arch = GetArch();
+  if (arch.empty()) {
+    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+    return;
+  }
+  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+  std::string testdata;
+  ASSERT_TRUE(android::base::ReadFileToString(offline_testdata_path, &testdata));
+
+  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
+  struct stat st;
+  if (stat(testlib_path.c_str(), &st) == -1) {
+    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+    return;
+  }
+
+  // Parse offline_testdata.
+  std::vector<std::string> lines = android::base::Split(testdata, "\n");
+  int pid;
+  int tid;
+  std::vector<backtrace_map_t> maps;
+  unw_context_t unw_context;
+  backtrace_stackinfo_t stack_info;
+  std::vector<uint8_t> stack;
+  std::vector<FunctionSymbol> symbols;
+  for (const auto& line : lines) {
+    if (android::base::StartsWith(line, "pid:")) {
+      sscanf(line.c_str(), "pid: %d tid: %d", &pid, &tid);
+    } else if (android::base::StartsWith(line, "map:")) {
+      maps.resize(maps.size() + 1);
+      int pos;
+      sscanf(line.c_str(),
+             "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
+             " load_base: %" SCNxPTR " flags: %d name: %n",
+             &maps.back().start, &maps.back().end, &maps.back().offset,
+             &maps.back().load_base, &maps.back().flags, &pos);
+      maps.back().name = android::base::Trim(line.substr(pos));
+    } else if (android::base::StartsWith(line, "registers:")) {
+      size_t size;
+      int pos;
+      sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
+      ASSERT_EQ(sizeof(unw_context), size);
+      HexStringToRawData(&line[pos], &unw_context, size);
+    } else if (android::base::StartsWith(line, "stack:")) {
+      size_t size;
+      int pos;
+      sscanf(line.c_str(),
+             "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
+             &stack_info.start, &stack_info.end, &size, &pos);
+      stack.resize(size);
+      HexStringToRawData(&line[pos], &stack[0], size);
+      stack_info.data = stack.data();
+    } else if (android::base::StartsWith(line, "function:")) {
+      symbols.resize(symbols.size() + 1);
+      int pos;
+      sscanf(line.c_str(),
+             "function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
+             &symbols.back().start, &symbols.back().end,
+             &pos);
+      symbols.back().name = line.substr(pos);
+    }
+  }
+
+  // Fix path of libbacktrace_testlib.so.
+  for (auto& map : maps) {
+    if (map.name.find("libbacktrace_test.so") != std::string::npos) {
+      map.name = testlib_path;
+    }
+  }
+
+  // Do offline backtrace.
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid, maps));
+  ASSERT_TRUE(map != nullptr);
+
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::CreateOffline(pid, tid, map.get(), stack_info));
+  ASSERT_TRUE(backtrace != nullptr);
+
+  ucontext_t ucontext = GetUContextFromUnwContext(unw_context);
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+
+  // Collect pc values of the call stack frames.
   std::vector<uintptr_t> pc_values;
-  OfflineBacktraceFunctionCall(function, &pc_values);
-  ASSERT_FALSE(pc_values.empty());
-  ASSERT_LE(pc_values.size(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
+    pc_values.push_back(backtrace->GetFrame(i)->pc);
+  }
 
   size_t test_one_index = 0;
   for (size_t i = 0; i < pc_values.size(); ++i) {
-    if (FunctionNameForAddress(pc_values[i]) == "test_level_one") {
+    if (FunctionNameForAddress(pc_values[i], symbols) == "test_level_one") {
       test_one_index = i;
       break;
     }
   }
 
   ASSERT_GE(test_one_index, 3u);
-  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index]));
-  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1]));
-  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2]));
-  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3]));
+  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], symbols));
+  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], symbols));
+  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2], symbols));
+  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3], symbols));
 }
 
-TEST(libbacktrace, offline_max_trace) {
-  std::function<int(void (*)(void*), void*)> function = std::bind(
-      test_recursive_call, MAX_BACKTRACE_FRAMES + 10, std::placeholders::_1, std::placeholders::_2);
-  std::vector<uintptr_t> pc_values;
-  OfflineBacktraceFunctionCall(function, &pc_values);
-  ASSERT_FALSE(pc_values.empty());
-  ASSERT_EQ(static_cast<size_t>(MAX_BACKTRACE_FRAMES), pc_values.size());
-  ASSERT_EQ("test_recursive_call", FunctionNameForAddress(pc_values.back()));
+TEST(libbacktrace, offline_eh_frame) {
+  BacktraceOfflineTest("libbacktrace_test_eh_frame.so");
+}
+
+TEST(libbacktrace, offline_debug_frame) {
+  BacktraceOfflineTest("libbacktrace_test_debug_frame.so");
+}
+
+TEST(libbacktrace, offline_gnu_debugdata) {
+  BacktraceOfflineTest("libbacktrace_test_gnu_debugdata.so");
+}
+
+TEST(libbacktrace, offline_arm_exidx) {
+  BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
 }
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
index d4d15db..6f6b535 100644
--- a/libbacktrace/backtrace_testlib.c
+++ b/libbacktrace/backtrace_testlib.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <libunwind.h>
 #include <stdio.h>
 
 int test_level_four(int one, int two, int three, int four,
@@ -53,3 +54,23 @@
   }
   return 0;
 }
+
+typedef struct {
+  unw_context_t* unw_context;
+  volatile int* exit_flag;
+} GetContextArg;
+
+static void GetContextAndExit(void* data) {
+  GetContextArg* arg = (GetContextArg*)data;
+  unw_getcontext(arg->unw_context);
+  // Don't touch the stack anymore.
+  while (*arg->exit_flag == 0) {
+  }
+}
+
+void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag) {
+  GetContextArg arg;
+  arg.unw_context = unw_context;
+  arg.exit_flag = exit_flag;
+  test_level_one(1, 2, 3, 4, GetContextAndExit, &arg);
+}
diff --git a/libbacktrace/testdata/aarch64/libbacktrace_test_eh_frame.so b/libbacktrace/testdata/aarch64/libbacktrace_test_eh_frame.so
new file mode 100755
index 0000000..880f337
--- /dev/null
+++ b/libbacktrace/testdata/aarch64/libbacktrace_test_eh_frame.so
Binary files differ
diff --git a/libbacktrace/testdata/aarch64/offline_testdata b/libbacktrace/testdata/aarch64/offline_testdata
new file mode 100644
index 0000000..ba44e09
--- /dev/null
+++ b/libbacktrace/testdata/aarch64/offline_testdata
@@ -0,0 +1,107 @@
+pid: 32438 tid: 32439
+map: start: 557066e000 end: 55706ee000 offset: 0 load_base: 0 flags: 5 name: /data/backtrace_test64
+map: start: 55706ef000 end: 55706f2000 offset: 80000 load_base: 0 flags: 1 name: /data/backtrace_test64
+map: start: 55706f2000 end: 55706f3000 offset: 83000 load_base: 0 flags: 3 name: /data/backtrace_test64
+map: start: 7014200000 end: 7014600000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
+map: start: 701464c000 end: 701465c000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libcutils.so
+map: start: 701465c000 end: 701465d000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 701465d000 end: 701465e000 offset: 10000 load_base: 0 flags: 1 name: /system/lib64/libcutils.so
+map: start: 701465e000 end: 701465f000 offset: 11000 load_base: 0 flags: 3 name: /system/lib64/libcutils.so
+map: start: 7014691000 end: 70146b5000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/liblzma.so
+map: start: 70146b5000 end: 70146b6000 offset: 23000 load_base: 0 flags: 1 name: /system/lib64/liblzma.so
+map: start: 70146b6000 end: 70146b7000 offset: 24000 load_base: 0 flags: 3 name: /system/lib64/liblzma.so
+map: start: 70146b7000 end: 70146bc000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 70146c9000 end: 70158b5000 offset: 0 load_base: af000 flags: 5 name: /system/lib64/libLLVM.so
+map: start: 70158b5000 end: 701596b000 offset: 11eb000 load_base: 0 flags: 1 name: /system/lib64/libLLVM.so
+map: start: 701596b000 end: 701596c000 offset: 12a1000 load_base: 0 flags: 3 name: /system/lib64/libLLVM.so
+map: start: 701596c000 end: 701599f000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 70159c2000 end: 70159f9000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libm.so
+map: start: 70159f9000 end: 70159fa000 offset: 36000 load_base: 0 flags: 1 name: /system/lib64/libm.so
+map: start: 70159fa000 end: 70159fb000 offset: 37000 load_base: 0 flags: 3 name: /system/lib64/libm.so
+map: start: 7015a1e000 end: 7015a2e000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libbacktrace.so
+map: start: 7015a2e000 end: 7015a2f000 offset: f000 load_base: 0 flags: 1 name: /system/lib64/libbacktrace.so
+map: start: 7015a2f000 end: 7015a30000 offset: 10000 load_base: 0 flags: 3 name: /system/lib64/libbacktrace.so
+map: start: 7015a5e000 end: 7015a7d000 offset: 0 load_base: 1000 flags: 5 name: /system/lib64/libutils.so
+map: start: 7015a7d000 end: 7015a7e000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 7015a7e000 end: 7015a7f000 offset: 1f000 load_base: 0 flags: 1 name: /system/lib64/libutils.so
+map: start: 7015a7f000 end: 7015a80000 offset: 20000 load_base: 0 flags: 3 name: /system/lib64/libutils.so
+map: start: 7015a99000 end: 7015b6d000 offset: 0 load_base: 9000 flags: 5 name: /system/lib64/libc++.so
+map: start: 7015b6d000 end: 7015b6e000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 7015b6e000 end: 7015b76000 offset: d4000 load_base: 0 flags: 1 name: /system/lib64/libc++.so
+map: start: 7015b76000 end: 7015b77000 offset: dc000 load_base: 0 flags: 3 name: /system/lib64/libc++.so
+map: start: 7015b77000 end: 7015b7a000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 7015b81000 end: 7015b92000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/liblog.so
+map: start: 7015b92000 end: 7015b93000 offset: 10000 load_base: 0 flags: 1 name: /system/lib64/liblog.so
+map: start: 7015b93000 end: 7015b94000 offset: 11000 load_base: 0 flags: 3 name: /system/lib64/liblog.so
+map: start: 7015be3000 end: 7015ca3000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libc.so
+map: start: 7015ca3000 end: 7015ca9000 offset: bf000 load_base: 0 flags: 1 name: /system/lib64/libc.so
+map: start: 7015ca9000 end: 7015cab000 offset: c5000 load_base: 0 flags: 3 name: /system/lib64/libc.so
+map: start: 7015cab000 end: 7015cac000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 7015cac000 end: 7015cad000 offset: 0 load_base: 0 flags: 1 name: [anon:.bss]
+map: start: 7015cad000 end: 7015cb4000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 7015cf5000 end: 7015cf6000 offset: 0 load_base: 0 flags: 5 name: /data/libbacktrace_test.so
+map: start: 7015cf6000 end: 7015cf7000 offset: 0 load_base: 0 flags: 1 name: /data/libbacktrace_test.so
+map: start: 7015cf7000 end: 7015cf8000 offset: 1000 load_base: 0 flags: 3 name: /data/libbacktrace_test.so
+map: start: 7015d1f000 end: 7015d39000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libunwind.so
+map: start: 7015d39000 end: 7015d3a000 offset: 19000 load_base: 0 flags: 1 name: /system/lib64/libunwind.so
+map: start: 7015d3a000 end: 7015d3b000 offset: 1a000 load_base: 0 flags: 3 name: /system/lib64/libunwind.so
+map: start: 7015d3b000 end: 7015da4000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: 7015de8000 end: 7015df7000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libbase.so
+map: start: 7015df7000 end: 7015df8000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 7015df8000 end: 7015df9000 offset: f000 load_base: 0 flags: 1 name: /system/lib64/libbase.so
+map: start: 7015df9000 end: 7015dfa000 offset: 10000 load_base: 0 flags: 3 name: /system/lib64/libbase.so
+map: start: 7015e35000 end: 7015e36000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
+map: start: 7015e4f000 end: 7015e50000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015f11000 end: 7015f13000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libnetd_client.so
+map: start: 7015f13000 end: 7015f14000 offset: 1000 load_base: 0 flags: 1 name: /system/lib64/libnetd_client.so
+map: start: 7015f14000 end: 7015f15000 offset: 2000 load_base: 0 flags: 3 name: /system/lib64/libnetd_client.so
+map: start: 7015f6c000 end: 7015f79000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7015f79000 end: 7015f99000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
+map: start: 7015f99000 end: 7015f9a000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015f9a000 end: 7015f9b000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015fa6000 end: 7015fa7000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fa8000 end: 7015fa9000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7015faf000 end: 7015fcf000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: 7015fcf000 end: 7015fd0000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fd0000 end: 7015fd1000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015fd1000 end: 7015fd2000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fd4000 end: 7015fd7000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7015fd7000 end: 7015fdb000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
+map: start: 7015fdb000 end: 7015fdc000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
+map: start: 7015fdc000 end: 7015fdd000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7015fdd000 end: 7015fde000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7015fde000 end: 7015ffe000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
+map: start: 7015ffe000 end: 701601e000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: 701601e000 end: 701601f000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 701601f000 end: 7016020000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 7016020000 end: 7016021000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7016021000 end: 7016022000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: 7016022000 end: 7016023000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_lob]
+map: start: 7016023000 end: 7016025000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7016025000 end: 7016026000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7016026000 end: 7016027000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7016027000 end: 7016028000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7016028000 end: 7016029000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
+map: start: 7016029000 end: 701602a000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 701602a000 end: 701602b000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
+map: start: 701602b000 end: 701602c000 offset: 0 load_base: 0 flags: 0 name: [anon:thread signal stack guard page]
+map: start: 701602c000 end: 7016030000 offset: 0 load_base: 0 flags: 3 name: [anon:thread signal stack]
+map: start: 7016030000 end: 7016031000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
+map: start: 7016031000 end: 7016033000 offset: 0 load_base: 0 flags: 5 name: [vdso]
+map: start: 7016033000 end: 70160dd000 offset: 0 load_base: 0 flags: 5 name: /system/bin/linker64
+map: start: 70160dd000 end: 70160e0000 offset: a9000 load_base: 0 flags: 1 name: /system/bin/linker64
+map: start: 70160e0000 end: 70160e1000 offset: ac000 load_base: 0 flags: 3 name: /system/bin/linker64
+map: start: 70160e1000 end: 70160e4000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 70160e4000 end: 70160e5000 offset: 0 load_base: 0 flags: 1 name: 
+map: start: 70160e5000 end: 70160e8000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_base: 0 flags: 3 name: [stack]
+registers: 4560 679a0b1670000000f3eb6d705500000090f56e7055000000000000000000000000206f705500000014e0677055000000d038bed87f0000004cde67705500000041000000000000001900000000000000c00f241470000000d3aec914588f4bcd0400000000000000e493af157000000090f56e7055000000060000000000000023c00b1670000000b1d1fd15700000003039bed87f000000c898041670000000304cbed87f000000b8130e1670000000303cbed87f000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000003003167000000001000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000033000000000000000300000000000000003303167000000008330316700000000000000006000000f8320316700000005839bed87f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000c84cbed87f000000e84cbed87f000000984dbed87f00000078170e167000000002fd0000000000001400000000000000ff8100000100000000000000000000000000000000000000000000000000000078145700000000000010000000000000902b000000000000bdd04058000000000000000000000000bdd04058000000000000000000000000ccb58a560000000042487408000000000000000000000000cc57041670000000004704167000000010c0fd157000000010c0fd157000000090c0fd15700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000002f48bed87f000000d3aec914588f4bcd2045bed87f0000002045bed87f0000002f48bed87f00000001000000000000002f000080000000005045bed87f0000000045bed87f000000c0a0c315700000006045bed87f0000006045bed87f000000010000000000000001000000000000000344bed87f00000001000000100000009c3fbed87f0000009b3fbed87f0000000344bed87f0000009a3fbed87f0000000100000000000000953fbed87f0000004344bed80100000001000000010000002c48bed87f0000000444bed87f0000004344bed80100000000000000000000000100000000000000b03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd000000000100000000000000000000000100000000000000f03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03fbed87f0000000000000000000000000000000000000000000000000000000000000000000000d3aec914588f4bcd08226f70550000000000000000000000000000000000000000000000000000001048bed87f0000008047bed87f0000006047bed87f000000e0ffffff80ffffff03000000000000000000000000000000891d6e7055000000d3aec914588f4bcd5047bed87f0000005047bed87f000000861d6e705500000003000000000000002f00008000000000f0a6ca15700000004047bed87f000000c0a0c31570000000891d6e7055000000d3aec914000000000100000000000000a047bed800000000f9006e70550000000100000000000000dc41bed87f000000db41bed87f0000004346bed87f000000da41bed87f0000000100000000000000d541bed87f00000001000000010000000100000001000000861d6e70550000004446bed87f0000002c42bed80300000000000000000000000100000000000000f041bed87f0000009b1e6e700100000000000000000000000000000000000000d3aec914588f4bcd8e1e6e70550000000d000000000000002f00008000000000f0a6ca15700000003048bed87f000000c0a0c31570000000661e6e700100000000000000000000002f000000000000001000000000000000e21e6e7055000000d3aec914588f4bcdb048bed87f000000b048bed87f000000e21e6e70550000002f000000000000002f00008000000000f0a6ca1570000000a048bed87f000000c0a0c315700000008e1e6e7055000000000000000000000022000000000000000000000000000000205827147000000022000000000000003c43bed87f0000003b43bed87f000000a347bed87f0000003a43bed87f00000001000000000000003543bed87f000000f048bed8010000000100000001000000dd1e6e7055000000a447bed87f0000008c43bed82f000000000000000000000001000000000000005043bed87f000000861d6e700300000000000000000000000000000000000000d3aec914588f4bcd721e6e7055000000f447bed87f000000981123141800000000000000000000000100000000000000a043bed87f000000861d6e70030000000000000000000000d042bed87f0000000000000000000000981123147000000098112314700000009811231470000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000504abed87f000000b049bed87f0000008049bed87f00000000000000000000004043bed87f0000000000000000000000991123147000000000000000000000008e1e6e70550000000d00000000000000a04abed87f000000000000000000000000000000000000000000000000000000504abed87f000000e049bed87f000000a049bed87f000000c8ffffff80ffffff591e6e70550000000d0000000000000098112314700000000000000000000000df1e6e7055000000010000000000000020582714700000002200000000000000f049bed87f000000c8ffffff80ffffff9811231470000000980023147000000098112314700000009811231470000000741e6e7055000000060000000000000009f12914700000000c00000000000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b149bed87f000000b149bed87f000000f049be317f000000f049bed87f000000f049bed87f000000b149bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000f149bed87f000000f049bed87f000000d3aec914588f4bcdfcb58a56000000006cbb687055000000160000000000000098112314700000009911231470000000991123147000000098112314700000009911231470000000fcb58a5600000000010000000000000000000000000000000100000000000000604a050000000000e845bed87f0000006048bed87f000000a046bed87f00000017000000000000002c48bed87f0000009046bed87f000000ac73c515700000009911231470000000d3aec914588f4bcd1048bed87f0000008047bed87f0000006047bed87f000000e8ffffff80ffffffffffffffffffffff99112314700000006148bed87f000000981123141500000008020000ffffffff6048bed87f000000160000000000000058112314700000001700000000000000a849bed87f0000000000000000000000284abed87f0000001700000000000000284abed87f000000284abed87f000000d249bed87f00000001000000000000009a112314700000001600000000000000284abed87f000000ffffffffffffffff284abed87f000000284abed87f000000284abed87f000000284abed87f0000001700000000000000ffffffffffffffff284abed87f000000284abed87f000000ff49bed87f000000284abed87f00000000000000000000000000000000000000d049bed87f000000d049bed87f000000004abed87f000000d049bed87f0000000100000000000000d049bed87f000000d049bed87f000000d049bed87f00000017000000000000000100000000000000ffffffffffffffff991123147000000001000000000000003448bed87f0000009911231470000000b0ca687055000000ffffffffffffffff010000000000000099112314700000007047bed87f000000d3aec914588f4bcdfcb58a56000000000100000000000000000000000000000050226f70550000000000000000000000b44b05000000000000102a1470000000861d6e70550000000300000000000000f0a6ca1570000000a047bed87f0000006c79c31570000000f048bed87f0000008048bed87f0000004048bed87f000000c8ffffff80ffffff0000000000000000d3aec914588f4bcdf849bed87f000000f0a6ca15700000000200000000000000085b0e1670000000e048bed87f0000002c6fc515700000009048bed87f000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a89912314700000000000000000000000e9216f70550000008991231470000000e449bed87f0000008991231470000000000000000000000000000000000000008891231470000000899123147000000089912314700000008891231470000000170000000000000088912314700000008891231470000000d3aec914588f4bcd899123147000000016000000000000000000000000000000e9216f705500000088912314700000008891231470000000889123147000000088912314700000008891231470000000f0a6ca15700000000049bed87f0000006c79c31570000000889123147000000088912314700000008891231470000000889123147000000088912314700000008891231470000000889123147000000089912314700000008991231470000000085b0e1670000000404abed87f0000002c6fc51570000000c80a6f7055000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a3b3325736d001b5b6d002c20776865726520002573203d202573000a526570650000000000000000000000000000000000000000000000008891231470000000000000000000000088912314700000008891231470000000889123147000000088912314700000000000000000000000889123147000000088912314700000008891231470000000470000000000000000502a1470000000d3aec914588f4bcdf05727147000000000b2221470000000604abed87f0000005c716c7055000000fcb58a56000000007c706c7055000000fcb58a5600000000ea4b050000000000
+stack: start: 7015fd3000 end: 7015fd7000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000004038bed87f000000b863fd1570000000b863fd1570000000b863fd1570000000ec59cf15700000001c000000150000000e000000070000003063fd15700000001c58cf1570000000b863fd1570000000ec59cf1570000000100000000c00000008000000040000006063fd15700000007c58cf1570000000b863fd1570000000ec59cf1570000000080000000600000004000000020000009063fd1570000000dc58cf1570000000b863fd1570000000ec59cf157000000004000000030000000200000001000000d063fd1570000000c459cf15700000000100000000000000144abed87f0000004038bed87f0000004038bed87f000000144abed87f000000d3aec914588f4bcd1064fd157000000074fd6770550000004038bed87f0000004038bed87f000000ec84c41570000000e484c41570000000c484c4157000000000000000000000004064fd15700000004015c01570000000b67e0000000000000000000000000000705a0e1670000000185b0e167000000000000000000000000000000000000000705a0e16700000000000000000000000b77e0000b67e000000000000550000000030fd157000000050340000000000000010000000000000000000000000000000b222147000000000102a14700000000000000000000000000000000000000040fd6770550000004038bed87f000000000000000000000000a0fa1570000000010000000000000000000000000000000000000000000000e864fd15700000005064fd1570000000000000000000000000000000000000000000000000000000d3aec914588f4bcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+function: start: 0 end: 7015cf5760 name: unknown_start
+function: start: 7015cf5760 end: 7015cf57cc name: test_level_four
+function: start: 7015cf57cc end: 7015cf582c name: test_level_three
+function: start: 7015cf582c end: 7015cf588c name: test_level_two
+function: start: 7015cf588c end: 7015cf58ec name: test_level_one
+function: start: 7015cf58ec end: 7015cf5968 name: test_recursive_call
+function: start: 7015cf5968 end: ffffffffffffffff name: test_get_context_and_wait
+function: start: ffffffffffffffff end: ffffffffffffffff name: unknown_end
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so b/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so
new file mode 100755
index 0000000..454b032
--- /dev/null
+++ b/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so b/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so
new file mode 100755
index 0000000..787f2cb
--- /dev/null
+++ b/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so b/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so
new file mode 100755
index 0000000..9340d98
--- /dev/null
+++ b/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata b/libbacktrace/testdata/arm/offline_testdata
new file mode 100644
index 0000000..43d305a
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata
@@ -0,0 +1,105 @@
+pid: 32232 tid: 32233
+map: start: aad19000 end: aad6c000 offset: 0 load_base: 0 flags: 5 name: /data/backtrace_test32
+map: start: aad6c000 end: aad6e000 offset: 52000 load_base: 0 flags: 1 name: /data/backtrace_test32
+map: start: aad6e000 end: aad6f000 offset: 54000 load_base: 0 flags: 3 name: /data/backtrace_test32
+map: start: e7380000 end: e7400000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e745f000 end: e7463000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libnetd_client.so
+map: start: e7463000 end: e7464000 offset: 3000 load_base: 0 flags: 1 name: /system/lib/libnetd_client.so
+map: start: e7464000 end: e7465000 offset: 4000 load_base: 0 flags: 3 name: /system/lib/libnetd_client.so
+map: start: e7480000 end: e7500000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e7558000 end: e756c000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libunwind.so
+map: start: e756c000 end: e756d000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e756d000 end: e756e000 offset: 14000 load_base: 0 flags: 1 name: /system/lib/libunwind.so
+map: start: e756e000 end: e756f000 offset: 15000 load_base: 0 flags: 3 name: /system/lib/libunwind.so
+map: start: e756f000 end: e75b5000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e75d4000 end: e75e1000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libbase.so
+map: start: e75e1000 end: e75e2000 offset: c000 load_base: 0 flags: 1 name: /system/lib/libbase.so
+map: start: e75e2000 end: e75e3000 offset: d000 load_base: 0 flags: 3 name: /system/lib/libbase.so
+map: start: e7600000 end: e7616000 offset: 0 load_base: 0 flags: 5 name: /system/lib/liblzma.so
+map: start: e7616000 end: e7617000 offset: 15000 load_base: 0 flags: 1 name: /system/lib/liblzma.so
+map: start: e7617000 end: e7618000 offset: 16000 load_base: 0 flags: 3 name: /system/lib/liblzma.so
+map: start: e7618000 end: e761d000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e7647000 end: e7656000 offset: 0 load_base: 0 flags: 5 name: /system/lib/liblog.so
+map: start: e7656000 end: e7657000 offset: e000 load_base: 0 flags: 1 name: /system/lib/liblog.so
+map: start: e7657000 end: e7658000 offset: f000 load_base: 0 flags: 3 name: /system/lib/liblog.so
+map: start: e7681000 end: e76a2000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libm.so
+map: start: e76a2000 end: e76a3000 offset: 20000 load_base: 0 flags: 1 name: /system/lib/libm.so
+map: start: e76a3000 end: e76a4000 offset: 21000 load_base: 0 flags: 3 name: /system/lib/libm.so
+map: start: e76eb000 end: e76ee000 offset: 0 load_base: 0 flags: 5 name: /data/libbacktrace_test.so
+map: start: e76ee000 end: e76ef000 offset: 2000 load_base: 0 flags: 1 name: /data/libbacktrace_test.so
+map: start: e76ef000 end: e76f0000 offset: 3000 load_base: 0 flags: 3 name: /data/libbacktrace_test.so
+map: start: e7712000 end: e771f000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libbacktrace.so
+map: start: e771f000 end: e7720000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e7720000 end: e7721000 offset: d000 load_base: 0 flags: 1 name: /system/lib/libbacktrace.so
+map: start: e7721000 end: e7722000 offset: e000 load_base: 0 flags: 3 name: /system/lib/libbacktrace.so
+map: start: e7761000 end: e7778000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libutils.so
+map: start: e7778000 end: e7779000 offset: 16000 load_base: 0 flags: 1 name: /system/lib/libutils.so
+map: start: e7779000 end: e777a000 offset: 17000 load_base: 0 flags: 3 name: /system/lib/libutils.so
+map: start: e77a5000 end: e782d000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libc.so
+map: start: e782d000 end: e7831000 offset: 87000 load_base: 0 flags: 1 name: /system/lib/libc.so
+map: start: e7831000 end: e7833000 offset: 8b000 load_base: 0 flags: 3 name: /system/lib/libc.so
+map: start: e7833000 end: e7834000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e7834000 end: e7835000 offset: 0 load_base: 0 flags: 1 name: [anon:.bss]
+map: start: e7835000 end: e783b000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e7845000 end: e8437000 offset: 0 load_base: 2b000 flags: 5 name: /system/lib/libLLVM.so
+map: start: e8437000 end: e8438000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e8438000 end: e848a000 offset: bf2000 load_base: 0 flags: 1 name: /system/lib/libLLVM.so
+map: start: e848a000 end: e848b000 offset: c44000 load_base: 0 flags: 3 name: /system/lib/libLLVM.so
+map: start: e848b000 end: e84a1000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e84eb000 end: e84f7000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libcutils.so
+map: start: e84f7000 end: e84f8000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e84f8000 end: e84f9000 offset: c000 load_base: 0 flags: 1 name: /system/lib/libcutils.so
+map: start: e84f9000 end: e84fa000 offset: d000 load_base: 0 flags: 3 name: /system/lib/libcutils.so
+map: start: e852e000 end: e85b3000 offset: 0 load_base: 2000 flags: 5 name: /system/lib/libc++.so
+map: start: e85b3000 end: e85b4000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e85b4000 end: e85b8000 offset: 85000 load_base: 0 flags: 1 name: /system/lib/libc++.so
+map: start: e85b8000 end: e85b9000 offset: 89000 load_base: 0 flags: 3 name: /system/lib/libc++.so
+map: start: e85b9000 end: e85ba000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
+map: start: e85ce000 end: e85cf000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
+map: start: e85e4000 end: e85e5000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e8607000 end: e8608000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e8680000 end: e8700000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e870d000 end: e8719000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: e8719000 end: e871b000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
+map: start: e871b000 end: e873b000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
+map: start: e873b000 end: e875b000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: e875b000 end: e875c000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e875c000 end: e875d000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
+map: start: e875d000 end: e875e000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
+map: start: e875e000 end: e875f000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e875f000 end: e877f000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
+map: start: e877f000 end: e879f000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: e879f000 end: e87a0000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a0000 end: e87a1000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87a1000 end: e87a2000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a2000 end: e87a3000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e87a3000 end: e87a4000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: e87a4000 end: e87a5000 offset: 0 load_base: 0 flags: 0 name: 
+map: start: e87a5000 end: e87a6000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_lob]
+map: start: e87a6000 end: e87a7000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e87a7000 end: e87a8000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a8000 end: e87a9000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87a9000 end: e87aa000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87aa000 end: e87ab000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87ab000 end: e87ac000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
+map: start: e87ac000 end: e87ad000 offset: 0 load_base: 0 flags: 0 name: [anon:thread signal stack guard page]
+map: start: e87ad000 end: e87af000 offset: 0 load_base: 0 flags: 3 name: [anon:thread signal stack]
+map: start: e87af000 end: e87b0000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
+map: start: e87b0000 end: e880d000 offset: 0 load_base: 0 flags: 5 name: /system/bin/linker
+map: start: e880d000 end: e880f000 offset: 5c000 load_base: 0 flags: 1 name: /system/bin/linker
+map: start: e880f000 end: e8810000 offset: 5e000 load_base: 0 flags: 3 name: /system/bin/linker
+map: start: e8810000 end: e8812000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: e8812000 end: e8813000 offset: 0 load_base: 0 flags: 1 name: 
+map: start: e8813000 end: e8815000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: ff886000 end: ff8a9000 offset: 0 load_base: 0 flags: 3 name: [stack]
+map: start: ffff0000 end: ffff1000 offset: 0 load_base: 0 flags: 5 name: [vectors]
+registers: 64 34868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee7
+stack: start: e8715000 end: e8719000 size: 16384 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc8871e87dba6ee734868affdc8871e8dc8871e85dba6ee7070000000e000000150000001c000000dc8871e85dba6ee71c000000150000000e00000007000000100000000c0000000800000004000000ddb86ee75dba6ee7dc8871e804000000080000000c00000010000000dc8871e85dba6ee7100000000c000000080000000400000008000000060000000400000002000000288871e835b96ee75dba6ee7dc8871e802000000040000000600000008000000dc8871e85dba6ee70800000006000000040000000200000004000000030000000200000001000000708871e88db96ee75dba6ee7dc8871e801000000020000000300000004000000dc8871e85dba6ee70400000003000000020000000100000004000000208971e8208971e878000000e87d00003dba6ee75dba6ee7dc8871e878000000c5807ce7fc7183e734868aff78868aff78868aff34868aff34868aff78868affe0879437208971e84154d2aa0020000034868aff34868aff34868aff78000000c9b87ee7b1b87ee7a3f47be7288971e8b1b87ee7208971e800000000f83481e800000000e97d0000e87d000000000000005071e82039000000100000000000000000000000000000000000002354d2aa34868aff00000000002071e801000000000000000000000000000000708971e8208971e8000000000000000000000000e0879437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+function: start: 0 end: e76eb835 name: unknown_start
+function: start: e76eb835 end: e76eb88d name: test_level_four
+function: start: e76eb88d end: e76eb8e5 name: test_level_three
+function: start: e76eb8e5 end: e76eb93d name: test_level_two
+function: start: e76eb93d end: e76eb995 name: test_level_one
+function: start: e76eb995 end: e76eb9f1 name: test_recursive_call
+function: start: e76eb9f1 end: ffffffff name: test_get_context_and_wait
+function: start: ffffffff end: ffffffff name: unknown_end
diff --git a/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so b/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so
new file mode 100755
index 0000000..a6f3b29
--- /dev/null
+++ b/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so
Binary files differ
diff --git a/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so b/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so
new file mode 100755
index 0000000..ea58dfb
--- /dev/null
+++ b/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so
Binary files differ
diff --git a/libbacktrace/testdata/x86/offline_testdata b/libbacktrace/testdata/x86/offline_testdata
new file mode 100644
index 0000000..3e4e06c
--- /dev/null
+++ b/libbacktrace/testdata/x86/offline_testdata
@@ -0,0 +1,82 @@
+pid: 34545 tid: 34546
+map: start: f705a000 end: f705c000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f705c000 end: f707f000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f707f000 end: f7080000 offset: 22000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f7080000 end: f7081000 offset: 23000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f7081000 end: f7088000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7088000 end: f7230000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7230000 end: f7231000 offset: 1a8000 load_base: 0 flags: 0 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7231000 end: f7233000 offset: 1a8000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7233000 end: f7234000 offset: 1aa000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7234000 end: f7237000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7237000 end: f727b000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727b000 end: f727c000 offset: 43000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727c000 end: f727d000 offset: 44000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727d000 end: f7299000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libgcc_s.so.1
+map: start: f7299000 end: f729a000 offset: 1b000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libgcc_s.so.1
+map: start: f729a000 end: f72b8000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72b8000 end: f72b9000 offset: 1e000 load_base: 0 flags: 0 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72b9000 end: f72bb000 offset: 1e000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72bb000 end: f72bc000 offset: 20000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72bc000 end: f72bd000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f72bd000 end: f72e0000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e0000 end: f72e1000 offset: 22000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e1000 end: f72e2000 offset: 23000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e2000 end: f72e5000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e5000 end: f72e6000 offset: 2000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e6000 end: f72e7000 offset: 3000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e7000 end: f72ee000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72ee000 end: f72ef000 offset: 6000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72ef000 end: f72f0000 offset: 7000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72f0000 end: f7308000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f7308000 end: f7309000 offset: 18000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f7309000 end: f730a000 offset: 19000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f730a000 end: f730c000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f732f000 end: f7331000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7331000 end: f7425000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f7425000 end: f7426000 offset: f4000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f7426000 end: f742a000 offset: f4000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f742a000 end: f742b000 offset: f8000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f742b000 end: f742d000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f742d000 end: f7446000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7446000 end: f7447000 offset: 18000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7447000 end: f7448000 offset: 19000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7448000 end: f7457000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7457000 end: f745c000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745c000 end: f745d000 offset: 4000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745d000 end: f745e000 offset: 5000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745e000 end: f7467000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7467000 end: f7468000 offset: 9000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7468000 end: f7469000 offset: 9000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7469000 end: f746a000 offset: a000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f746a000 end: f7477000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7477000 end: f7478000 offset: c000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7478000 end: f7479000 offset: d000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7479000 end: f7489000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f7489000 end: f748a000 offset: f000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f748a000 end: f748b000 offset: 10000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f748b000 end: f748c000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f748c000 end: f748d000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748d000 end: f748e000 offset: 0 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748e000 end: f748f000 offset: 1000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748f000 end: f7491000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7491000 end: f74b1000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b1000 end: f74b2000 offset: 1f000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b2000 end: f74b3000 offset: 20000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b3000 end: f77c6000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77c6000 end: f77c7000 offset: 0 load_base: ffffe000 flags: 5 name: [vdso]
+map: start: f77c7000 end: f77d4000 offset: 313000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77d4000 end: f77d5000 offset: 320000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77d5000 end: f77d6000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: f7ec6000 end: f7ee7000 offset: 0 load_base: 0 flags: 3 name: [heap]
+map: start: ffe4e000 end: ffe70000 offset: 0 load_base: 0 flags: 3 name: [stack]
+registers: 348 00000000abdae6fff83b7df704000000a6ec77f7abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000008c8decf78c8decf7ceca48f7a8dae6ff8d8decf70a0000000000000014dae6ff8c8decf78c8decf78c8decf78c8decf78c8decf7a9dae6ff06000000c03a23f78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78d8decf78d8decf7c03a23f7543b23f7000033f75f5f0ff7c03a23f7503423f77000000098000000020000000f2700006c0000000e00000080000000000000008c8decf7000000008c8decf77f03ffff0000ffffffffffff0000000000000000000000000000ffff040000000f27000008000000003023f78d8decf7f069ec000046bdaa308decf715537df7f83b7df78c8decf74c1c71f78c8decf715537df70000000000000000f069ecf7f83b7df75064ecf792e671f7f069ecf7
+stack: start: f732c000 end: f7330000 size: 16384 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d9d49f761b009f71e382ff7000000000000000000000000000000000000000002000000f6372ff704c82bf70000000000204bf7f0a908f7ceca48f728d9e6fff4a449f70000000020f332f720f332f7d0df48f7f8f132f794c748f720f332f70c144205978142a8d4be08f7d0df48f720f332f7a0ca48f71c000000150000000e000000070000001c000000a0ca48f7d0df48f748f232f739c848f7070000000e000000150000001c000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7100000000c000000080000000400000010000000a0ca48f7d0df48f798f232f7c9c848f704000000080000000c00000010000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f70800000006000000040000000200000008000000a0ca48f7d0df48f7e8f232f759c948f702000000040000000600000008000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7040000000300000002000000010000000046bdaa00000000d0df48f738f332f77cca48f701000000020000000300000004000000a0ca48f720f332f700000000f83b7df7696d4df7d0df48f788dae6ff28d9e6ff28d9e6ff88dae6ff58f332f70046bdaa40fb32f7f83b7df758f332f78d6d4df728d9e6ff88dae6fff83b7df728d9e6ff28d9e6ff009030f728f432f7726f2ff728d9e6ff40fb32f740fb32f740fb32f790f332f700000000000000000000000000000000000000000000000000000000009030f740fb32f7000f3d0028f432f703b12c75032f144e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a06e2ff700000000000f3d00000000008e3f17f740fb32f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03823f7c4fd32f700000000e0341df7e02e1df7e03d1df70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040fb32f7188eecf740fb32f70100000030647cf70046bdaa28658876000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060a705f7a4b130f7f2860000f1860000b0fb32f7ecffffff000000000000000090f332f7000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccfb32f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c2638cfa7f3e1d0000000000000000000000000000000000406d4df728d9e6ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c032f7004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+function: start: 0 end: f748c740 name: unknown_start
+function: start: f748c740 end: f748c7c0 name: test_level_four
+function: start: f748c7c0 end: f748c850 name: test_level_three
+function: start: f748c850 end: f748c8e0 name: test_level_two
+function: start: f748c8e0 end: f748c970 name: test_level_one
+function: start: f748c970 end: f748ca10 name: test_recursive_call
+function: start: f748ca10 end: ffffffff name: test_get_context_and_wait
+function: start: ffffffff end: ffffffff name: unknown_end
diff --git a/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so b/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so
new file mode 100755
index 0000000..f116658
--- /dev/null
+++ b/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so
Binary files differ
diff --git a/libbacktrace/testdata/x86_64/offline_testdata b/libbacktrace/testdata/x86_64/offline_testdata
new file mode 100644
index 0000000..baf6450
--- /dev/null
+++ b/libbacktrace/testdata/x86_64/offline_testdata
@@ -0,0 +1,93 @@
+pid: 25683 tid: 25692
+map: start: 7fd5aa784000 end: 7fd5aa93e000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aa93e000 end: 7fd5aab3e000 offset: 1ba000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab3e000 end: 7fd5aab42000 offset: 1ba000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab42000 end: 7fd5aab44000 offset: 1be000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab44000 end: 7fd5aab49000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5aab49000 end: 7fd5aac4e000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aac4e000 end: 7fd5aae4d000 offset: 105000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4d000 end: 7fd5aae4e000 offset: 104000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4e000 end: 7fd5aae4f000 offset: 105000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4f000 end: 7fd5aae65000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5aae65000 end: 7fd5ab064000 offset: 16000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5ab064000 end: 7fd5ab065000 offset: 15000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5ab065000 end: 7fd5ab08a000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab08a000 end: 7fd5ab289000 offset: 25000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab289000 end: 7fd5ab28d000 offset: 24000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab28d000 end: 7fd5ab28e000 offset: 28000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab28e000 end: 7fd5ab2b0000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab2b0000 end: 7fd5ab4af000 offset: 22000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4af000 end: 7fd5ab4b0000 offset: 21000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4b0000 end: 7fd5ab4b1000 offset: 22000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4b1000 end: 7fd5ab4b4000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab4b4000 end: 7fd5ab6b3000 offset: 3000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b3000 end: 7fd5ab6b4000 offset: 2000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b4000 end: 7fd5ab6b5000 offset: 3000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b5000 end: 7fd5ab6bc000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab6bc000 end: 7fd5ab8bb000 offset: 7000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bb000 end: 7fd5ab8bc000 offset: 6000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bc000 end: 7fd5ab8bd000 offset: 7000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bd000 end: 7fd5ab8d6000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5ab8d6000 end: 7fd5abad5000 offset: 19000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad5000 end: 7fd5abad6000 offset: 18000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad6000 end: 7fd5abad7000 offset: 19000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad7000 end: 7fd5abadb000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abadb000 end: 7fd5abafe000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abb17000 end: 7fd5abb1a000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abb1a000 end: 7fd5abb40000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb40000 end: 7fd5abb41000 offset: 25000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb41000 end: 7fd5abb42000 offset: 26000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb42000 end: 7fd5abb4b000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abb6a000 end: 7fd5abb70000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abb70000 end: 7fd5abc62000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc62000 end: 7fd5abc63000 offset: f2000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc63000 end: 7fd5abc6b000 offset: f2000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc6b000 end: 7fd5abc6c000 offset: fa000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc6c000 end: 7fd5abc70000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abc70000 end: 7fd5abc8d000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8d000 end: 7fd5abc8e000 offset: 1c000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8e000 end: 7fd5abc8f000 offset: 1d000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8f000 end: 7fd5abcb8000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abcb8000 end: 7fd5abcbe000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcbe000 end: 7fd5abcbf000 offset: 6000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcbf000 end: 7fd5abcc0000 offset: 6000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcc0000 end: 7fd5abcc1000 offset: 7000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcc1000 end: 7fd5abcc2000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abcc2000 end: 7fd5abccd000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abccd000 end: 7fd5abcce000 offset: b000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abcce000 end: 7fd5abccf000 offset: b000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abccf000 end: 7fd5abcd0000 offset: c000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abcd0000 end: 7fd5abcdf000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abcdf000 end: 7fd5abce0000 offset: f000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce0000 end: 7fd5abce1000 offset: f000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce1000 end: 7fd5abce2000 offset: 10000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce2000 end: 7fd5abcf5000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf5000 end: 7fd5abcf6000 offset: 12000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf6000 end: 7fd5abcf7000 offset: 13000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf7000 end: 7fd5abcf8000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcf8000 end: 7fd5abcf9000 offset: 1000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcf9000 end: 7fd5abcfa000 offset: 1000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcfa000 end: 7fd5abcfb000 offset: 2000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcfb000 end: 7fd5abcfd000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abcfd000 end: 7fd5abcfe000 offset: 22000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abcfe000 end: 7fd5abcff000 offset: 23000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abcff000 end: 7fd5abd00000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5abd00000 end: 7fd5ac053000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac053000 end: 7fd5ac054000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5ac054000 end: 7fd5ac06f000 offset: 353000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac06f000 end: 7fd5ac070000 offset: 36e000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac070000 end: 7fd5ac071000 offset: 0 load_base: 0 flags: 3 name: 
+map: start: 7fd5ad54e000 end: 7fd5ad56f000 offset: 0 load_base: 0 flags: 3 name: [heap]
+map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_base: 0 flags: 3 name: [stack]
+map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_base: ffffffffff700000 flags: 5 name: [vdso]
+map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_base: 0 flags: 5 name: [vsyscall]
+registers: 936 010000000000000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f0000b92455add57f0000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000a0b180f4fc7f000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f000078b480f4fc7f000078b480f4fc7f00007f03ffff0000ffffffffffff000000000000000000000000801f0000fc7f000078b480f4fc7f000060b280f4fc7f000000006a80f3f73cf110b480f4fc7f0000de66d6abd57f00000000000000000000000000000000000000006a80f3f73cf128b480f4fc7f0000782455add57f0000fd96d6abd57f0000092555add57f0000000000000000000057b480f4fc7f0000092555add57f000060b480f4fc7f00006994d6abd57f0000b0e0c6abd57f000071b280f4fc7f000070b280f4fc7f0000256c640000000000a8b180f4fc7f000090b480f4fc7f0000082555add57f0000092555add57f0000092555add57f0000082555add57f00001700000000000000082555add57f0000082555add57f0000f93cfcabd57f0000092555add57f000016000000000000000000000000000000090c07acd57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f000010b380f4fc7f000078b480f4fc7f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000092555add57f0000092555add57f0000b92455add57f000028b480f4fc7f0000c800000000000000014c7f0b0380ffff0d000000fc7f0000030000000000000033000000d57f000000b480f4fc7f00000000000000000000a0e154ad5b000000000000000000000000000000000000006e000000770000000000000000000000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f00006027b4aad57f0000c800000000000000a0e154add57f0000c0e354add57f0000092555add57f000000006a80f3f73cf1e0e054add57f0000e0e554add57f0000d14df6abd57f0000
+stack: start: 7fd5abb6b000 end: 7fd5abb6f000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c4eaeabd57f00000000000000000000978142a8000000000f0000000000000012000000000000003888b4abd57f0000e657aeabd57f00000000000000000000a0dcb6abd57f0000307d78aad57f0000b0ddb6abd57f000028d978aad57f0000060aa10200000000a0ddb6abd57f0000000000000000000000000000000000002091b1abd57f0000e094b4abd57f000017008cabd57f0000c84d79aad57f000028e28babd57f00000000000005000000d503000001000000000000000000000068deb6abd57f000040deb6abd57f00002091b1abd57f00000100000000000000e0f3c6abd57f000088f0c6abd57f00006159aeabd57f000000000000000000002091b1abd57f000005000000000000000000000000000000010000000000000088f0c6abd57f00000000000000000000d07bcfabd57f00000000000000000000000000000000000098deb6abd57f000098deb6abd57f0000b0ddb6abd57f00006179cfabd57f000098deb6abd57f0000b07bcfabd57f00001c000000150000000e00000007000000f0ddb6abd57f0000e179cfabd57f00000000000000000000150000001c00000098deb6abd57f0000b07bcfabd57f0000100000000c000000080000000400000030deb6abd57f0000417acfabd57f000000000000000000000c0000001000000098deb6abd57f0000b07bcfabd57f00000800000006000000040000000200000070deb6abd57f0000a17acfabd57f00000000000000000000060000000800000098deb6abd57f0000b07bcfabd57f000004000000030000000200000001000000b0deb6abd57f0000817bcfabd57f0000000000000000000074b480f4fc7f0000c8b080f4fc7f0000c8b080f4fc7f000074b480f4fc7f000000006a80f3f73cf1d0deb6abd57f00002a52d5abd57f0000c8b080f4fc7f0000c8b080f4fc7f0000000000000000000084518cabd57f0000000000000000000000e7b6abd57f000000e7b6abd57f00008f990b1e3bad5a6700000000000000000000000000000000c0e354add57f000000e7b6abd57f00008f99cba356faf1988f9991bc23faf1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f00007de387aad57f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006030b4aad57f0000b8edb6abd57f00000000000000000000000000000000000080b88eaad57f0000000000000000000080b28eaad57f0000000000000000000080c18eaad57f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f0000402555add57f000000e7b6abd57f00000100000000000000000000000000000000006a80f3f73cf1058f9d56adb3c7cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407ab1abd57f000030a3adabd57f00005c64000053640000e0e9b6abd57f0000e0e9b6abd57f0000e0ffffffffffffff00000000000000000000000000000000f0deb6abd57f00000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010eab6abd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c46ad90f52391d00000000000000000000000000000000000000000000000000f051d5abd57f0000c8b080f4fc7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b6abd57f000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+function: start: 0 end: 7fd5abcf7930 name: unknown_start
+function: start: 7fd5abcf7930 end: 7fd5abcf7990 name: test_level_four
+function: start: 7fd5abcf7990 end: 7fd5abcf79f0 name: test_level_three
+function: start: 7fd5abcf79f0 end: 7fd5abcf7a50 name: test_level_two
+function: start: 7fd5abcf7a50 end: 7fd5abcf7ab0 name: test_level_one
+function: start: 7fd5abcf7ab0 end: 7fd5abcf7b30 name: test_recursive_call
+function: start: 7fd5abcf7b30 end: ffffffffffffffff name: test_get_context_and_wait
+function: start: ffffffffffffffff end: ffffffffffffffff name: unknown_end
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index f7b497d..39f8aba 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,6 +18,7 @@
 // they correspond to features not used by our host development tools
 // which are also hard or even impossible to port to native Win32
 libcutils_nonwindows_sources = [
+    "android_get_control_file.cpp",
     "fs.c",
     "multiuser.c",
     "socket_inaddr_any_server_unix.c",
@@ -34,7 +35,6 @@
     host_supported: true,
     srcs: [
         "config_utils.c",
-        "files.cpp",
         "fs_config.c",
         "canned_fs_config.c",
         "hashmap.c",
diff --git a/include/cutils/files.h b/libcutils/android_get_control_env.h
similarity index 63%
copy from include/cutils/files.h
copy to libcutils/android_get_control_env.h
index 0210e30..638c831 100644
--- a/include/cutils/files.h
+++ b/libcutils/android_get_control_env.h
@@ -14,24 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_FILES_H
-#define __CUTILS_FILES_H
+#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
 
-#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+/* To declare library function hidden and internal */
+#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/*
- * android_get_control_file - simple helper function to get the file
- * descriptor of our init-managed file. `path' is the filename path as
- * given in init.rc. Returns -1 on error.
- */
-int android_get_control_file(const char* path);
-
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name);
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* __CUTILS_FILES_H */
+#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
diff --git a/libcutils/files.cpp b/libcutils/android_get_control_file.cpp
similarity index 74%
rename from libcutils/files.cpp
rename to libcutils/android_get_control_file.cpp
index bf15b42..780d9f1 100644
--- a/libcutils/files.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -25,11 +25,6 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
-// This file contains files implementation that can be shared between
-// platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // for asprintf
-
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -41,17 +36,20 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
 
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
 #endif
 
-int android_get_control_file(const char* path) {
-    if (!path) return -1;
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name) {
+    if (!prefix || !name) return -1;
 
     char *key = NULL;
-    if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1;
+    if (asprintf(&key, "%s%s", prefix, name) < 0) return -1;
     if (!key) return -1;
 
     char *cp = key;
@@ -70,29 +68,33 @@
 
     // validity checking
     if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
-    if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
-    if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
-    if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
 
-#if defined(F_GETFD)
+    // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
+
+    // Still open?
+#if defined(F_GETFD) // Lowest overhead
     if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
+#elif defined(F_GETFL) // Alternate lowest overhead
     if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
+#else // Hail Mary pass
     struct stat s;
     if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
 #endif
 
+    return static_cast<int>(fd);
+}
+
+int android_get_control_file(const char* path) {
+    int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+
 #if defined(__linux__)
+    // Find file path from /proc and make sure it is correct
     char *proc = NULL;
-    if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
+    if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
     if (!proc) return -1;
 
     size_t len = strlen(path);
+    // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
     char *buf = static_cast<char *>(calloc(1, len + 2));
     if (!buf) {
         free(proc);
@@ -104,8 +106,8 @@
     free(buf);
     if (ret < 0) return -1;
     if (cmp != 0) return -1;
+    // It is what we think it is
 #endif
 
-    // It is what we think it is
-    return static_cast<int>(fd);
+    return fd;
 }
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index af7e189..159a9d4 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -42,24 +42,6 @@
     struct mntent entry;
 } mntent_list;
 
-static bool has_mount_option(const char* opts, const char* opt_to_find)
-{
-  bool ret = false;
-  char* copy = NULL;
-  char* opt;
-  char* rem;
-
-  while ((opt = strtok_r(copy ? NULL : (copy = strdup(opts)), ",", &rem))) {
-      if (!strcmp(opt, opt_to_find)) {
-          ret = true;
-          break;
-      }
-  }
-
-  free(copy);
-  return ret;
-}
-
 static bool is_block_device(const char* fsname)
 {
     return !strncmp(fsname, "/dev/block", 10);
@@ -78,8 +60,7 @@
         return;
     }
     while ((mentry = getmntent(fp)) != NULL) {
-        if (is_block_device(mentry->mnt_fsname) &&
-            has_mount_option(mentry->mnt_opts, "rw")) {
+        if (is_block_device(mentry->mnt_fsname) && hasmntopt(mentry, "rw")) {
             mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
             item->entry = *mentry;
             item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
@@ -170,8 +151,7 @@
             goto out;
         }
         while ((mentry = getmntent(fp)) != NULL) {
-            if (!is_block_device(mentry->mnt_fsname) ||
-                !has_mount_option(mentry->mnt_opts, "ro")) {
+            if (!is_block_device(mentry->mnt_fsname) || !hasmntopt(mentry, "ro")) {
                 continue;
             }
             mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 60a389b..032e361 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -91,6 +91,7 @@
     { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
     { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
     { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
+    { 00775, AID_ROOT,   AID_ROOT,   0, "data/preloads" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
     { 00755, AID_ROOT,   AID_SYSTEM, 0, "mnt" },
     { 00755, AID_ROOT,   AID_ROOT,   0, "root" },
@@ -149,6 +150,9 @@
     { 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" },
+
     /* Support hostapd administering a network interface. */
     { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
                                            CAP_MASK_LONG(CAP_NET_RAW),
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 9d823cf..4bad28a 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,7 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/files.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 
 static int klog_level = KLOG_DEFAULT_LEVEL;
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 0f4427b..0ef337d 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -15,21 +15,36 @@
  */
 
 #include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
 
 userid_t multiuser_get_user_id(uid_t uid) {
-    return uid / MULTIUSER_APP_PER_USER_RANGE;
+    return uid / AID_USER_OFFSET;
 }
 
 appid_t multiuser_get_app_id(uid_t uid) {
-    return uid % MULTIUSER_APP_PER_USER_RANGE;
+    return uid % AID_USER_OFFSET;
 }
 
-uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
-    return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
+uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) {
+    return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
 }
 
-appid_t multiuser_get_shared_app_gid(uid_t id) {
-  return MULTIUSER_FIRST_SHARED_APPLICATION_GID + (id % MULTIUSER_APP_PER_USER_RANGE)
-          - MULTIUSER_FIRST_APPLICATION_UID;
+gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) {
+    if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+        return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START);
+    } else {
+        return -1;
+    }
+}
 
+gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id) {
+    if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+        return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_SHARED_GID_START);
+    } else {
+        return -1;
+    }
+}
+
+gid_t multiuser_get_shared_app_gid(uid_t uid) {
+    return multiuser_get_shared_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid));
 }
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index cab9263..5c5f3a5 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -64,9 +64,12 @@
 static int bg_cpuset_fd = -1;
 static int fg_cpuset_fd = -1;
 static int ta_cpuset_fd = -1; // special cpuset for top app
+#endif
+
+// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
 static int bg_schedboost_fd = -1;
 static int fg_schedboost_fd = -1;
-#endif
+static int ta_schedboost_fd = -1;
 
 /* Add tid to the scheduling group defined by the policy */
 static int add_tid_to_cgroup(int tid, int fd)
@@ -136,9 +139,11 @@
         ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
 
 #ifdef USE_SCHEDBOOST
+        filename = "/dev/stune/top-app/tasks";
+        ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/stune/foreground/tasks";
         fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        filename = "/dev/stune/tasks";
+        filename = "/dev/stune/background/tasks";
         bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
 #endif
     }
@@ -300,11 +305,10 @@
         break;
     case SP_TOP_APP :
         fd = ta_cpuset_fd;
-        boost_fd = fg_schedboost_fd;
+        boost_fd = ta_schedboost_fd;
         break;
     case SP_SYSTEM:
         fd = system_bg_cpuset_fd;
-        boost_fd = bg_schedboost_fd;
         break;
     default:
         boost_fd = fd = -1;
@@ -316,10 +320,12 @@
             return -errno;
     }
 
+#ifdef USE_SCHEDBOOST
     if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
         if (errno != ESRCH && errno != ENOENT)
             return -errno;
     }
+#endif
 
     return 0;
 #endif
@@ -391,19 +397,26 @@
 #endif
 
     if (__sys_supports_schedgroups) {
-        int fd;
+        int fd = -1;
+        int boost_fd = -1;
         switch (policy) {
         case SP_BACKGROUND:
             fd = bg_cgroup_fd;
+            boost_fd = bg_schedboost_fd;
             break;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
+            fd = fg_cgroup_fd;
+            boost_fd = fg_schedboost_fd;
+            break;
         case SP_TOP_APP:
             fd = fg_cgroup_fd;
+            boost_fd = ta_schedboost_fd;
             break;
         default:
             fd = -1;
+            boost_fd = -1;
             break;
         }
 
@@ -412,6 +425,13 @@
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
+
+#ifdef USE_SCHEDBOOST
+        if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+            if (errno != ESRCH && errno != ENOENT)
+                return -errno;
+        }
+#endif
     } else {
         struct sched_param param;
 
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index 63761a2..23a447b 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -28,33 +28,9 @@
 
 // This file contains socket implementation that can be shared between
 // platforms as long as the correct headers are included.
-#define _GNU_SOURCE 1 // For asprintf
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#if !defined(_WIN32)
-#include <netinet/in.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#if !defined(_WIN32)
-#include <sys/un.h>
-#endif
-#include <unistd.h>
-
-#include <string>
 
 #include <cutils/sockets.h>
 
-#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
-#define TEMP_FAILURE_RETRY(exp) (exp)
-#endif
-
 int socket_get_local_port(cutils_socket_t sock) {
     sockaddr_storage addr;
     socklen_t addr_size = sizeof(addr);
@@ -65,58 +41,3 @@
     }
     return -1;
 }
-
-int android_get_control_socket(const char* name) {
-    char *key = NULL;
-    if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1;
-    if (!key) return -1;
-
-    char *cp = key;
-    while (*cp) {
-        if (!isalnum(*cp)) *cp = '_';
-        ++cp;
-    }
-
-    const char* val = getenv(key);
-    free(key);
-    if (!val) return -1;
-
-    errno = 0;
-    long fd = strtol(val, NULL, 10);
-    if (errno) return -1;
-
-    // validity checking
-    if ((fd < 0) || (fd > INT_MAX)) return -1;
-#if defined(_SC_OPEN_MAX)
-    if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
-#elif defined(OPEN_MAX)
-    if (fd >= OPEN_MAX) return -1;
-#elif defined(_POSIX_OPEN_MAX)
-    if (fd >= _POSIX_OPEN_MAX) return -1;
-#endif
-
-#if defined(F_GETFD)
-    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL)
-    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else
-    struct stat s;
-    if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
-#endif
-
-#if !defined(_WIN32)
-    struct sockaddr_un addr;
-    socklen_t addrlen = sizeof(addr);
-    int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
-    if (ret < 0) return -1;
-    char *path = NULL;
-    if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1;
-    if (!path) return -1;
-    int cmp = strcmp(addr.sun_path, path);
-    free(path);
-    if (cmp != 0) return -1;
-#endif
-
-    // It is what we think it is
-    return static_cast<int>(fd);
-}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 3545403..5a14a5c 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -16,13 +16,25 @@
 
 #define LOG_TAG "socket-unix"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
 #include <sys/uio.h>
+#include <sys/un.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <android/log.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
+
 #if defined(__ANDROID__)
 /* For the socket trust (credentials) check */
 #include <private/android_filesystem_config.h>
@@ -80,3 +92,24 @@
 
     return writev(sock, iovec_buffers, num_buffers);
 }
+
+int android_get_control_socket(const char* name) {
+    int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
+
+    if (fd < 0) return fd;
+
+    // Compare to UNIX domain socket name, must match!
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+    int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+    if (ret < 0) return -1;
+    char *path = NULL;
+    if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
+    if (!path) return -1;
+    int cmp = strcmp(addr.sun_path, path);
+    free(path);
+    if (cmp != 0) return -1;
+
+    // It is what we think it is
+    return fd;
+}
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index ed6b1a7..3064c70 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -84,3 +84,7 @@
 
     return -1;
 }
+
+int android_get_control_socket(const char* name) {
+    return -1;
+}
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index bd35412..0b0dc09 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -14,7 +14,7 @@
 
 cc_defaults {
     name: "libcutils_test_default",
-    srcs: ["sockets_test.cpp", "files_test.cpp"],
+    srcs: ["sockets_test.cpp"],
 
     target: {
         android: {
@@ -24,11 +24,17 @@
                 "PropertiesTest.cpp",
                 "sched_policy_test.cpp",
                 "trace-dev_test.cpp",
+                "test_str_parms.cpp",
+                "android_get_control_socket_test.cpp",
+                "android_get_control_file_test.cpp",
+                "multiuser_test.cpp"
             ],
         },
 
         not_windows: {
-            srcs: ["test_str_parms.cpp"],
+            srcs: [
+                "test_str_parms.cpp",
+            ],
         },
     },
 
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
new file mode 100644
index 0000000..6c6fd2a
--- /dev/null
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
+#include <gtest/gtest.h>
+
+TEST(FilesTest, android_get_control_file) {
+    TemporaryFile tf;
+    ASSERT_GE(tf.fd, 0);
+
+    std::string key(ANDROID_FILE_ENV_PREFIX);
+    key += tf.path;
+
+    std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+
+    EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+
+    EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+    close(tf.fd);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+}
diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/tests/android_get_control_socket_test.cpp
new file mode 100644
index 0000000..e586748
--- /dev/null
+++ b/libcutils/tests/android_get_control_socket_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <cutils/sockets.h>
+#include <gtest/gtest.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+TEST(SocketsTest, android_get_control_socket) {
+    static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
+    static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
+
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    int fd;
+    ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
+#ifdef F_GETFL
+    int flags;
+    ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
+    ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
+#endif
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    struct sockaddr_un addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
+    unlink(addr.sun_path);
+
+    EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    char val[32];
+    snprintf(val, sizeof(val), "%d", fd);
+    EXPECT_EQ(setenv(key, val, true), 0);
+
+    EXPECT_EQ(android_get_control_socket(name), fd);
+    socket_close(fd);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unlink(addr.sun_path), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+}
diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/files_test.cpp
deleted file mode 100644
index 1a7d673..0000000
--- a/libcutils/tests/files_test.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <cutils/files.h>
-#include <gtest/gtest.h>
-
-TEST(FilesTest, android_get_control_file) {
-    static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg";
-    static const char name[] = "/dev/kmsg";
-
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-
-    int fd;
-    ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-
-    char val[32];
-    snprintf(val, sizeof(val), "%d", fd);
-    EXPECT_EQ(setenv(key, val, true), 0);
-
-    EXPECT_EQ(android_get_control_file(name), fd);
-    close(fd);
-    EXPECT_EQ(android_get_control_file(name), -1);
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_file(name), -1);
-}
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
new file mode 100644
index 0000000..2307ea8
--- /dev/null
+++ b/libcutils/tests/multiuser_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 <cutils/multiuser.h>
+#include <gtest/gtest.h>
+
+TEST(MultiuserTest, TestMerge) {
+    EXPECT_EQ(0, multiuser_get_uid(0, 0));
+    EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
+    EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
+    EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
+    EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
+    EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
+    EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
+    EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+}
+
+TEST(MultiuserTest, TestSplitUser) {
+    EXPECT_EQ(0, multiuser_get_user_id(0));
+    EXPECT_EQ(0, multiuser_get_user_id(1000));
+    EXPECT_EQ(0, multiuser_get_user_id(10000));
+    EXPECT_EQ(0, multiuser_get_user_id(50000));
+    EXPECT_EQ(10, multiuser_get_user_id(1000000));
+    EXPECT_EQ(10, multiuser_get_user_id(1001000));
+    EXPECT_EQ(10, multiuser_get_user_id(1010000));
+    EXPECT_EQ(10, multiuser_get_user_id(1050000));
+}
+
+TEST(MultiuserTest, TestSplitApp) {
+    EXPECT_EQ(0, multiuser_get_app_id(0));
+    EXPECT_EQ(1000, multiuser_get_app_id(1000));
+    EXPECT_EQ(10000, multiuser_get_app_id(10000));
+    EXPECT_EQ(50000, multiuser_get_app_id(50000));
+    EXPECT_EQ(0, multiuser_get_app_id(1000000));
+    EXPECT_EQ(1000, multiuser_get_app_id(1001000));
+    EXPECT_EQ(10000, multiuser_get_app_id(1010000));
+    EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+}
+
+TEST(MultiuserTest, TestCache) {
+    EXPECT_EQ(-1, multiuser_get_cache_gid(0, 0));
+    EXPECT_EQ(-1, multiuser_get_cache_gid(0, 1000));
+    EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
+    EXPECT_EQ(-1, multiuser_get_cache_gid(0, 50000));
+    EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+}
+
+TEST(MultiuserTest, TestShared) {
+    EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
+    EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
+    EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
+    EXPECT_EQ(-1, multiuser_get_shared_gid(0, 50000));
+    EXPECT_EQ(1050000, multiuser_get_shared_gid(10, 10000));
+}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index adfbf4a..0441fb6 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,11 +18,9 @@
 // IPv6 capabilities. These tests assume that no UDP packets are lost, which
 // should be the case for loopback communication, but is not guaranteed.
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <sys/un.h>
 #include <time.h>
 
 #include <cutils/sockets.h>
@@ -189,49 +187,3 @@
 TEST(SocketsTest, TestSocketSendBuffersFailure) {
     EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
 }
-
-#ifndef SOCK_NONBLOCK
-#define SOCK_NONBLOCK 0
-#endif
-
-#ifndef SOCK_CLOEXEC
-#define SOCK_CLOEXEC 0
-#endif
-
-TEST(SocketsTest, android_get_control_socket) {
-    static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
-    static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
-
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    int fd;
-    ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
-#ifdef F_GETFL
-    int flags;
-    ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
-    ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
-#endif
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    struct sockaddr_un addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
-    unlink(addr.sun_path);
-
-    EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-
-    char val[32];
-    snprintf(val, sizeof(val), "%d", fd);
-    EXPECT_EQ(setenv(key, val, true), 0);
-
-    EXPECT_EQ(android_get_control_socket(name), fd);
-    socket_close(fd);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-    EXPECT_EQ(unlink(addr.sun_path), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-    EXPECT_EQ(unsetenv(key), 0);
-    EXPECT_EQ(android_get_control_socket(name), -1);
-}
diff --git a/libcutils/uevent.c b/libcutils/uevent.c
index de5d227..f548dca 100644
--- a/libcutils/uevent.c
+++ b/libcutils/uevent.c
@@ -116,7 +116,12 @@
     if(s < 0)
         return -1;
 
-    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
+    /* buf_sz should be less than net.core.rmem_max for this to succeed */
+    if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
+        close(s);
+        return -1;
+    }
+
     setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
 
     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
diff --git a/libion/ion.c b/libion/ion.c
index 2db8845..a7b22b8 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -34,7 +34,7 @@
 
 int ion_open()
 {
-    int fd = open("/dev/ion", O_RDONLY);
+    int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         ALOGE("open /dev/ion failed!\n");
     return fd;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 16aa4fa..2424dba 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -27,10 +27,10 @@
     "fake_writer.c",
 ]
 liblog_target_sources = [
-    "event_tag_map.c",
+    "event_tag_map.cpp",
     "config_read.c",
     "log_time.cpp",
-    "log_is_loggable.c",
+    "properties.c",
     "logprint.c",
     "pmsg_reader.c",
     "pmsg_writer.c",
@@ -68,11 +68,14 @@
             enabled: true,
         },
         not_windows: {
-            srcs: ["event_tag_map.c"],
+            srcs: ["event_tag_map.cpp"],
         },
         linux: {
             host_ldlibs: ["-lrt"],
         },
+        linux_bionic: {
+            enabled: true,
+        },
     },
 
     cflags: [
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
deleted file mode 100644
index f9cad99..0000000
--- a/liblog/event_tag_map.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2007 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 <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-
-#include <android/log.h>
-#include <log/event_tag_map.h>
-
-#include "log_portability.h"
-
-#define OUT_TAG "EventTagMap"
-
-/*
- * Single entry.
- */
-typedef struct EventTag {
-    uint32_t tagIndex;
-    char*    tagStr;
-    size_t   tagLen;
-    char*    fmtStr;
-    size_t   fmtLen;
-} EventTag;
-
-/*
- * Map.
- */
-struct EventTagMap {
-    /* memory-mapped source file; we get strings from here */
-    void*           mapAddr;
-    size_t          mapLen;
-
-    /* array of event tags, sorted numerically by tag index */
-    EventTag*       tagArray;
-    int             numTags;
-};
-
-/* fwd */
-static int processFile(EventTagMap* map);
-static int countMapLines(const EventTagMap* map);
-static int parseMapLines(EventTagMap* map);
-static int scanTagLine(char** pData, EventTag* tag, int lineNum);
-static int sortTags(EventTagMap* map);
-
-/*
- * Open the map file and allocate a structure to manage it.
- *
- * We create a private mapping because we want to terminate the log tag
- * strings with '\0'.
- */
-LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
-{
-    EventTagMap* newTagMap;
-    off_t end;
-    int save_errno;
-
-    int fd = open(fileName, 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));
-        goto fail_errno;
-    }
-
-    end = lseek(fd, 0L, SEEK_END);
-    save_errno = errno;
-    (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));
-        goto fail_close;
-    }
-
-    newTagMap = (EventTagMap*)calloc(1, sizeof(EventTagMap));
-    if (newTagMap == NULL) {
-        save_errno = errno;
-        goto fail_close;
-    }
-
-    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-    save_errno = errno;
-    close(fd);
-    fd = -1;
-    if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
-        fprintf(stderr, "%s: mmap(%s) failed: %s\n",
-                OUT_TAG, fileName, strerror(save_errno));
-        goto fail_free;
-    }
-
-    newTagMap->mapLen = end;
-
-    if (processFile(newTagMap) != 0) goto fail_unmap;
-
-    return newTagMap;
-
-fail_unmap:
-    munmap(newTagMap->mapAddr, newTagMap->mapLen);
-    save_errno = EINVAL;
-fail_free:
-    free(newTagMap);
-fail_close:
-    close(fd);
-fail_errno:
-    errno = save_errno;
-fail:
-    return NULL;
-}
-
-/*
- * Close the map.
- */
-LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map)
-{
-    if (map == NULL) return;
-
-    munmap(map->mapAddr, map->mapLen);
-    free(map->tagArray);
-    free(map);
-}
-
-/*
- * 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_lookupEventTag_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].tagLen;
-            /*
-             * b/31456426 to check if gTest can detect copy-on-write issue
-             * add the following line to break us:
-             *     map->tagArray[mid].tagStr[map->tagArray[mid].tagLen] = '\0';
-             * or explicitly use deprecated android_lookupEventTag().
-             */
-            return map->tagArray[mid].tagStr;
-        }
-    }
-
-    errno = ENOENT;
-    if (len) *len = 0;
-    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)
-{
-    size_t len;
-    const char* tagStr = android_lookupEventTag_len(map, &len, tag);
-    char* cp;
-
-    if (!tagStr) return tagStr;
-    cp = (char*)tagStr;
-    cp += len;
-    if (*cp) *cp = '\0'; /* Trigger copy on write :-( */
-    return tagStr;
-}
-
-/*
- * Crunch through the file, parsing the contents and creating a tag index.
- */
-static int processFile(EventTagMap* map)
-{
-    /* get a tag count */
-    map->numTags = countMapLines(map);
-    if (map->numTags < 0) {
-        errno = ENOENT;
-        return -1;
-    }
-
-    /* allocate storage for the tag index array */
-    map->tagArray = (EventTag*)calloc(1, sizeof(EventTag) * map->numTags);
-    if (map->tagArray == NULL) return -1;
-
-    /* parse the file, null-terminating tag strings */
-    if (parseMapLines(map) != 0) return -1;
-
-    /* sort the tags and check for duplicates */
-    if (sortTags(map) != 0) return -1;
-
-    return 0;
-}
-
-/*
- * Run through all lines in the file, determining whether they're blank,
- * comments, or possibly have a tag entry.
- *
- * This is a very "loose" scan.  We don't try to detect syntax errors here.
- * The later pass is more careful, but the number of tags found there must
- * match the number of tags found here.
- *
- * Returns the number of potential tag entries found.
- */
-static int countMapLines(const EventTagMap* map)
-{
-    const char* cp = (const char*) map->mapAddr;
-    const char* endp = cp + map->mapLen;
-    int numTags = 0;
-    int unknown = 1;
-
-    while (cp < endp) {
-        if (*cp == '\n') {
-            unknown = 1;
-        } else if (unknown) {
-            if (isdigit(*cp)) {
-                /* looks like a tag to me */
-                numTags++;
-                unknown = 0;
-            } else if (isspace(*cp)) {
-                /* might be leading whitespace before tag num, keep going */
-            } else {
-                /* assume comment; second pass can complain in detail */
-                unknown = 0;
-            }
-        } else {
-            /* we've made up our mind; just scan to end of line */
-        }
-        cp++;
-    }
-
-    return numTags;
-}
-
-/*
- * Parse the tags out of the file.
- */
-static int parseMapLines(EventTagMap* map)
-{
-    int tagNum, lineStart, lineNum;
-    char* cp = (char*) map->mapAddr;
-    char* endp = cp + map->mapLen;
-
-    /* insist on EOL at EOF; simplifies parsing and null-termination */
-    if (*(endp - 1) != '\n') {
-        fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
-        errno = EINVAL;
-        return -1;
-    }
-
-    tagNum = 0;
-    lineStart = 1;
-    lineNum = 1;
-    while (cp < endp) {
-        if (*cp == '\n') {
-            lineStart = 1;
-            lineNum++;
-        } else if (lineStart) {
-            if (*cp == '#') {
-                /* comment; just scan to end */
-                lineStart = 0;
-            } else if (isdigit(*cp)) {
-                /* looks like a tag; scan it out */
-                if (tagNum >= map->numTags) {
-                    fprintf(stderr,
-                        "%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
-                    errno = EMFILE;
-                    return -1;
-                }
-                if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0) {
-                    return -1;
-                }
-                tagNum++;
-                lineNum++;      // we eat the '\n'
-                /* leave lineStart==1 */
-            } else if (isspace(*cp)) {
-                /* looks like leading whitespace; keep scanning */
-            } else {
-                fprintf(stderr,
-                    "%s: unexpected chars (0x%02x) in tag number on line %d\n",
-                    OUT_TAG, *cp, lineNum);
-                errno = EINVAL;
-                return -1;
-            }
-        } else {
-            /* this is a blank or comment line */
-        }
-        cp++;
-    }
-
-    if (tagNum != map->numTags) {
-        fprintf(stderr, "%s: parsed %d tags, expected %d\n",
-            OUT_TAG, tagNum, map->numTags);
-        errno = EINVAL;
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Scan one tag line.
- *
- * "*pData" should be pointing to the first digit in the tag number.  On
- * successful return, it will be pointing to the last character in the
- * tag line (i.e. the character before the start of the next line).
- *
- * Returns 0 on success, nonzero on failure.
- */
-static int scanTagLine(char** pData, EventTag* tag, int lineNum)
-{
-    char* cp;
-
-    unsigned long val = strtoul(*pData, &cp, 10);
-    if (cp == *pData) {
-        fprintf(stderr, "%s: malformed tag number on line %d\n", OUT_TAG, lineNum);
-        errno = EINVAL;
-        return -1;
-    }
-
-    tag->tagIndex = val;
-    if (tag->tagIndex != val) {
-        fprintf(stderr, "%s: tag number too large on line %d\n", OUT_TAG, lineNum);
-        errno = ERANGE;
-        return -1;
-    }
-
-    while ((*++cp != '\n') && isspace(*cp)) {
-    }
-
-    if (*cp == '\n') {
-        fprintf(stderr, "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
-        errno = EINVAL;
-        return -1;
-    }
-
-    tag->tagStr = cp;
-
-    /* Determine whether "c" is a valid tag char. */
-    while (isalnum(*++cp) || (*cp == '_')) {
-    }
-    tag->tagLen = cp - tag->tagStr;
-
-    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;
-}
-
-/*
- * Compare two EventTags.
- */
-static int compareEventTags(const void* v1, const void* v2)
-{
-    const EventTag* tag1 = (const EventTag*) v1;
-    const EventTag* tag2 = (const EventTag*) v2;
-
-    return tag1->tagIndex - tag2->tagIndex;
-}
-
-/*
- * Sort the EventTag array so we can do fast lookups by tag index.  After
- * the sort we do a quick check for duplicate tag indices.
- *
- * Returns 0 on success.
- */
-static int sortTags(EventTagMap* map)
-{
-    int i;
-
-    qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
-
-    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:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
-                OUT_TAG,
-                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;
-        }
-    }
-
-    return 0;
-}
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
new file mode 100644
index 0000000..1155422
--- /dev/null
+++ b/liblog/event_tag_map.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2007-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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <experimental/string_view>
+#include <functional>
+#include <unordered_map>
+
+#include <log/event_tag_map.h>
+
+#include "log_portability.h"
+
+#define OUT_TAG "EventTagMap"
+
+typedef std::experimental::string_view MapString;
+
+typedef std::pair<MapString, MapString> TagFmt;
+
+template <> struct _LIBCPP_TYPE_VIS_ONLY std::hash<TagFmt>
+        : public std::unary_function<const TagFmt&, size_t> {
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(const TagFmt& __t) const _NOEXCEPT {
+        // Tag is typically unique.  Will cost us an extra 100ns for the
+        // unordered_map lookup if we instead did a hash that combined
+        // both of tag and fmt members, e.g.:
+        //
+        // return std::hash<MapString>()(__t.first) ^
+        //        std::hash<MapString>()(__t.second);
+        return std::hash<MapString>()(__t.first);
+    }
+};
+
+// Map
+struct EventTagMap {
+    // memory-mapped source file; we get strings from here
+    void*  mapAddr;
+    size_t mapLen;
+
+private:
+    std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
+
+public:
+    EventTagMap() : mapAddr(NULL), mapLen(0) { }
+
+    ~EventTagMap() {
+        Idx2TagFmt.clear();
+        if (mapAddr) {
+            munmap(mapAddr, mapLen);
+            mapAddr = 0;
+        }
+    }
+
+    bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
+    const TagFmt* find(uint32_t tag) const;
+};
+
+bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose) {
+    std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+    it = Idx2TagFmt.find(tag);
+    if (it != Idx2TagFmt.end()) {
+        if (verbose) {
+            fprintf(stderr,
+                    OUT_TAG ": duplicate tag entries %" PRIu32
+                        ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
+                    it->first,
+                    (int)it->second.first.length(), it->second.first.data(),
+                    (int)it->second.second.length(), it->second.second.data(),
+                    tag,
+                    (int)tagfmt.first.length(), tagfmt.first.data(),
+                    (int)tagfmt.second.length(), tagfmt.second.data());
+        }
+        return false;
+    }
+
+    Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
+    return true;
+}
+
+const TagFmt* EventTagMap::find(uint32_t tag) const {
+    std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+    it = Idx2TagFmt.find(tag);
+    if (it == Idx2TagFmt.end()) return NULL;
+    return &(it->second);
+}
+
+// Scan one tag line.
+//
+// "*pData" should be pointing to the first digit in the tag number.  On
+// successful return, it will be pointing to the last character in the
+// tag line (i.e. the character before the start of the next line).
+//
+// Returns 0 on success, nonzero on failure.
+static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
+    char* cp;
+    unsigned long val = strtoul(*pData, &cp, 10);
+    if (cp == *pData) {
+        fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
+        errno = EINVAL;
+        return -1;
+    }
+
+    uint32_t tagIndex = val;
+    if (tagIndex != val) {
+        fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
+        errno = ERANGE;
+        return -1;
+    }
+
+    while ((*++cp != '\n') && isspace(*cp)) {
+    }
+
+    if (*cp == '\n') {
+        fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
+        errno = EINVAL;
+        return -1;
+    }
+
+    const char* tag = cp;
+    // Determine whether "c" is a valid tag char.
+    while (isalnum(*++cp) || (*cp == '_')) { }
+    size_t tagLen = cp - tag;
+
+    if (!isspace(*cp)) {
+        fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+        errno = EINVAL;
+        return -1;
+    }
+
+    while (isspace(*cp) && (*cp != '\n')) ++cp;
+    const char* fmt = NULL;
+    size_t fmtLen = 0;
+    if (*cp != '#') {
+        fmt = cp;
+        while ((*cp != '\n') && (*cp != '#')) ++cp;
+        while ((cp > fmt) && isspace(*(cp - 1))) --cp;
+        fmtLen = cp - fmt;
+    }
+
+    while (*cp != '\n') ++cp;
+#ifdef DEBUG
+    fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
+#endif
+    *pData = cp;
+
+    if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+            MapString(tag, tagLen), MapString(fmt, fmtLen))), true)) {
+        return 0;
+    }
+    errno = EMLINK;
+    return -1;
+}
+
+// Parse the tags out of the file.
+static int parseMapLines(EventTagMap* map) {
+    char* cp = static_cast<char*>(map->mapAddr);
+    size_t len = map->mapLen;
+    char* endp = cp + len;
+
+    // insist on EOL at EOF; simplifies parsing and null-termination
+    if (!len || (*(endp - 1) != '\n')) {
+#ifdef DEBUG
+        fprintf(stderr, OUT_TAG ": map file missing EOL on last line\n");
+#endif
+        errno = EINVAL;
+        return -1;
+    }
+
+    bool lineStart = true;
+    int lineNum = 1;
+    while (cp < endp) {
+        if (*cp == '\n') {
+            lineStart = true;
+            lineNum++;
+        } else if (lineStart) {
+            if (*cp == '#') {
+                // comment; just scan to end
+                lineStart = false;
+            } else if (isdigit(*cp)) {
+                // looks like a tag; scan it out
+                if (scanTagLine(map, &cp, lineNum) != 0) {
+                    return -1;
+                }
+                lineNum++;      // we eat the '\n'
+                // leave lineStart==true
+            } else if (isspace(*cp)) {
+                // looks like leading whitespace; keep scanning
+            } else {
+                fprintf(stderr,
+                        OUT_TAG ": unexpected chars (0x%02x) in tag number on line %d\n",
+                        *cp, lineNum);
+                errno = EINVAL;
+                return -1;
+            }
+        } else {
+            // this is a blank or comment line
+        }
+        cp++;
+    }
+
+    return 0;
+}
+
+// Open the map file and allocate a structure to manage it.
+//
+// We create a private mapping because we want to terminate the log tag
+// strings with '\0'.
+LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
+    int save_errno;
+
+    const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
+    int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        save_errno = errno;
+        fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n",
+                tagfile, strerror(save_errno));
+        errno = save_errno;
+        return NULL;
+    }
+    off_t end = lseek(fd, 0L, SEEK_END);
+    save_errno = errno;
+    (void)lseek(fd, 0L, SEEK_SET);
+    if (end < 0) {
+        fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n",
+                tagfile, strerror(save_errno));
+        close(fd);
+        errno = save_errno;
+        return NULL;
+    }
+
+    EventTagMap* newTagMap = new EventTagMap;
+    if (newTagMap == NULL) {
+        save_errno = errno;
+        close(fd);
+        errno = save_errno;
+        return NULL;
+    }
+
+    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE, fd, 0);
+    save_errno = errno;
+    close(fd);
+    fd = -1;
+    if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
+        fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n",
+                tagfile, strerror(save_errno));
+        delete newTagMap;
+        errno = save_errno;
+        return NULL;
+    }
+
+    newTagMap->mapLen = end;
+
+    if (parseMapLines(newTagMap) != 0) {
+        delete newTagMap;
+        return NULL;
+    }
+
+    return newTagMap;
+}
+
+// Close the map.
+LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
+    if (map) delete map;
+}
+
+// Look up an entry in the map.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
+                                                         size_t *len,
+                                                         unsigned int tag) {
+    if (len) *len = 0;
+    const TagFmt* str = map->find(tag);
+    if (!str) return NULL;
+    if (len) *len = str->first.length();
+    return str->first.data();
+}
+
+// Look up an entry in the map.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+        const EventTagMap* map, size_t *len, unsigned int tag) {
+    if (len) *len = 0;
+    const TagFmt* str = map->find(tag);
+    if (!str) return NULL;
+    if (len) *len = str->second.length();
+    return str->second.data();
+}
+
+// This function is deprecated and replaced with android_lookupEventTag_len
+// since it will cause the map to change from Shared and backed by a file,
+// to Private Dirty and backed up by swap, albeit highly compressible. By
+// deprecating this function everywhere, we save 100s of MB of memory space.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
+                                                     unsigned int tag) {
+    size_t len;
+    const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+
+    if (!tagStr) return tagStr;
+    char* cp = const_cast<char*>(tagStr);
+    cp += len;
+    if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
+    return tagStr;
+}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 11d8afb..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <log/log_event_list.h>
 #include <private/android_logger.h>
 
 #include "log_portability.h"
@@ -319,7 +320,7 @@
     context->storage[1] = context->count[0];
     len = context->len = context->pos;
     msg = (const char *)context->storage;
-    /* it'snot a list */
+    /* it's not a list */
     if (context->count[0] <= 1) {
         len -= sizeof(uint8_t) + sizeof(uint8_t);
         if (len < 0) {
@@ -332,6 +333,38 @@
         __android_log_security_bwrite(context->tag, msg, len);
 }
 
+LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
+                                                     const char **buffer) {
+    android_log_context_internal *context;
+    const char *msg;
+    ssize_t len;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+    if (buffer == NULL) {
+        return -EFAULT;
+    }
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char *)context->storage;
+    /* it's not a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+    *buffer = msg;
+    return len;
+}
+
 /*
  * Extract a 4-byte value from a byte stream.
  */
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 7262fc5..14d6482 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 157bd88..f19c3ab 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -48,7 +48,7 @@
 
 static int check_log_uid_permissions()
 {
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     uid_t uid = __android_log_uid();
 
     /* Matches clientHasLogCredentials() in logd */
@@ -130,7 +130,7 @@
     return kLogNotAvailable;
 }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
 static atomic_uintptr_t tagMap;
 #endif
 
@@ -140,7 +140,7 @@
 LIBLOG_ABI_PUBLIC void __android_log_close()
 {
     struct android_log_transport_write *transport;
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     EventTagMap *m;
 #endif
 
@@ -170,7 +170,7 @@
         }
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     /*
      * Additional risk here somewhat mitigated by immediately unlock flushing
      * the processor cache. The multi-threaded race that we choose to accept,
@@ -188,7 +188,7 @@
 
     __android_log_unlock();
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
 #endif
 
@@ -261,7 +261,7 @@
         return -EINVAL;
     }
 
-#if defined(__BIONIC__)
+#if defined(__ANDROID__)
     if (log_id == LOG_ID_SECURITY) {
         if (vec[0].iov_len < 4) {
             return -EINVAL;
@@ -293,7 +293,7 @@
             ret = __android_log_trylock();
             m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
             if (!m) {
-                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+                m = android_openEventTagMap(NULL);
                 if (ret) { /* trylock failed, use local copy, mark for close */
                     f = m;
                 } else {
diff --git a/liblog/logprint.c b/liblog/logprint.c
index fb942a1..da80e36 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -632,8 +632,8 @@
     size_t len;
     int64_t lval;
 
-    if (eventDataLen < 1)
-        return -1;
+    if (eventDataLen < 1) return -1;
+
     type = *eventData++;
     eventDataLen--;
 
@@ -729,8 +729,7 @@
         {
             int32_t ival;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
@@ -740,8 +739,7 @@
         goto pr_lval;
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
-        if (eventDataLen < 8)
-            return -1;
+        if (eventDataLen < 8) return -1;
         lval = get8LE(eventData);
         eventData += 8;
         eventDataLen -= 8;
@@ -761,8 +759,7 @@
             uint32_t ival;
             float fval;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             fval = *(float*)&ival;
             eventData += 4;
@@ -783,14 +780,12 @@
         {
             unsigned int strLen;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             strLen = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
 
-            if (eventDataLen < strLen)
-                return -1;
+            if (eventDataLen < strLen) return -1;
 
             if (cp && (strLen == 0)) {
                 /* reset the format if no content */
@@ -818,41 +813,32 @@
             unsigned char count;
             int i;
 
-            if (eventDataLen < 1)
-                return -1;
+            if (eventDataLen < 1) return -1;
 
             count = *eventData++;
             eventDataLen--;
 
-            if (outBufLen > 0) {
-                *outBuf++ = '[';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = '[';
+            outBufLen--;
 
             for (i = 0; i < count; i++) {
                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
                         &outBuf, &outBufLen, fmtStr, fmtLen);
-                if (result != 0)
-                    goto bail;
+                if (result != 0) goto bail;
 
-                if (i < count-1) {
-                    if (outBufLen > 0) {
-                        *outBuf++ = ',';
-                        outBufLen--;
-                    } else {
-                        goto no_room;
-                    }
+                if (i < (count - 1)) {
+                    if (outBufLen <= 0) goto no_room;
+                    *outBuf++ = ',';
+                    outBufLen--;
                 }
             }
 
-            if (outBufLen > 0) {
-                *outBuf++ = ']';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = ']';
+            outBufLen--;
         }
         break;
     default:
@@ -997,8 +983,7 @@
         }
     }
     inCount = buf->len;
-    if (inCount < 4)
-        return -1;
+    if (inCount < 4) return -1;
     tagIndex = get4LE(eventData);
     eventData += 4;
     inCount -= 4;
@@ -1031,16 +1016,20 @@
     /*
      * Format the event log data into the buffer.
      */
-    char* outBuf = messageBuf;
-    size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
-    int result;
     const char* fmtStr = NULL;
     size_t fmtLen = 0;
     if (descriptive_output && map) {
         fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
     }
-    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
-                &outRemaining, &fmtStr, &fmtLen);
+
+    char* outBuf = messageBuf;
+    size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
+    int result = 0;
+
+    if ((inCount > 0) || fmtLen) {
+        result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+                                              &outRemaining, &fmtStr, &fmtLen);
+    }
     if ((result == 1) && fmtStr) {
         /* We overflowed :-(, let's repaint the line w/o format dressings */
         eventData = (const unsigned char*)buf->msg;
@@ -1055,18 +1044,18 @@
     }
     if (result < 0) {
         fprintf(stderr, "Binary log entry conversion failed\n");
-        return -1;
-    } else if (result == 1) {
-        if (outBuf > messageBuf) {
-            /* leave an indicator */
-            *(outBuf-1) = '!';
-        } else {
-            /* no room to output anything at all */
-            *outBuf++ = '!';
-            outRemaining--;
+    }
+    if (result) {
+        if (!outRemaining) {
+            /* make space to leave an indicator */
+            --outBuf;
+            ++outRemaining;
         }
-        /* pretend we ate all the data */
+        *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
+        outRemaining--;
+        /* pretend we ate all the data to prevent log stutter */
         inCount = 0;
+        if (result > 0) result = 0;
     }
 
     /* eat the silly terminating '\n' */
@@ -1090,7 +1079,7 @@
 
     entry->message = messageBuf;
 
-    return 0;
+    return result;
 }
 
 /*
@@ -1802,8 +1791,7 @@
     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
             sizeof(defaultBuffer), entry, &totalLen);
 
-    if (!outBuffer)
-        return -1;
+    if (!outBuffer) return -1;
 
     do {
         ret = write(fd, outBuffer, totalLen);
diff --git a/liblog/log_is_loggable.c b/liblog/properties.c
similarity index 100%
rename from liblog/log_is_loggable.c
rename to liblog/properties.c
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 158987a..ec5a99b 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -74,3 +74,38 @@
 LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
+
+cts_executable := CtsLiblogTestCases
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
+LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_CTS_TEST_PACKAGE := android.core.liblog
+include $(BUILD_CTS_EXECUTABLE)
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)_list
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(test_c_flags) -DHOST
+LOCAL_C_INCLUDES := external/gtest/include
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_CXX_STL := libc++
+LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif  # ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml
new file mode 100644
index 0000000..b8d87e6
--- /dev/null
+++ b/liblog/tests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for CTS Logging Library test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="CtsLiblogTestCases" />
+        <option name="runtime-hint" value="65s" />
+    </test>
+</configuration>
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index f05a955..8cea7dc 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 
 TEST(libc, __pstore_append) {
+#ifdef __ANDROID__
     FILE *fp;
     ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
     static const char message[] = "libc.__pstore_append\n";
@@ -42,4 +43,7 @@
                 "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
                );
     }
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 44045c3..5420f68 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -20,7 +20,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <unordered_set>
+
 #include <cutils/sockets.h>
+#include <log/event_tag_map.h>
 #include <private/android_logger.h>
 
 #include "benchmark.h"
@@ -689,3 +692,96 @@
     StopBenchmarkTiming();
 }
 BENCHMARK(BM_security);
+
+// Keep maps around for multiple iterations
+static std::unordered_set<uint32_t> set;
+static const EventTagMap* map;
+
+static bool prechargeEventMap() {
+    if (map) return true;
+
+    fprintf(stderr, "Precharge: start\n");
+
+    map = android_openEventTagMap(NULL);
+    for (uint32_t tag = 1; tag < USHRT_MAX; ++tag) {
+        size_t len;
+        if (android_lookupEventTag_len(map, &len, tag) == NULL) continue;
+        set.insert(tag);
+    }
+
+    fprintf(stderr, "Precharge: stop %zu\n", set.size());
+
+    return true;
+}
+
+/*
+ *	Measure the time it takes for android_lookupEventTag_len
+ */
+static void BM_lookupEventTag(int iters) {
+
+    prechargeEventMap();
+
+    std::unordered_set<uint32_t>::const_iterator it = set.begin();
+
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        size_t len;
+        android_lookupEventTag_len(map, &len, (*it));
+        ++it;
+        if (it == set.end()) it = set.begin();
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_lookupEventTag);
+
+/*
+ *	Measure the time it takes for android_lookupEventTag_len
+ */
+static uint32_t notTag = 1;
+
+static void BM_lookupEventTag_NOT(int iters) {
+
+    prechargeEventMap();
+
+    while (set.find(notTag) != set.end()) {
+        ++notTag;
+        if (notTag >= USHRT_MAX) notTag = 1;
+    }
+
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        size_t len;
+        android_lookupEventTag_len(map, &len, notTag);
+    }
+
+    StopBenchmarkTiming();
+
+    ++notTag;
+    if (notTag >= USHRT_MAX) notTag = 1;
+}
+BENCHMARK(BM_lookupEventTag_NOT);
+
+/*
+ *	Measure the time it takes for android_lookupEventFormat_len
+ */
+static void BM_lookupEventFormat(int iters) {
+
+    prechargeEventMap();
+
+    std::unordered_set<uint32_t>::const_iterator it = set.begin();
+
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        size_t len;
+        android_lookupEventFormat_len(map, &len, (*it));
+        ++it;
+        if (it == set.end()) it = set.begin();
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_lookupEventFormat);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9c09523..d07d774 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -30,9 +30,12 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
+#ifdef __ANDROID__ // includes sys/properties.h which does not exist outside
 #include <cutils/properties.h>
+#endif
 #include <gtest/gtest.h>
 #include <log/logprint.h>
+#include <log/log_event_list.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -52,6 +55,7 @@
     _rc; })
 
 TEST(liblog, __android_log_buf_print) {
+#ifdef __ANDROID__
     EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "radio"));
@@ -64,9 +68,13 @@
                                          "TEST__android_log_buf_print",
                                          "main"));
     usleep(1000);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_buf_write) {
+#ifdef __ANDROID__
     EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "radio"));
@@ -79,9 +87,13 @@
                                          "TEST__android_log_buf_write",
                                          "main"));
     usleep(1000);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_btwrite) {
+#ifdef __ANDROID__
     int intBuf = 0xDEADBEEF;
     EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_INT,
@@ -96,20 +108,26 @@
                                       EVENT_TYPE_STRING,
                                       Buf, sizeof(Buf) - 1));
     usleep(1000);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static void* ConcurrentPrintFn(void *arg) {
     int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                   "TEST__android_log_print", "Concurrent %" PRIuPTR,
                                   reinterpret_cast<uintptr_t>(arg));
     return reinterpret_cast<void*>(ret);
 }
+#endif
 
 #define NUM_CONCURRENT 64
 #define _concurrent_name(a,n) a##__concurrent##n
 #define concurrent_name(a,n) _concurrent_name(a,n)
 
 TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
+#ifdef __ANDROID__
     pthread_t t[NUM_CONCURRENT];
     int i;
     for (i=0; i < NUM_CONCURRENT; i++) {
@@ -127,8 +145,12 @@
         }
     }
     ASSERT_LT(0, ret);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 std::string popenToString(std::string command) {
     std::string ret;
 
@@ -192,8 +214,10 @@
     }
     return false;
 }
+#endif
 
 TEST(liblog, __android_log_btwrite__android_logger_list_read) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -256,14 +280,20 @@
     EXPECT_EQ(1, second_count);
 
     android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static inline int32_t get4LE(const char* src)
 {
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
 }
+#endif
 
 static void bswrite_test(const char *message) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -328,6 +358,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);
@@ -343,6 +376,10 @@
     EXPECT_EQ(1, count);
 
     android_logger_list_close(logger_list);
+#else
+    message = NULL;
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_bswrite_and_print) {
@@ -366,6 +403,7 @@
 }
 
 static void buf_write_test(const char *message) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -432,6 +470,10 @@
     EXPECT_EQ(1, count);
 
     android_logger_list_close(logger_list);
+#else
+    message = NULL;
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_buf_write_and_print__empty) {
@@ -447,6 +489,7 @@
 }
 
 TEST(liblog, __security) {
+#ifdef __ANDROID__
     static const char persist_key[] = "persist.logd.security";
     static const char readonly_key[] = "ro.device_owner";
     static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
@@ -481,9 +524,13 @@
     property_set(persist_key, "");
     EXPECT_FALSE(__android_log_security());
     property_set(persist_key, persist);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __security_buffer) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
     android_event_long_t buffer;
 
@@ -492,6 +539,7 @@
     bool set_persist = false;
     bool allow_security = false;
 
+    setuid(AID_SYSTEM); // only one that can read security buffer
     if (__android_log_security()) {
         allow_security = true;
     } else {
@@ -617,9 +665,12 @@
                 "not system, content submitted but can not check end-to-end\n");
     }
     EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
-
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static unsigned signaled;
 static log_time signal_time;
 
@@ -678,8 +729,10 @@
         *uticks = *sticks = 0;
     }
 }
+#endif
 
 TEST(liblog, android_logger_list_read__cpu_signal) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -764,8 +817,12 @@
     EXPECT_GT(one_percent_ticks, user_ticks);
     EXPECT_GT(one_percent_ticks, system_ticks);
     EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 /*
  *  Strictly, we are not allowed to log messages in a signal context, the
  * correct way to handle this is to ensure the messages are constructed in
@@ -828,8 +885,10 @@
     pthread_attr_destroy(&attr);
     return 0;
 }
+#endif
 
 TEST(liblog, android_logger_list_read__cpu_thread) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
     unsigned long long v = 0xDEADBEAFA55A0000ULL;
 
@@ -915,11 +974,16 @@
     EXPECT_GT(one_percent_ticks, user_ticks);
     EXPECT_GT(one_percent_ticks, system_ticks);
     EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
 #define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
                                 sizeof(max_payload_tag) - 1)
+#endif
 static const char max_payload_buf[] = "LEONATO\n\
 I learn in this letter that Don Peter of Arragon\n\
 comes this night to Messina\n\
@@ -1052,6 +1116,7 @@
 takes his leave.";
 
 TEST(liblog, max_payload) {
+#ifdef __ANDROID__
     pid_t pid = getpid();
     char tag[sizeof(max_payload_tag)];
     memcpy(tag, max_payload_tag, sizeof(tag));
@@ -1109,9 +1174,13 @@
     EXPECT_EQ(true, matches);
 
     EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_buf_print__maxtag) {
+#ifdef __ANDROID__
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1165,9 +1234,13 @@
     EXPECT_EQ(1, count);
 
     android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, too_big_payload) {
+#ifdef __ANDROID__
     pid_t pid = getpid();
     static const char big_payload_tag[] = "TEST_big_payload_XXXX";
     char tag[sizeof(big_payload_tag)];
@@ -1222,9 +1295,13 @@
               static_cast<size_t>(max_len));
 
     EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, dual_reader) {
+#ifdef __ANDROID__
     struct logger_list *logger_list1;
 
     // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
@@ -1269,9 +1346,13 @@
 
     EXPECT_EQ(25, count1);
     EXPECT_EQ(15, count2);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, android_logger_get_) {
+#ifdef __ANDROID__
     struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
 
     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
@@ -1303,14 +1384,20 @@
     }
 
     android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
     return android_log_shouldPrintLine(p_format, tag, pri)
         && !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
 }
+#endif
 
 TEST(liblog, filterRule) {
+#ifdef __ANDROID__
     static const char tag[] = "random";
 
     AndroidLogFormat *p_format = android_log_format_new();
@@ -1372,9 +1459,13 @@
 #endif
 
     android_log_format_free(p_format);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, is_loggable) {
+#ifdef __ANDROID__
     static const char tag[] = "is_loggable";
     static const char log_namespace[] = "persist.log.tag.";
     static const size_t base_offset = 8; /* skip "persist." */
@@ -1667,13 +1758,15 @@
     key[sizeof(log_namespace) - 2] = '\0';
     property_set(key, hold[2]);
     property_set(key + base_offset, hold[3]);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-    const int TAG = 123456781;
-    const char SUBTAG[] = "test-subtag";
-    const int UID = -1;
-    const int DATA_LEN = 200;
+#ifdef __ANDROID__
+static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
+                                                 int UID, const char* payload,
+                                                 int DATA_LEN, int& count) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1681,96 +1774,17 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    ASSERT_LT(0, android_errorWriteWithInfoLog(
-            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
-
-    sleep(2);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        char *eventData = log_msg.msg();
-        if (!eventData) {
-            continue;
-        }
-
-        // Tag
-        int tag = get4LE(eventData);
-        eventData += 4;
-
-        if (tag != TAG) {
-            continue;
-        }
-
-        // List type
-        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
-        eventData++;
-
-        // Number of elements in list
-        ASSERT_EQ(3, eventData[0]);
-        eventData++;
-
-        // Element #1: string type for subtag
-        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
-        eventData++;
-
-        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
-        eventData +=4;
-
-        if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
-            continue;
-        }
-        eventData += strlen(SUBTAG);
-
-        // Element #2: int type for uid
-        ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
-        eventData++;
-
-        ASSERT_EQ(UID, get4LE(eventData));
-        eventData += 4;
-
-        // Element #3: string type for data
-        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
-        eventData++;
-
-        ASSERT_EQ(DATA_LEN, get4LE(eventData));
-        eventData += 4;
-
-        if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
-            continue;
-        }
-
-        ++count;
+    int retval_android_errorWriteWithinInfoLog = android_errorWriteWithInfoLog(
+            TAG, SUBTAG, UID, payload, DATA_LEN);
+    if (payload) {
+        ASSERT_LT(0, retval_android_errorWriteWithinInfoLog);
+    } else {
+        ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
     }
 
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
-}
-
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-    const int TAG = 123456782;
-    const char SUBTAG[] = "test-subtag";
-    const int UID = -1;
-    const int DATA_LEN = sizeof(max_payload_buf);
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    ASSERT_LT(0, android_errorWriteWithInfoLog(
-            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
-
     sleep(2);
 
-    int count = 0;
+    count = 0;
 
     for (;;) {
         log_msg log_msg;
@@ -1793,6 +1807,12 @@
             continue;
         }
 
+        if (!payload) {
+            // This tag should not have been written because the data was null
+            ++count;
+            break;
+        }
+
         // List type
         ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
         eventData++;
@@ -1805,13 +1825,15 @@
         ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
         eventData++;
 
-        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+        int subtag_len = strlen(SUBTAG);
+        if (subtag_len > 32) subtag_len = 32;
+        ASSERT_EQ(subtag_len, get4LE(eventData));
         eventData +=4;
 
-        if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+        if (memcmp(SUBTAG, eventData, subtag_len)) {
             continue;
         }
-        eventData += strlen(SUBTAG);
+        eventData += subtag_len;
 
         // Element #2: int type for uid
         ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
@@ -1826,153 +1848,88 @@
 
         size_t dataLen = get4LE(eventData);
         eventData += 4;
+        if (DATA_LEN < 512) ASSERT_EQ(DATA_LEN, (int)dataLen);
 
-        if (memcmp(max_payload_buf, eventData, dataLen)) {
+        if (memcmp(payload, eventData, dataLen)) {
             continue;
         }
-        eventData += dataLen;
 
-        // 4 bytes for the tag, and max_payload_buf should be truncated.
-        ASSERT_LE(4 + 512, eventData - original);      // worst expectations
-        ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
+        if (DATA_LEN >= 512) {
+            eventData += dataLen;
+            // 4 bytes for the tag, and max_payload_buf should be truncated.
+            ASSERT_LE(4 + 512, eventData - original);      // worst expectations
+            ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
+        }
 
         ++count;
     }
 
-    EXPECT_EQ(1, count);
-
     android_logger_list_close(logger_list);
 }
+#endif
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteWithInfoLog_helper(
+            123456781,
+            "test-subtag",
+            -1,
+            max_payload_buf,
+            200,
+            count);
+    EXPECT_EQ(1, count);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteWithInfoLog_helper(
+            123456782,
+            "test-subtag",
+            -1,
+            max_payload_buf,
+            sizeof(max_payload_buf),
+            count);
+    EXPECT_EQ(1, count);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-    const int TAG = 123456783;
-    const char SUBTAG[] = "test-subtag";
-    const int UID = -1;
-    const int DATA_LEN = 200;
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    ASSERT_GT(0, android_errorWriteWithInfoLog(
-            TAG, SUBTAG, UID, NULL, DATA_LEN));
-
-    sleep(2);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        char *eventData = log_msg.msg();
-        if (!eventData) {
-            continue;
-        }
-
-        // Tag
-        int tag = get4LE(eventData);
-        eventData += 4;
-
-        if (tag == TAG) {
-            // This tag should not have been written because the data was null
-            count++;
-            break;
-        }
-    }
-
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteWithInfoLog_helper(
+            123456783,
+            "test-subtag",
+            -1,
+            NULL,
+            200,
+            count);
     EXPECT_EQ(0, count);
-
-    android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-    const int TAG = 123456784;
-    const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
-    const int UID = -1;
-    const int DATA_LEN = 200;
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    ASSERT_LT(0, android_errorWriteWithInfoLog(
-            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
-
-    sleep(2);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        char *eventData = log_msg.msg();
-        if (!eventData) {
-            continue;
-        }
-
-        // Tag
-        int tag = get4LE(eventData);
-        eventData += 4;
-
-        if (tag != TAG) {
-            continue;
-        }
-
-        // List type
-        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
-        eventData++;
-
-        // Number of elements in list
-        ASSERT_EQ(3, eventData[0]);
-        eventData++;
-
-        // Element #1: string type for subtag
-        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
-        eventData++;
-
-        // The subtag is longer than 32 and should be truncated to that.
-        ASSERT_EQ(32, get4LE(eventData));
-        eventData +=4;
-
-        if (memcmp(SUBTAG, eventData, 32)) {
-            continue;
-        }
-        eventData += 32;
-
-        // Element #2: int type for uid
-        ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
-        eventData++;
-
-        ASSERT_EQ(UID, get4LE(eventData));
-        eventData += 4;
-
-        // Element #3: string type for data
-        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
-        eventData++;
-
-        ASSERT_EQ(DATA_LEN, get4LE(eventData));
-        eventData += 4;
-
-        if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
-            continue;
-        }
-
-        ++count;
-    }
-
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteWithInfoLog_helper(
+            123456784,
+            "abcdefghijklmnopqrstuvwxyz now i know my abc",
+            -1,
+            max_payload_buf,
+            200,
+            count);
     EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, __android_log_bswrite_and_print___max) {
@@ -1983,9 +1940,8 @@
     buf_write_test(max_payload_buf);
 }
 
-TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-    const int TAG = 123456785;
-    const char SUBTAG[] = "test-subtag";
+#ifdef __ANDROID__
+static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1993,11 +1949,16 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
+    int retval_android_errorWriteLog = android_errorWriteLog(TAG, SUBTAG);
+    if (SUBTAG) {
+        ASSERT_LT(0, retval_android_errorWriteLog);
+    } else {
+        ASSERT_GT(0, retval_android_errorWriteLog);
+    }
 
     sleep(2);
 
-    int count = 0;
+    count = 0;
 
     for (;;) {
         log_msg log_msg;
@@ -2018,6 +1979,12 @@
             continue;
         }
 
+        if (!SUBTAG) {
+            // This tag should not have been written because the data was null
+            ++count;
+            break;
+        }
+
         // List type
         ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
         eventData++;
@@ -2039,53 +2006,31 @@
         ++count;
     }
 
-    EXPECT_EQ(1, count);
-
     android_logger_list_close(logger_list);
 }
+#endif
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteLog_helper(123456785, "test-subtag", count);
+    EXPECT_EQ(1, count);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
 
 TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-    const int TAG = 123456786;
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
-
-    sleep(2);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        char *eventData = log_msg.msg();
-        if (!eventData) {
-            continue;
-        }
-
-        // Tag
-        int tag = get4LE(eventData);
-        eventData += 4;
-
-        if (tag == TAG) {
-            // This tag should not have been written because the data was null
-            count++;
-            break;
-        }
-    }
-
+#ifdef __ANDROID__
+    int count;
+    android_errorWriteLog_helper(123456786, NULL, count);
     EXPECT_EQ(0, count);
-
-    android_logger_list_close(logger_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 static int is_real_element(int type) {
     return ((type == EVENT_TYPE_INT) ||
             (type == EVENT_TYPE_LONG) ||
@@ -2579,48 +2524,90 @@
 
     android_logger_list_close(logger_list);
 }
+#endif
 
 TEST(liblog, create_android_logger_int32) {
+#ifdef __ANDROID__
     create_android_logger(event_test_int32);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_int64) {
+#ifdef __ANDROID__
     create_android_logger(event_test_int64);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_list_int64) {
+#ifdef __ANDROID__
     create_android_logger(event_test_list_int64);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_simple_automagic_list) {
+#ifdef __ANDROID__
     create_android_logger(event_test_simple_automagic_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_list_empty) {
+#ifdef __ANDROID__
     create_android_logger(event_test_list_empty);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_complex_nested_list) {
+#ifdef __ANDROID__
     create_android_logger(event_test_complex_nested_list);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_7_level_prefix) {
+#ifdef __ANDROID__
     create_android_logger(event_test_7_level_prefix);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_7_level_suffix) {
+#ifdef __ANDROID__
     create_android_logger(event_test_7_level_suffix);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_android_log_error_write) {
+#ifdef __ANDROID__
     create_android_logger(event_test_android_log_error_write);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_android_log_error_write_null) {
+#ifdef __ANDROID__
     create_android_logger(event_test_android_log_error_write_null);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
 TEST(liblog, create_android_logger_overflow) {
+#ifdef __ANDROID__
     android_log_context ctx;
 
     EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
@@ -2645,12 +2632,35 @@
     EXPECT_GT(0, android_log_write_list_begin(ctx));
     EXPECT_LE(0, android_log_destroy(&ctx));
     ASSERT_TRUE(NULL == ctx);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+TEST(liblog, android_log_write_list_buffer) {
+#ifdef __ANDROID__
+    __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)]");
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#ifdef __ANDROID__
 static const char __pmsg_file[] =
         "/data/william-shakespeare/MuchAdoAboutNothing.txt";
+#endif
 
 TEST(liblog, __android_log_pmsg_file_write) {
+#ifdef __ANDROID__
     __android_log_close();
     bool pmsgActiveAfter__android_log_close = isPmsgActive();
     bool logdwActiveAfter__android_log_close = isLogdwActive();
@@ -2687,8 +2697,12 @@
     logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
     EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
     EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
                   const char *buf, size_t len, void *arg) {
     EXPECT_TRUE(NULL == arg);
@@ -2710,8 +2724,10 @@
            (len != sizeof(max_payload_buf)) ||
            !!strcmp(max_payload_buf, buf) ? -ENOEXEC : 1;
 }
+#endif
 
 TEST(liblog, __android_log_pmsg_file_read) {
+#ifdef __ANDROID__
     signaled = 0;
 
     __android_log_close();
@@ -2739,8 +2755,12 @@
 
     EXPECT_LT(0, ret);
     EXPECT_EQ(1U, signaled);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
 
+#ifdef __ANDROID__
 // meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
 static testing::AssertionResult IsOk(bool ok, std::string &message) {
     return ok ?
@@ -2748,6 +2768,26 @@
         (testing::AssertionFailure() << message);
 }
 
+// must be: '<needle:> 0 kB'
+static bool isZero(const std::string &content, std::string::size_type pos,
+                   const char* needle) {
+    std::string::size_type offset = content.find(needle, pos);
+    return (offset != std::string::npos) &&
+           ((offset = content.find_first_not_of(" \t", offset +
+                      strlen(needle))) != std::string::npos) &&
+           (content.find_first_not_of("0", offset) != offset);
+}
+
+// must not be: '<needle:> 0 kB'
+static bool isNotZero(const std::string &content, std::string::size_type pos,
+                      const char* needle) {
+    std::string::size_type offset = content.find(needle, pos);
+    return (offset != std::string::npos) &&
+           ((offset = content.find_first_not_of(" \t", offset +
+                      strlen(needle))) != std::string::npos) &&
+           (content.find_first_not_of("123456789", offset) != offset);
+}
+
 static void event_log_tags_test_smap(pid_t pid) {
     std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
 
@@ -2755,6 +2795,7 @@
     if (!android::base::ReadFileToString(filename, &content)) return;
 
     bool shared_ok = false;
+    bool private_ok = false;
     bool anonymous_ok = false;
     bool pass_ok = false;
 
@@ -2764,25 +2805,28 @@
         pos += strlen(event_log_tags);
 
         // must not be: 'Shared_Clean: 0 kB'
-        static const char shared_clean[] = "Shared_Clean:";
-        std::string::size_type clean = content.find(shared_clean, pos);
-        bool ok = (clean != std::string::npos) &&
-                  ((clean = content.find_first_not_of(" \t", clean +
-                                strlen(shared_clean))) != std::string::npos) &&
-                  (content.find_first_not_of("123456789", clean) != clean);
+        bool ok = isNotZero(content, pos, "Shared_Clean:") ||
+                  // If not /etc/event-log-tags, thus r/w, then half points
+                  // back for not 'Shared_Dirty: 0 kB'
+                  ((content.substr(pos - 5 - strlen(event_log_tags), 5) != "/etc/") &&
+                      isNotZero(content, pos, "Shared_Dirty:"));
         if (ok && !pass_ok) {
             shared_ok = true;
         } else if (!ok) {
             shared_ok = false;
         }
 
+        // must be: 'Private_Dirty: 0 kB' and 'Private_Clean: 0 kB'
+        ok = isZero(content, pos, "Private_Dirty:") ||
+             isZero(content, pos, "Private_Clean:");
+        if (ok && !pass_ok) {
+            private_ok = true;
+        } else if (!ok) {
+            private_ok = false;
+        }
+
         // must be: 'Anonymous: 0 kB'
-        static const char anonymous[] = "Anonymous:";
-        std::string::size_type anon = content.find(anonymous, pos);
-        ok = (anon != std::string::npos) &&
-             ((anon = content.find_first_not_of(" \t", anon +
-                          strlen(anonymous))) != std::string::npos) &&
-             (content.find_first_not_of("0", anon) != anon);
+        ok = isZero(content, pos, "Anonymous:");
         if (ok && !pass_ok) {
             anonymous_ok = true;
         } else if (!ok) {
@@ -2794,7 +2838,7 @@
     content = "";
 
     if (!pass_ok) return;
-    if (shared_ok && anonymous_ok) return;
+    if (shared_ok && anonymous_ok && private_ok) return;
 
     filename = android::base::StringPrintf("/proc/%d/comm", pid);
     android::base::ReadFileToString(filename, &content);
@@ -2802,10 +2846,13 @@
                   pid, content.substr(0, content.find("\n")).c_str());
 
     EXPECT_TRUE(IsOk(shared_ok, content));
+    EXPECT_TRUE(IsOk(private_ok, content));
     EXPECT_TRUE(IsOk(anonymous_ok, content));
 }
+#endif
 
 TEST(liblog, event_log_tags) {
+#ifdef __ANDROID__
     std::unique_ptr<DIR, int(*)(DIR*)> proc_dir(opendir("/proc"), closedir);
     ASSERT_FALSE(!proc_dir);
 
@@ -2819,4 +2866,7 @@
         if (id != pid) continue;
         event_log_tags_test_smap(pid);
     }
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
 }
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/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 42d4adb..356f65f 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -176,6 +176,13 @@
 int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc);
 
 /**
+ * sparse_file_block_size
+ *
+ * @s - sparse file cookie
+ */
+unsigned int sparse_file_block_size(struct sparse_file *s);
+
+/**
  * sparse_file_callback - call a callback for blocks in sparse file
  *
  * @s - sparse file cookie
@@ -197,6 +204,24 @@
 		int (*write)(void *priv, const void *data, int len), void *priv);
 
 /**
+ * sparse_file_foreach_chunk - call a callback for data blocks in sparse file
+ *
+ * @s - sparse file cookie
+ * @sparse - write in the Android sparse file format
+ * @crc - append a crc chunk
+ * @write - function to call for each block
+ * @priv - value that will be passed as the first argument to write
+ *
+ * The function has the same behavior as 'sparse_file_callback', except it only
+ * iterates on blocks that contain data.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
+	int (*write)(void *priv, const void *data, int len, unsigned int block,
+		     unsigned int nr_blocks),
+	void *priv);
+/**
  * sparse_file_read - read a file into a sparse file cookie
  *
  * @s - sparse file cookie
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 311678a..b175860 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -199,6 +199,57 @@
 	return ret;
 }
 
+struct chunk_data {
+	void		*priv;
+	unsigned int	block;
+	unsigned int	nr_blocks;
+	int (*write)(void *priv, const void *data, int len, unsigned int block,
+		     unsigned int nr_blocks);
+};
+
+static int foreach_chunk_write(void *priv, const void *data, int len)
+{
+	struct chunk_data *chk = priv;
+
+	return chk->write(chk->priv, data, len, chk->block, chk->nr_blocks);
+}
+
+int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
+	int (*write)(void *priv, const void *data, int len, unsigned int block,
+		     unsigned int nr_blocks),
+	void *priv)
+{
+	int ret;
+	int chunks;
+	struct chunk_data chk;
+	struct output_file *out;
+	struct backed_block *bb;
+
+	chk.priv = priv;
+	chk.write = write;
+	chk.block = chk.nr_blocks = 0;
+	chunks = sparse_count_chunks(s);
+	out = output_file_open_callback(foreach_chunk_write, &chk,
+					s->block_size, s->len, false, sparse,
+					chunks, crc);
+
+	if (!out)
+		return -ENOMEM;
+
+	for (bb = backed_block_iter_new(s->backed_block_list); bb;
+			bb = backed_block_iter_next(bb)) {
+		chk.block = backed_block_block(bb);
+		chk.nr_blocks = (backed_block_len(bb) - 1) / s->block_size + 1;
+		ret = sparse_file_write_block(out, bb);
+		if (ret)
+			return ret;
+	}
+
+	output_file_close(out);
+
+	return ret;
+}
+
 static int out_counter_write(void *priv, const void *data __unused, int len)
 {
 	int64_t *count = priv;
@@ -230,6 +281,11 @@
 	return count;
 }
 
+unsigned int sparse_file_block_size(struct sparse_file *s)
+{
+	return s->block_size;
+}
+
 static struct backed_block *move_chunks_up_to_len(struct sparse_file *from,
 		struct sparse_file *to, unsigned int len)
 {
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index d3fb45f..3457d5b 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -24,6 +24,7 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include <string.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -35,12 +36,24 @@
 #define SYS_POWER_STATE "/sys/power/state"
 #define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
 
+#define BASE_SLEEP_TIME 100000
+
 static int state_fd;
 static int wakeup_count_fd;
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
 static void (*wakeup_func)(bool success) = NULL;
+static int sleep_time = BASE_SLEEP_TIME;
+
+static void update_sleep_time(bool success) {
+    if (success) {
+        sleep_time = BASE_SLEEP_TIME;
+        return;
+    }
+    // double sleep time after each failure up to one minute
+    sleep_time = MIN(sleep_time * 2, 60000000);
+}
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -48,10 +61,12 @@
     char wakeup_count[20];
     int wakeup_count_len;
     int ret;
-    bool success;
+    bool success = true;
 
     while (1) {
-        usleep(100000);
+        update_sleep_time(success);
+        usleep(sleep_time);
+        success = false;
         ALOGV("%s: read wakeup_count\n", __func__);
         lseek(wakeup_count_fd, 0, SEEK_SET);
         wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
@@ -75,7 +90,6 @@
             continue;
         }
 
-        success = true;
         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
         ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
         if (ret < 0) {
@@ -84,8 +98,8 @@
         } else {
             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
             ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
-            if (ret < 0) {
-                success = false;
+            if (ret >= 0) {
+                success = true;
             }
             void (*func)(bool success) = wakeup_func;
             if (func != NULL) {
diff --git a/libsync/sync.c b/libsync/sync.c
index 169dc36..6281b20 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -21,8 +21,6 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <linux/sw_sync.h>
-
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -42,6 +40,16 @@
 #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
 #define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, struct sync_fence_info_data)
 
+struct sw_sync_create_fence_data {
+  __u32 value;
+  char name[32];
+  __s32 fence;
+};
+
+#define SW_SYNC_IOC_MAGIC 'W'
+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
+
 int sync_wait(int fd, int timeout)
 {
     __s32 to = timeout;
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 52f28af..1b6076f 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -50,6 +50,7 @@
     errorRate = 0;
     mCommandCount = 0;
     mWithSeq = withSeq;
+    mSkipToNextNullByte = false;
 }
 
 bool FrameworkListener::onDataAvailable(SocketClient *c) {
@@ -60,10 +61,15 @@
     if (len < 0) {
         SLOGE("read() failed (%s)", strerror(errno));
         return false;
-    } else if (!len)
+    } else if (!len) {
         return false;
-   if(buffer[len-1] != '\0')
+    } else if (buffer[len-1] != '\0') {
         SLOGW("String is not zero-terminated");
+        android_errorWriteLog(0x534e4554, "29831647");
+        c->sendMsg(500, "Command too large for buffer", false);
+        mSkipToNextNullByte = true;
+        return false;
+    }
 
     int offset = 0;
     int i;
@@ -71,11 +77,16 @@
     for (i = 0; i < len; i++) {
         if (buffer[i] == '\0') {
             /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
-            dispatchCommand(c, buffer + offset);
+            if (mSkipToNextNullByte) {
+                mSkipToNextNullByte = false;
+            } else {
+                dispatchCommand(c, buffer + offset);
+            }
             offset = i + 1;
         }
     }
 
+    mSkipToNextNullByte = false;
     return true;
 }
 
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 25c779e..217b8c3 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -86,6 +86,13 @@
                 "ProcessCallStack.cpp",
             ],
         },
+        linux_bionic: {
+            enabled: true,
+            srcs: [
+                "Looper.cpp",
+                "ProcessCallStack.cpp",
+            ],
+        },
 
         darwin: {
             cflags: ["-Wno-unused-parameter"],
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 5ed0fe8..fce1378 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -62,7 +62,17 @@
         android: {
             static_libs: ["libz"],
         },
-        host: {
+        linux_bionic: {
+            static_libs: ["libz"],
+            enabled: true,
+        },
+        linux: {
+            shared_libs: ["libz-host"],
+        },
+        darwin: {
+            shared_libs: ["libz-host"],
+        },
+        windows: {
             shared_libs: ["libz-host"],
         },
     },
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index d36cc3f..0ac6f2c 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -267,9 +267,14 @@
    * Grab the CD offset and size, and the number of entries in the
    * archive and verify that they look reasonable.
    */
-  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+  if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
         eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
+#if defined(__ANDROID__)
+    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
+      android_errorWriteLog(0x534e4554, "31251826");
+    }
+#endif
     return kInvalidOffset;
   }
   if (eocd->num_records == 0) {
@@ -781,7 +786,8 @@
   // Creates a FileWriter for |fd| and prepare to write |entry| to it,
   // guaranteeing that the file descriptor is valid and that there's enough
   // space on the volume to write out the entry completely and that the file
-  // is truncated to the correct length.
+  // is truncated to the correct length (no truncation if |fd| references a
+  // block device).
   //
   // Returns a valid FileWriter on success, |nullptr| if an error occurred.
   static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
@@ -814,13 +820,22 @@
     }
 #endif  // __linux__
 
-    result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-    if (result == -1) {
-      ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-            static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+    struct stat sb;
+    if (fstat(fd, &sb) == -1) {
+      ALOGW("Zip: unable to fstat file: %s", strerror(errno));
       return std::unique_ptr<FileWriter>(nullptr);
     }
 
+    // Block device doesn't support ftruncate(2).
+    if (!S_ISBLK(sb.st_mode)) {
+      result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+      if (result == -1) {
+        ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        return std::unique_ptr<FileWriter>(nullptr);
+      }
+    }
+
     return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
   }
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d0c693d..c204a16 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -81,6 +81,7 @@
 static size_t g_maxCount;
 static size_t g_printCount;
 static bool g_printItAnyways;
+static bool g_debug;
 
 enum helpType {
     HELP_FALSE,
@@ -176,7 +177,7 @@
         static EventTagMap *eventTagMap = NULL;
 
         if (!eventTagMap && !hasOpenedEventTagMap) {
-            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            eventTagMap = android_openEventTagMap(NULL);
             hasOpenedEventTagMap = true;
         }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
@@ -188,7 +189,7 @@
     } else {
         err = android_log_processLogBuffer(&buf->entry_v1, &entry);
     }
-    if (err < 0) {
+    if ((err < 0) && !g_debug) {
         goto error;
     }
 
@@ -320,7 +321,7 @@
                     "  -g, --buffer-size                      Get the size of the ring buffer.\n"
                     "  -G <size>, --buffer-size=<size>\n"
                     "                  Set size of log ring buffer, may suffix with K or M.\n"
-                    "  -L, -last       Dump logs from prior to last reboot\n"
+                    "  -L, --last      Dump logs from prior to last reboot\n"
                     // Leave security (Device Owner only installations) and
                     // kernel (userdebug and eng) buffers undocumented.
                     "  -b <buffer>, --buffer=<buffer>         Request alternate ring buffer, 'main',\n"
@@ -619,6 +620,7 @@
         int option_index = 0;
         // list of long-argument only strings for later comparison
         static const char pid_str[] = "pid";
+        static const char debug_str[] = "debug";
         static const char id_str[] = "id";
         static const char wrap_str[] = "wrap";
         static const char print_str[] = "print";
@@ -627,6 +629,7 @@
           { "buffer",        required_argument, NULL,   'b' },
           { "buffer-size",   optional_argument, NULL,   'g' },
           { "clear",         no_argument,       NULL,   'c' },
+          { debug_str,       no_argument,       NULL,   0 },
           { "dividers",      no_argument,       NULL,   'D' },
           { "file",          required_argument, NULL,   'f' },
           { "format",        required_argument, NULL,   'v' },
@@ -691,6 +694,10 @@
                     g_printItAnyways = true;
                     break;
                 }
+                if (long_options[option_index].name == debug_str) {
+                    g_debug = true;
+                    break;
+                }
                 if (long_options[option_index].name == id_str) {
                     setId = optarg && optarg[0] ? optarg : NULL;
                     break;
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 1da1942..b082a64 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -35,7 +35,8 @@
     # all exec/services are called with umask(077), so no gain beyond 0700
     mkdir /data/misc/logd 0700 logd log
     # logd for write to /data/misc/logd, log group for read from pstore (-L)
-    exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
+    # b/28788401 b/30041146 b/30612424
+    # exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
     start logcatd
 
 # stop logcatd service and clear data
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 18067dc..11cffe6 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -29,6 +29,7 @@
 
 #include <gtest/gtest.h>
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #define BIG_BUFFER (5 * 1024)
 
@@ -1091,7 +1092,7 @@
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *hold = *list;
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1126,7 +1127,7 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1255,19 +1256,25 @@
     va_end(ap);
 
     char *str = NULL;
-    asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+    asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
     std::string expect(str);
     free(str);
 
     int count = 0;
     pid_t pid = getpid();
     std::string lastMatch;
+    int maxMatch = 1;
     while (fgets(buffer, sizeof(buffer), fp)) {
+        char space;
         char newline;
         int p;
-        int ret = sscanf(buffer, expect.c_str(), &p, &newline);
-        if ((2 == ret) && (p == pid) && (newline == '\n')) ++count;
-        else if ((1 == ret) && (p == pid) && (count == 0)) lastMatch = buffer;
+        int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
+        if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
+            ++count;
+        } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
+            lastMatch = buffer;
+            maxMatch = ret;
+        }
     }
 
     pclose(fp);
@@ -1289,7 +1296,7 @@
 
     {
         static const struct tag hhgtg = { 42, "answer" };
-        android_log_event_context ctx(hhgtg.tagNo);
+        android_log_event_list ctx(hhgtg.tagNo);
         static const char theAnswer[] = "what is five by seven";
         ctx << theAnswer;
         ctx.write();
@@ -1301,7 +1308,7 @@
         static const struct tag sync = { 2720, "sync" };
         static const char id[] = "logcat.decriptive";
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1311,7 +1318,7 @@
 
         // Partial match to description
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1321,7 +1328,7 @@
 
         // Negative Test of End_to_End, ensure it is working
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
             ctx.write();
             fprintf(stderr, "Expect a \"Closest match\" message\n");
@@ -1334,7 +1341,7 @@
     {
         static const struct tag sync = { 2747, "contacts_aggregation" };
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)30 << (int32_t)2;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1342,7 +1349,7 @@
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint64_t)31570 << (int32_t)911;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr,
@@ -1353,46 +1360,52 @@
     {
         static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)512;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3072;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097152;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)2097153;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)1073741824;
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
         }
 
         {
-            android_log_event_context ctx(sync.tagNo);
+            android_log_event_list ctx(sync.tagNo);
             ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
             ctx.write();
             EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
         }
     }
 
+    {
+        static const struct tag sync = { 27501, "notification_panel_hidden" };
+        android_log_event_list ctx(sync.tagNo);
+        ctx.write();
+        EXPECT_TRUE(End_to_End(sync.tagStr, ""));
+    }
 }
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 7394f11..52c6742 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -48,6 +48,7 @@
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
     registerCmd(new ReinitCmd());
+    registerCmd(new ExitCmd(this));
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
@@ -297,6 +298,21 @@
     return 0;
 }
 
+CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
+        LogCommand("EXIT"),
+        mParent(*parent) {
+}
+
+int CommandListener::ExitCmd::runCommand(SocketClient * cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+
+    cli->sendMsg("success");
+    release(cli);
+
+    return 0;
+}
+
 int CommandListener::getLogSocket() {
     static const char socketName[] = "logd";
     int sock = android_get_control_socket(socketName);
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index cbcd601..5d50177 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -52,22 +52,38 @@
         explicit name##Cmd(LogBuffer *buf);                      \
         virtual ~name##Cmd() {}                                  \
         int runCommand(SocketClient *c, int argc, char ** argv); \
-    };
+    }
 
-    LogBufferCmd(Clear)
-    LogBufferCmd(GetBufSize)
-    LogBufferCmd(SetBufSize)
-    LogBufferCmd(GetBufSizeUsed)
-    LogBufferCmd(GetStatistics)
-    LogBufferCmd(GetPruneList)
-    LogBufferCmd(SetPruneList)
+    LogBufferCmd(Clear);
+    LogBufferCmd(GetBufSize);
+    LogBufferCmd(SetBufSize);
+    LogBufferCmd(GetBufSizeUsed);
+    LogBufferCmd(GetStatistics);
+    LogBufferCmd(GetPruneList);
+    LogBufferCmd(SetPruneList);
 
-    class ReinitCmd : public LogCommand {
-    public:
-        ReinitCmd();
-        virtual ~ReinitCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
+#define LogCmd(name)                                             \
+    class name##Cmd : public LogCommand {                        \
+    public:                                                      \
+        name##Cmd();                                             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+    }
+
+    LogCmd(Reinit);
+
+#define LogParentCmd(name)                                       \
+    class name##Cmd : public LogCommand {                        \
+        CommandListener &mParent;                                \
+    public:                                                      \
+        name##Cmd();                                             \
+        explicit name##Cmd(CommandListener *parent);             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+        void release(SocketClient *c) { mParent.release(c); }    \
+    }
+
+    LogParentCmd(Exit);
 
 };
 
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index c3ccd84..aa05932 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -34,6 +34,7 @@
 #include "LogBuffer.h"
 #include "LogKlog.h"
 #include "LogReader.h"
+#include "LogUtils.h"
 
 #define KMSG_PRIORITY(PRI)                          \
     '<',                                            \
@@ -117,7 +118,8 @@
             if (avcl) {
                 char *avcr = strstr(str, avc);
 
-                skip = avcr && !strcmp(avcl + strlen(avc), avcr + strlen(avc));
+                skip = avcr && !fastcmp<strcmp>(avcl + strlen(avc),
+                                                avcr + strlen(avc));
                 if (skip) {
                     ++count;
                     free(last_str);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a009433..d476596 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -33,6 +33,7 @@
 #include "LogBuffer.h"
 #include "LogKlog.h"
 #include "LogReader.h"
+#include "LogUtils.h"
 
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -110,9 +111,65 @@
         mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
 
+    log_id_for_each(i) {
+        lastLoggedElements[i] = NULL;
+        droppedElements[i] = NULL;
+    }
+
     init();
 }
 
+LogBuffer::~LogBuffer() {
+    log_id_for_each(i) {
+        delete lastLoggedElements[i];
+        delete droppedElements[i];
+    }
+}
+
+static bool identical(LogBufferElement* elem, LogBufferElement* last) {
+    // is it mostly identical?
+//  if (!elem) return false;
+    unsigned short lenl = elem->getMsgLen();
+    if (!lenl) return false;
+//  if (!last) return false;
+    unsigned short lenr = last->getMsgLen();
+    if (!lenr) return false;
+//  if (elem->getLogId() != last->getLogId()) return false;
+    if (elem->getUid() != last->getUid()) return false;
+    if (elem->getPid() != last->getPid()) return false;
+    if (elem->getTid() != last->getTid()) return false;
+
+    // last is more than a minute old, stop squashing identical messages
+    if (elem->getRealTime().nsec() >
+        (last->getRealTime().nsec() + 60 * NS_PER_SEC)) return false;
+
+    // Identical message
+    const char* msgl = elem->getMsg();
+    const char* msgr = last->getMsg();
+    if ((lenl == lenr) && !fastcmp<memcmp>(msgl, msgr, lenl)) return true;
+
+    // audit message (except sequence number) identical?
+    static const char avc[] = "): avc: ";
+
+    if (last->isBinary()) {
+        if (fastcmp<memcmp>(msgl, msgr,
+                            sizeof(android_log_event_string_t) -
+                                sizeof(int32_t))) return false;
+        msgl += sizeof(android_log_event_string_t);
+        lenl -= sizeof(android_log_event_string_t);
+        msgr += sizeof(android_log_event_string_t);
+        lenr -= sizeof(android_log_event_string_t);
+    }
+    const char *avcl = android::strnstr(msgl, lenl, avc);
+    if (!avcl) return false;
+    lenl -= avcl - msgl;
+    const char *avcr = android::strnstr(msgr, lenr, avc);
+    if (!avcr) return false;
+    lenr -= avcr - msgr;
+    if (lenl != lenr) return false;
+    return !fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl);
+}
+
 int LogBuffer::log(log_id_t log_id, log_time realtime,
                    uid_t uid, pid_t pid, pid_t tid,
                    const char *msg, unsigned short len) {
@@ -145,14 +202,57 @@
     }
 
     pthread_mutex_lock(&mLogElementsLock);
+    LogBufferElement* currentLast = lastLoggedElements[log_id];
+    if (currentLast) {
+        LogBufferElement *dropped = droppedElements[log_id];
+        unsigned short count = dropped ? dropped->getDropped() : 0;
+        if (identical(elem, currentLast)) {
+            if (dropped) {
+                if (count == USHRT_MAX) {
+                    log(dropped);
+                    count = 1;
+                } else {
+                    delete dropped;
+                    ++count;
+                }
+            }
+            if (count) {
+                stats.add(currentLast);
+                stats.subtract(currentLast);
+                currentLast->setDropped(count);
+            }
+            droppedElements[log_id] = currentLast;
+            lastLoggedElements[log_id] = elem;
+            pthread_mutex_unlock(&mLogElementsLock);
+            return len;
+        }
+        if (dropped) {
+            log(dropped);
+            droppedElements[log_id] = NULL;
+        }
+        if (count) {
+            log(currentLast);
+        } else {
+            delete currentLast;
+        }
+    }
+    lastLoggedElements[log_id] = new LogBufferElement(*elem);
 
+    log(elem);
+    pthread_mutex_unlock(&mLogElementsLock);
+
+    return len;
+}
+
+// assumes mLogElementsLock held, owns elem, will look after garbage collection
+void LogBuffer::log(LogBufferElement* elem) {
     // Insert elements in time sorted order if possible
     //  NB: if end is region locked, place element at end of list
     LogBufferElementCollection::iterator it = mLogElements.end();
     LogBufferElementCollection::iterator last = it;
     while (last != mLogElements.begin()) {
         --it;
-        if ((*it)->getRealTime() <= realtime) {
+        if ((*it)->getRealTime() <= elem->getRealTime()) {
             break;
         }
         last = it;
@@ -169,7 +269,7 @@
 
         LastLogTimes::iterator times = mTimes.begin();
         while(times != mTimes.end()) {
-            LogTimeEntry *entry = (*times);
+            LogTimeEntry* entry = (*times);
             if (entry->owned_Locked()) {
                 if (!entry->mNonBlock) {
                     end_always = true;
@@ -187,17 +287,14 @@
                 || (end_set && (end >= (*last)->getSequence()))) {
             mLogElements.push_back(elem);
         } else {
-            mLogElements.insert(last,elem);
+            mLogElements.insert(last, elem);
         }
 
         LogTimeEntry::unlock();
     }
 
     stats.add(elem);
-    maybePrune(log_id);
-    pthread_mutex_unlock(&mLogElementsLock);
-
-    return len;
+    maybePrune(elem->getLogId());
 }
 
 // Prune at most 10% of the log entries or maxPrune, whichever is less.
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index ff9692e..932d55f 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -99,10 +99,15 @@
 
     bool monotonic;
 
+    LogBufferElement* lastLoggedElements[LOG_ID_MAX];
+    LogBufferElement* droppedElements[LOG_ID_MAX];
+    void log(LogBufferElement* elem);
+
 public:
     LastLogTimes &mTimes;
 
     explicit LogBuffer(LastLogTimes *times);
+    ~LogBuffer();
     void init();
     bool isMonotonic() { return monotonic; }
 
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index f5c60c7..5e37a30 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -50,6 +50,19 @@
         0;
 }
 
+LogBufferElement::LogBufferElement(const LogBufferElement &elem) :
+        mTag(elem.mTag),
+        mUid(elem.mUid),
+        mPid(elem.mPid),
+        mTid(elem.mTid),
+        mSequence(elem.mSequence),
+        mRealTime(elem.mRealTime),
+        mMsgLen(elem.mMsgLen),
+        mLogId(elem.mLogId) {
+    mMsg = new char[mMsgLen];
+    memcpy(mMsg, elem.mMsg, mMsgLen);
+}
+
 LogBufferElement::~LogBufferElement() {
     delete [] mMsg;
 }
@@ -89,7 +102,7 @@
         size_t name_len = strlen(name);
         // KISS: ToDo: Only checks prefix truncated, not suffix, or both
         if ((retval_len < name_len)
-                && !fast<strcmp>(retval, name + name_len - retval_len)) {
+                && !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
             free(retval);
             retval = name;
         } else {
@@ -157,8 +170,6 @@
                           mDropped, (mDropped > 1) ? "s" : "");
 
     size_t hdrLen;
-    // LOG_ID_SECURITY not strictly needed since spam filter not activated,
-    // but required for accuracy.
     if (isBinary()) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index fb7fbed..f8ffacd 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -59,6 +59,7 @@
     LogBufferElement(log_id_t log_id, log_time realtime,
                      uid_t uid, pid_t pid, pid_t tid,
                      const char *msg, unsigned short len);
+    LogBufferElement(const LogBufferElement &elem);
     virtual ~LogBufferElement();
 
     bool isBinary(void) const {
@@ -79,6 +80,7 @@
         return mDropped = value;
     }
     unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
+    const char* getMsg() const { return mMsg; }
     uint64_t getSequence(void) const { return mSequence; }
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index fe08846..f224079 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -306,22 +306,18 @@
 static const char resumeStr[] = "PM: suspend exit ";
 static const char suspendedStr[] = "Suspended for ";
 
-static const char *strnstr(const char *s, size_t len, const char *needle) {
+const char* android::strnstr(const char* s, size_t len, const char* needle) {
     char c;
 
-    if (!len) {
-        return NULL;
-    }
+    if (!len) return NULL;
     if ((c = *needle++) != 0) {
         size_t needleLen = strlen(needle);
         do {
             do {
-                if (len <= needleLen) {
-                    return NULL;
-                }
+                if (len <= needleLen) return NULL;
                 --len;
             } while (*s++ != c);
-        } while (fast<memcmp>(s, needle, needleLen));
+        } while (fastcmp<memcmp>(s, needle, needleLen));
         s--;
     }
     return s;
@@ -349,25 +345,25 @@
             return;
         }
 
-        const char *b;
-        if (((b = strnstr(cp, len, suspendStr)))
+        const char* b;
+        if (((b = android::strnstr(cp, len, suspendStr)))
                 && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
             len -= b - cp;
             calculateCorrection(now, b, len);
-        } else if (((b = strnstr(cp, len, resumeStr)))
+        } else if (((b = android::strnstr(cp, len, resumeStr)))
                 && ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
             len -= b - cp;
             calculateCorrection(now, b, len);
-        } else if (((b = strnstr(cp, len, healthd)))
+        } else if (((b = android::strnstr(cp, len, healthd)))
                 && ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
-                && ((b = strnstr(b, len -= b - cp, battery)))
+                && ((b = android::strnstr(b, len -= b - cp, battery)))
                 && ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
             // NB: healthd is roughly 150us late, so we use it instead to
             //     trigger a check for ntp-induced or hardware clock drift.
             log_time real(CLOCK_REALTIME);
             log_time mono(CLOCK_MONOTONIC);
             correction = (real < mono) ? log_time::EPOCH : (real - mono);
-        } else if (((b = strnstr(cp, len, suspendedStr)))
+        } else if (((b = android::strnstr(cp, len, suspendedStr)))
                 && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
             len -= b - cp;
             log_time real;
@@ -402,7 +398,32 @@
     }
 }
 
-pid_t LogKlog::sniffPid(const char *cp, size_t len) {
+pid_t LogKlog::sniffPid(const char **buf, size_t len) {
+    const char *cp = *buf;
+    // HTC kernels with modified printk "c0   1648 "
+    if ((len > 9) &&
+            (cp[0] == 'c') &&
+            isdigit(cp[1]) &&
+            (isdigit(cp[2]) || (cp[2] == ' ')) &&
+            (cp[3] == ' ')) {
+        bool gotDigit = false;
+        int i;
+        for (i = 4; i < 9; ++i) {
+            if (isdigit(cp[i])) {
+                gotDigit = true;
+            } else if (gotDigit || (cp[i] != ' ')) {
+                break;
+            }
+        }
+        if ((i == 9) && (cp[i] == ' ')) {
+            int pid = 0;
+            char dummy;
+            if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
+                *buf = cp + 10; // skip-it-all
+                return pid;
+            }
+        }
+    }
     while (len) {
         // Mediatek kernels with modified printk
         if (*cp == '[') {
@@ -441,18 +462,14 @@
 
 // Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
 // compensated start time.
-void LogKlog::synchronize(const char *buf, size_t len) {
-    const char *cp = strnstr(buf, len, suspendStr);
+void LogKlog::synchronize(const char* buf, size_t len) {
+    const char* cp = android::strnstr(buf, len, suspendStr);
     if (!cp) {
-        cp = strnstr(buf, len, resumeStr);
-        if (!cp) {
-            return;
-        }
+        cp = android::strnstr(buf, len, resumeStr);
+        if (!cp) return;
     } else {
-        const char *rp = strnstr(buf, len, resumeStr);
-        if (rp && (rp < cp)) {
-            cp = rp;
-        }
+        const char* rp = android::strnstr(buf, len, resumeStr);
+        if (rp && (rp < cp)) cp = rp;
     }
 
     do {
@@ -466,7 +483,7 @@
     log_time now;
     sniffTime(now, &cp, len - (cp - buf), true);
 
-    const char *suspended = strnstr(buf, len, suspendedStr);
+    const char* suspended = android::strnstr(buf, len, suspendedStr);
     if (!suspended || (suspended > cp)) {
         return;
     }
@@ -556,12 +573,12 @@
 //  logd.klogd:
 // return -1 if message logd.klogd: <signature>
 //
-int LogKlog::log(const char *buf, size_t len) {
-    if (auditd && strnstr(buf, len, " audit(")) {
+int LogKlog::log(const char* buf, size_t len) {
+    if (auditd && android::strnstr(buf, len, " audit(")) {
         return 0;
     }
 
-    const char *p = buf;
+    const char* p = buf;
     int pri = parseKernelPrio(&p, len);
 
     log_time now;
@@ -569,7 +586,7 @@
 
     // sniff for start marker
     const char klogd_message[] = "logd.klogd: ";
-    const char *start = strnstr(p, len - (p - buf), klogd_message);
+    const char* start = android::strnstr(p, len - (p - buf), klogd_message);
     if (start) {
         uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
         if (sig == signature.nsec()) {
@@ -588,7 +605,7 @@
     }
 
     // Parse pid, tid and uid
-    const pid_t pid = sniffPid(p, len - (p - buf));
+    const pid_t pid = sniffPid(&p, len - (p - buf));
     const pid_t tid = pid;
     uid_t uid = AID_ROOT;
     if (pid) {
@@ -615,7 +632,7 @@
 
     static const char infoBrace[] = "[INFO]";
     static const size_t infoBraceLen = strlen(infoBrace);
-    if ((taglen >= infoBraceLen) && !fast<strncmp>(p, infoBrace, infoBraceLen)) {
+    if ((taglen >= infoBraceLen) && !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
         // <PRI>[<TIME>] "[INFO]"<tag> ":" message
         bt = p + infoBraceLen;
         taglen -= infoBraceLen;
@@ -650,7 +667,7 @@
             p = cp + 1;
         } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
             // clean up any tag stutter
-            if (!fast<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
+            if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
                 // <PRI>[<TIME>] <tag> <tag> : message
                 // <PRI>[<TIME>] <tag> <tag>: message
                 // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
@@ -672,8 +689,8 @@
                 static const char host[] = "_host";
                 static const size_t hostlen = strlen(host);
                 if ((size > hostlen) &&
-                        !fast<strncmp>(bt + size - hostlen, host, hostlen) &&
-                        !fast<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
+                        !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
+                        !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
                     const char *b = cp;
                     cp += size - hostlen;
                     taglen -= size - hostlen;
@@ -721,10 +738,10 @@
         // register names like x18 but not driver names like en0
             || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
         // blacklist
-            || ((size == cpuLen) && !fast<strncmp>(tag, cpu, cpuLen))
-            || ((size == warningLen) && !fast<strncasecmp>(tag, warning, warningLen))
-            || ((size == errorLen) && !fast<strncasecmp>(tag, error, errorLen))
-            || ((size == infoLen) && !fast<strncasecmp>(tag, info, infoLen))) {
+            || ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen))
+            || ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen))
+            || ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen))
+            || ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
         p = start;
         etag = tag = "";
     }
@@ -736,7 +753,7 @@
     const char *mp = strnrchr(tag, ']', taglen);
     if (mp && (++mp < etag)) {
         size_t s = etag - mp;
-        if (((s + s) < taglen) && !fast<memcmp>(mp, mp - 1 - s, s)) {
+        if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
             taglen = mp - tag;
         }
     }
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index d812436..11d88af 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -51,7 +51,7 @@
 
 protected:
     void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
-    pid_t sniffPid(const char *buf, size_t len);
+    pid_t sniffPid(const char **buf, size_t len);
     void calculateCorrection(const log_time &monotonic,
                              const char *real_string, size_t len);
     virtual bool onDataAvailable(SocketClient *cli);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 61d4c49..1b50b4e 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -108,7 +108,7 @@
     }
 
     bool nonBlock = false;
-    if (!fast<strncmp>(buffer, "dumpAndClose", 12)) {
+    if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
         // Allow writer to get some cycles, and wait for pending notifications
         sched_yield();
         LogTimeEntry::lock();
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index d4b48ef..ddbb64f 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -53,7 +53,7 @@
             if (ret > 0) {
                 buffer[sizeof(buffer)-1] = '\0';
                 // frameworks intermediate state
-                if (fast<strcmp>(buffer, "<pre-initialized>")) {
+                if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
                     retval = strdup(buffer);
                 }
             }
@@ -71,8 +71,17 @@
     mSizes[log_id] += size;
     ++mElements[log_id];
 
-    mSizesTotal[log_id] += size;
-    ++mElementsTotal[log_id];
+    if (element->getDropped()) {
+        ++mDroppedElements[log_id];
+    } else {
+        // When caller adding a chatty entry, they will have already
+        // called add() and subtract() for each entry as they are
+        // evaluated and trimmed, thus recording size and number of
+        // elements, but we must recognize the manufactured dropped
+        // entry as not contributing to the lifetime totals.
+        mSizesTotal[log_id] += size;
+        ++mElementsTotal[log_id];
+    }
 
     if (log_id == LOG_ID_KERNEL) {
         return;
@@ -182,7 +191,7 @@
     }
 
     // Parse /data/system/packages.list
-    uid_t userId = uid % AID_USER;
+    uid_t userId = uid % AID_USER_OFFSET;
     const char *name = android::uidToName(userId);
     if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
         name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
@@ -209,7 +218,7 @@
             if (nameTmp) {
                 if (!name) {
                     name = strdup(nameTmp);
-                } else if (fast<strcmp>(name, nameTmp)) {
+                } else if (fastcmp<strcmp>(name, nameTmp)) {
                     free(const_cast<char *>(name));
                     name = NULL;
                     break;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 1f598af..8bf655b 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -265,7 +265,7 @@
         if (pid != element->getPid()) {
             pid = -1;
         }
-        EntryBase::add(element);
+        EntryBaseDropped::add(element);
     }
 
     std::string formatHeader(const std::string &name, log_id_t id) const;
@@ -307,7 +307,7 @@
     const char*getName() const { return name; }
 
     inline void add(pid_t newPid) {
-        if (name && !fast<strncmp>(name, "zygote", 6)) {
+        if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
@@ -368,7 +368,7 @@
     const char*getName() const { return name; }
 
     inline void add(pid_t incomingTid) {
-        if (name && !fast<strncmp>(name, "zygote", 6)) {
+        if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
@@ -419,7 +419,7 @@
         if (pid != element->getPid()) {
             pid = -1;
         }
-        EntryBase::add(element);
+        EntryBaseDropped::add(element);
     }
 
     std::string formatHeader(const std::string &name, log_id_t id) const;
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 44ac742..d300a2a 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,6 +20,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+#include <utils/FastStrcmp.h>
 #include <private/android_logger.h>
 #include <sysutils/SocketClient.h>
 
@@ -39,6 +40,9 @@
 // Furnished in main.cpp. Thread safe.
 const char *tagToName(size_t *len, uint32_t tag);
 
+// Furnished by LogKlog.cpp.
+const char* strnstr(const char* s, size_t len, const char* needle);
+
 }
 
 // Furnished in LogCommand.cpp
@@ -50,21 +54,4 @@
             (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
 }
 
-template <int (*cmp)(const char *l, const char *r, const size_t s)>
-static inline int fast(const char *l, const char *r, const size_t s) {
-    return (*l != *r) || cmp(l + 1, r + 1, s - 1);
-}
-
-template <int (*cmp)(const void *l, const void *r, const size_t s)>
-static inline int fast(const void *lv, const void *rv, const size_t s) {
-    const char *l = static_cast<const char *>(lv);
-    const char *r = static_cast<const char *>(rv);
-    return (*l != *r) || cmp(l + 1, r + 1, s - 1);
-}
-
-template <int (*cmp)(const char *l, const char *r)>
-static inline int fast(const char *l, const char *r) {
-    return (*l != *r) || cmp(l + 1, r + 1);
-}
-
 #endif // _LOGD_LOG_UTILS_H__
diff --git a/logd/main.cpp b/logd/main.cpp
index d698976..c3343d7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -37,9 +37,9 @@
 #include <memory>
 
 #include <android-base/macros.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <cutils/files.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
@@ -311,7 +311,7 @@
     if (!map) {
         sem_wait(&sem_name);
         if (!map) {
-            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            map = android_openEventTagMap(NULL);
         }
         sem_post(&sem_name);
         if (!map) {
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 254a3f8..4e621e3 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -778,3 +778,102 @@
 
     close(fd);
 }
+
+static inline int32_t get4LE(const char* src)
+{
+    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+void __android_log_btwrite_multiple__helper(int count) {
+    log_time ts(CLOCK_MONOTONIC);
+
+    struct logger_list *logger_list;
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, 0)));
+
+    log_time ts1(CLOCK_MONOTONIC);
+
+    pid_t pid = fork();
+
+    if (pid == 0) {
+        // child
+        for (int i = count; i; --i) {
+            ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+            usleep(100);
+        }
+        ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+        usleep(1000000);
+
+        _exit(0);
+    }
+
+    siginfo_t info{};
+    ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
+
+    int expected_count = (count < 2) ? count : 2;
+    int expected_chatty_count = (count <= 2) ? 0 : 1;
+    int expected_expire_count = (count < 2) ? 0 : (count - 2);
+
+    count = 0;
+    int second_count = 0;
+    int chatty_count = 0;
+    int expire_count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+        if ((log_msg.entry.pid != pid) ||
+            (log_msg.entry.len < (4 + 1 + 8)) ||
+            (log_msg.id() != LOG_ID_EVENTS)) continue;
+
+        char *eventData = log_msg.msg();
+        if (!eventData) continue;
+
+        uint32_t tag = get4LE(eventData);
+
+        if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
+            if (tag != 0) continue;
+
+            log_time tx(eventData + 4 + 1);
+            if (ts == tx) {
+                ++count;
+            } else if (ts1 == tx) {
+                ++second_count;
+            }
+        } else if (eventData[4] == EVENT_TYPE_STRING) {
+            // chatty
+            if (tag != 1004) continue;
+            ++chatty_count;
+            // int len = get4LE(eventData + 4 + 1);
+            const char *cp = strstr(eventData + 4 + 1 + 4, " expire ");
+            if (!cp) continue;
+            unsigned val = 0;
+            sscanf(cp, " expire %u lines", &val);
+            expire_count += val;
+        }
+    }
+
+    EXPECT_EQ(expected_count, count);
+    EXPECT_EQ(1, second_count);
+    EXPECT_EQ(expected_chatty_count, chatty_count);
+    EXPECT_EQ(expected_expire_count, expire_count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(logd, multiple_test_1) {
+    __android_log_btwrite_multiple__helper(1);
+}
+
+TEST(logd, multiple_test_2) {
+    __android_log_btwrite_multiple__helper(2);
+}
+
+TEST(logd, multiple_test_3) {
+    __android_log_btwrite_multiple__helper(3);
+}
+
+TEST(logd, multiple_test_10) {
+    __android_log_btwrite_multiple__helper(10);
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e060a2c..7d0c87d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,6 +26,7 @@
 #######################################
 # asan.options
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
+
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := asan.options
@@ -34,6 +35,72 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT)
 
 include $(BUILD_PREBUILT)
+
+# Modules for asan.options.X files.
+
+ASAN_OPTIONS_FILES :=
+
+define create-asan-options-module
+include $$(CLEAR_VARS)
+LOCAL_MODULE := asan.options.$(1)
+ASAN_OPTIONS_FILES += asan.options.$(1)
+LOCAL_MODULE_CLASS := ETC
+# The asan.options.off.template tries to turn off as much of ASAN as is possible.
+LOCAL_SRC_FILES := asan.options.off.template
+LOCAL_MODULE_PATH := $(TARGET_OUT)
+include $$(BUILD_PREBUILT)
+endef
+
+# Pretty comprehensive set of native services. This list is helpful if all that's to be checked is an
+# app.
+ifeq ($(SANITIZE_LITE),true)
+SANITIZE_ASAN_OPTIONS_FOR := \
+  adbd \
+  ATFWD-daemon \
+  audioserver \
+  bridgemgrd \
+  cameraserver \
+  cnd \
+  debuggerd \
+  debuggerd64 \
+  dex2oat \
+  drmserver \
+  fingerprintd \
+  gatekeeperd \
+  installd \
+  keystore \
+  lmkd \
+  logcat \
+  logd \
+  lowi-server \
+  media.codec \
+  mediadrmserver \
+  media.extractor \
+  mediaserver \
+  mm-qcamera-daemon \
+  mpdecision \
+  netmgrd \
+  perfd \
+  perfprofd \
+  qmuxd \
+  qseecomd \
+  rild \
+  sdcard \
+  servicemanager \
+  slim_daemon \
+  surfaceflinger \
+  thermal-engine \
+  time_daemon \
+  update_engine \
+  vold \
+  wpa_supplicant \
+  zip
+endif
+
+ifneq ($(SANITIZE_ASAN_OPTIONS_FOR),)
+  $(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
+endif
+
 endif
 
 #######################################
@@ -47,15 +114,16 @@
 EXPORT_GLOBAL_ASAN_OPTIONS :=
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
   EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
-  LOCAL_REQUIRED_MODULES := asan.options
+  LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
 endif
 # Put it here instead of in init.rc module definition,
 # because init.rc is conditionally included.
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    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
@@ -63,6 +131,11 @@
 else
   LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
 endif
+ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
+  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
+else
+  LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache
+endif
 ifdef BOARD_ROOT_EXTRA_SYMLINKS
 # BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
   LOCAL_POST_INSTALL_CMD += $(foreach s, $(BOARD_ROOT_EXTRA_SYMLINKS),\
diff --git a/rootdir/asan.options b/rootdir/asan.options
index 43896a1..d728f12 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -3,3 +3,5 @@
 alloc_dealloc_mismatch=0
 allocator_may_return_null=1
 detect_container_overflow=0
+abort_on_error=1
+include_if_exists=/system/asan.options.%b
diff --git a/rootdir/asan.options.off.template b/rootdir/asan.options.off.template
new file mode 100644
index 0000000..59a1249
--- /dev/null
+++ b/rootdir/asan.options.off.template
@@ -0,0 +1,7 @@
+quarantine_size_mb=0
+max_redzone=16
+poison_heap=false
+poison_partial=false
+poison_array_cookie=false
+alloc_dealloc_mismatch=false
+new_delete_type_mismatch=false
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4e766bb..c0a0fce 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -50,12 +50,20 @@
     mkdir /dev/stune
     mount cgroup none /dev/stune schedtune
     mkdir /dev/stune/foreground
+    mkdir /dev/stune/background
+    mkdir /dev/stune/top-app
     chown system system /dev/stune
     chown system system /dev/stune/foreground
+    chown system system /dev/stune/background
+    chown system system /dev/stune/top-app
     chown system system /dev/stune/tasks
     chown system system /dev/stune/foreground/tasks
+    chown system system /dev/stune/background/tasks
+    chown system system /dev/stune/top-app/tasks
     chmod 0664 /dev/stune/tasks
     chmod 0664 /dev/stune/foreground/tasks
+    chmod 0664 /dev/stune/background/tasks
+    chmod 0664 /dev/stune/top-app/tasks
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
@@ -117,6 +125,12 @@
     write /proc/sys/kernel/sched_rt_runtime_us 950000
     write /proc/sys/kernel/sched_rt_period_us 1000000
 
+    # Assign reasonable ceiling values for socket rcv/snd buffers.
+    # These should almost always be overridden by the target per the
+    # the corresponding technology maximums.
+    write /proc/sys/net/core/rmem_max  262144
+    write /proc/sys/net/core/wmem_max  262144
+
     # reflect fwmark from incoming packets onto generated replies
     write /proc/sys/net/ipv4/fwmark_reflect 1
     write /proc/sys/net/ipv6/fwmark_reflect 1
@@ -134,16 +148,17 @@
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0666 /dev/cpuctl/tasks
-    write /dev/cpuctl/cpu.rt_runtime_us 800000
     write /dev/cpuctl/cpu.rt_period_us 1000000
+    write /dev/cpuctl/cpu.rt_runtime_us 950000
 
     mkdir /dev/cpuctl/bg_non_interactive
     chown system system /dev/cpuctl/bg_non_interactive/tasks
     chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
     # 5.0 %
     write /dev/cpuctl/bg_non_interactive/cpu.shares 52
-    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
+    # active FIFO threads will never be in BG
+    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 10000
 
     # sets up initial cpusets for ActivityManager
     mkdir /dev/cpuset
@@ -225,6 +240,8 @@
     # expecting it to point to /proc/self/fd
     symlink /proc/self/fd /dev/fd
 
+    export DOWNLOAD_CACHE /data/cache
+
     # set RLIMIT_NICE to allow priorities from 19 to -20
     setrlimit 13 40 40
 
@@ -293,11 +310,8 @@
     mount none /mnt/runtime/default /storage slave bind rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
-    restorecon_recursive /sys/kernel/debug
-
-    # On systems with tracefs, tracing is a separate mount, so make sure
-    # it too is correctly labeled
-    restorecon_recursive /sys/kernel/debug/tracing
+    # Note that tracefs may be mounted under debug, so we need to cross filesystems
+    restorecon --recursive --cross-filesystems /sys/kernel/debug
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -352,7 +366,7 @@
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell
-    bootchart_init
+    bootchart start
 
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom
@@ -415,6 +429,10 @@
     # create the A/B OTA directory, so as to enforce our permissions
     mkdir /data/ota 0771 root root
 
+    # create the OTA package directory. It will be accessed by GmsCore (cache
+    # group), update_engine and update_verifier.
+    mkdir /data/ota_package 0770 system cache
+
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
     chown system system /data/resource-cache
@@ -433,10 +451,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
@@ -459,10 +473,15 @@
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/media/obb 0770 media_rw media_rw
 
+    mkdir /data/cache 0770 system cache
+    mkdir /data/cache/recovery 0770 system cache
+    mkdir /data/cache/backup_stage 0700 system system
+    mkdir /data/cache/backup 0700 system system
+
     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
@@ -605,6 +624,9 @@
 on property:sys.powerctl=*
     powerctl ${sys.powerctl}
 
+on property:sys.boot_completed=1
+    bootchart stop
+
 # system server cannot write to /proc/sys files,
 # and chown/chmod does not work for /proc/sys/ entries.
 # So proxy writes through init.
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 1fd1e2a..915d159 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -103,7 +103,7 @@
 
 # Used to set USB configuration at boot and to switch the configuration
 # when changing the default configuration
-on property:persist.sys.usb.config=*
+on boot && property:persist.sys.usb.config=*
     setprop sys.usb.config ${persist.sys.usb.config}
 
 #
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index bfddcfa..eedeba8 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -10,4 +10,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1bbb007..84a907f 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -19,4 +19,4 @@
     group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 6742127..76e2b79 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -10,4 +10,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 81a7609..e918b67 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -19,4 +19,4 @@
     group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index aec51f4..e7b8cc2 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -165,12 +165,12 @@
   if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid");
 
   // Verify that user id is not too big.
-  if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+  if ((UID_MAX - info.uid) / AID_USER_OFFSET < (uid_t)userId) {
     error(1, 0, "user id too big: %d", userId);
   }
 
   // Calculate user app ID.
-  uid_t userAppId = (AID_USER * userId) + info.uid;
+  uid_t userAppId = (AID_USER_OFFSET * userId) + info.uid;
 
   // Reject system packages.
   if (userAppId < AID_APP) {
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index d4c51fd..3f0f95f 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -1026,7 +1026,13 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.lower_fd = h->fd;
+#else
     out.padding = 0;
+#endif
+
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1190,7 +1196,13 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.lower_fd = -1;
+#else
     out.padding = 0;
+#endif
+
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1262,17 +1274,19 @@
 #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;
     out.max_readahead = req->max_readahead;
     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.flags |= FUSE_SHORTCIRCUIT;
+#endif
+
     out.max_background = 32;
     out.congestion_threshold = 32;
     out.max_write = MAX_WRITE;
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index bc502a0..df3ce85 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -331,6 +331,27 @@
     return true;
 }
 
+static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
+                                        gid_t gid, mode_t mask) {
+    std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
+
+    if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
+            MS_BIND, nullptr) != 0) {
+        PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
+        return false;
+    }
+
+    if (mount(source_path.c_str(), dest_path.c_str(), "none",
+            MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
+        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+        if (umount2(dest_path.c_str(), MNT_DETACH))
+            PLOG(WARNING) << "Failed to unmount bind";
+        return false;
+    }
+
+    return true;
+}
+
 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
         gid_t gid, userid_t userid, bool multi_user, bool full_write) {
     std::string dest_path_default = "/mnt/runtime/default/" + label;
@@ -343,9 +364,8 @@
         // permissions are completely masked off.
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, 0027)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027)
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0027)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
@@ -355,9 +375,9 @@
         // deep inside attr_from_stat().
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
                                                       AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read,
                                                       AID_EVERYBODY, full_write ? 0027 : 0022)
-                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
                                                       AID_EVERYBODY, full_write ? 0007 : 0022)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5319ff4..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -81,15 +81,6 @@
 $(INPUT_H_LABELS_H):
 	$(transform-generated-source)
 
-# We only want 'r' on userdebug and eng builds.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := r.c
-LOCAL_CFLAGS += $(common_cflags)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_MODULE := r
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
-
 
 # We build BSD grep separately, so it can provide egrep and fgrep too.
 include $(CLEAR_VARS)
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 30053af..e6def6b 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -9,6 +9,7 @@
 #include <sys/limits.h>
 #include <sys/poll.h>
 #include <linux/input.h>
+#include <err.h>
 #include <errno.h>
 #include <unistd.h>
 
@@ -110,10 +111,8 @@
                 break;
             bits_size = res + 16;
             bits = realloc(bits, bits_size * 2);
-            if(bits == NULL) {
-                fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
-                return 1;
-            }
+            if(bits == NULL)
+                err(1, "failed to allocate buffer of size %d\n", (int)bits_size);
         }
         res2 = 0;
         switch(i) {
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27ea9e8..d7047e2 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -741,6 +741,7 @@
                 exit(1);
             }
         }
+        free(img);
     }
     return 0;
 }
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
-    fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
-    return -1;
-}
-
-int main(int argc, char *argv[])
-{
-    if(argc < 2) return usage();
-
-    int width = 4;
-    if(!strcmp(argv[1], "-b")) {
-        width = 1;
-        argc--;
-        argv++;
-    } else if(!strcmp(argv[1], "-s")) {
-        width = 2;
-        argc--;
-        argv++;
-    }
-
-    if(argc < 2) return usage();
-    uintptr_t addr = strtoptr(argv[1], 0, 16);
-
-    uintptr_t endaddr = 0;
-    char* end = strchr(argv[1], '-');
-    if (end)
-        endaddr = strtoptr(end + 1, 0, 16);
-
-    if (!endaddr)
-        endaddr = addr + width - 1;
-
-    if (endaddr <= addr) {
-        fprintf(stderr, "end address <= start address\n");
-        return -1;
-    }
-
-    bool set = false;
-    uint32_t value = 0;
-    if(argc > 2) {
-        set = true;
-        value = strtoul(argv[2], 0, 16);
-    }
-
-    int fd = open("/dev/mem", O_RDWR | O_SYNC);
-    if(fd < 0) {
-        fprintf(stderr,"cannot open /dev/mem\n");
-        return -1;
-    }
-
-    off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
-    size_t mmap_size = endaddr - mmap_start + 1;
-    mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-    void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
-                        MAP_SHARED, fd, mmap_start);
-
-    if(page == MAP_FAILED){
-        fprintf(stderr,"cannot mmap region\n");
-        return -1;
-    }
-
-    while (addr <= endaddr) {
-        switch(width){
-        case 4: {
-            uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
-            break;
-        }
-        case 2: {
-            uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
-            break;
-        }
-        case 1: {
-            uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
-            break;
-        }
-        }
-        addr += width;
-    }
-    return 0;
-}