resolve merge conflicts of 8eacf24 to nyc-dev-plus-aosp

Change-Id: I43a0ed3deded58a2d25a40b5053a43a5f517bcac
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index a856672..5aa878b 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -157,7 +157,7 @@
         "                                 (-r: replace existing application)\n"
         "                                 (-t: allow test packages)\n"
         "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
         "                                 (-g: grant all runtime permissions)\n"
         "  adb install-multiple [-lrtsdpg] <file...>\n"
         "                               - push this package file to the device and install it\n"
@@ -165,7 +165,7 @@
         "                                 (-r: replace existing application)\n"
         "                                 (-t: allow test packages)\n"
         "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
         "                                 (-p: partial application install)\n"
         "                                 (-g: grant all runtime permissions)\n"
         "  adb uninstall [-k] <package> - remove this app package from the device\n"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e3340af..f86a222 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -781,9 +781,7 @@
     // Local static allocation to avoid global non-POD variables.
     static const FeatureSet* features = new FeatureSet{
         kFeatureShell2,
-        // Internal master has 'cmd'. AOSP master doesn't.
-        // kFeatureCmd
-
+        kFeatureCmd
         // 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).
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7e60a72..636092e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -85,6 +85,8 @@
 static unsigned second_offset  = 0x00f00000;
 static unsigned tags_offset    = 0x00000100;
 
+static const std::string convert_fbe_marker_filename("convert_fbe");
+
 enum fb_buffer_type {
     FB_BUFFER,
     FB_BUFFER_SPARSE,
@@ -386,11 +388,17 @@
             "                                           given by --slot. If slots are not\n"
             "                                           supported, this does nothing. This will\n"
             "                                           run after all non-reboot commands.\n"
+#if !defined(_WIN32)
+            "  --wipe-and-use-fbe                       On devices which support it,\n"
+            "                                           erase userdata and cache, and\n"
+            "                                           enable file-based encryption\n"
+#endif
             "  --unbuffered                             Do not buffer input or output.\n"
             "  --version                                Display version.\n"
             "  -h, --help                               show this message.\n"
         );
 }
+
 static void* load_bootable_image(const char* kernel, const char* ramdisk,
                                  const char* secondstage, int64_t* sz,
                                  const char* cmdline) {
@@ -510,8 +518,60 @@
 
 #define tmpfile win32_tmpfile
 
+static std::string make_temporary_directory() {
+    fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
+    return "";
+}
+
+#else
+
+static std::string make_temporary_directory() {
+    const char *tmpdir = getenv("TMPDIR");
+    if (tmpdir == nullptr) {
+        tmpdir = P_tmpdir;
+    }
+    std::string result = std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
+    if (mkdtemp(&result[0]) == NULL) {
+        fprintf(stderr, "Unable to create temporary directory: %s\n",
+            strerror(errno));
+        return "";
+    }
+    return result;
+}
+
 #endif
 
+static std::string create_fbemarker_tmpdir() {
+    std::string dir = make_temporary_directory();
+    if (dir.empty()) {
+        fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
+        return "";
+    }
+    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+    int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
+    if (fd == -1) {
+        fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
+            marker_file.c_str(), errno, strerror(errno));
+        return "";
+    }
+    close(fd);
+    return dir;
+}
+
+static void delete_fbemarker_tmpdir(const std::string& dir) {
+    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+    if (unlink(marker_file.c_str()) == -1) {
+        fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
+            marker_file.c_str(), errno, strerror(errno));
+        return;
+    }
+    if (rmdir(dir.c_str()) == -1) {
+        fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
+            dir.c_str(), errno, strerror(errno));
+        return;
+    }
+}
+
 static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
     FILE* fp = tmpfile();
     if (fp == nullptr) {
@@ -1097,7 +1157,8 @@
 
 static void fb_perform_format(Transport* transport,
                               const char* partition, int skip_if_not_supported,
-                              const char* type_override, const char* size_override) {
+                              const char* type_override, const char* size_override,
+                              const std::string& initial_dir) {
     std::string partition_type, partition_size;
 
     struct fastboot_buffer buf;
@@ -1161,7 +1222,7 @@
     }
 
     fd = fileno(tmpfile());
-    if (fs_generator_generate(gen, fd, size)) {
+    if (fs_generator_generate(gen, fd, size, initial_dir)) {
         fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
         close(fd);
         return;
@@ -1190,6 +1251,7 @@
     bool wants_reboot_bootloader = false;
     bool wants_set_active = false;
     bool erase_first = true;
+    bool set_fbe_marker = false;
     void *data;
     int64_t sz;
     int longindex;
@@ -1212,6 +1274,9 @@
         {"slot", required_argument, 0, 0},
         {"set_active", optional_argument, 0, 'a'},
         {"set-active", optional_argument, 0, 'a'},
+#if !defined(_WIN32)
+        {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
         {0, 0, 0, 0}
     };
 
@@ -1293,6 +1358,15 @@
                 return 0;
             } else if (strcmp("slot", longopts[longindex].name) == 0) {
                 slot_override = std::string(optarg);
+#if !defined(_WIN32)
+            } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+                wants_wipe = true;
+                set_fbe_marker = true;
+#endif
+            } else {
+                fprintf(stderr, "Internal error in options processing for %s\n",
+                    longopts[longindex].name);
+                return 1;
             }
             break;
         default:
@@ -1390,7 +1464,8 @@
                 if (erase_first && needs_erase(transport, partition.c_str())) {
                     fb_queue_erase(partition.c_str());
                 }
-                fb_perform_format(transport, partition.c_str(), 0, type_override, size_override);
+                fb_perform_format(transport, partition.c_str(), 0,
+                    type_override, size_override, "");
             };
             do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
             skip(2);
@@ -1525,13 +1600,23 @@
     if (wants_wipe) {
         fprintf(stderr, "wiping userdata...\n");
         fb_queue_erase("userdata");
-        fb_perform_format(transport, "userdata", 1, nullptr, nullptr);
+        if (set_fbe_marker) {
+            fprintf(stderr, "setting FBE marker...\n");
+            std::string initial_userdata_dir = create_fbemarker_tmpdir();
+            if (initial_userdata_dir.empty()) {
+                return 1;
+            }
+            fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+            delete_fbemarker_tmpdir(initial_userdata_dir);
+        } else {
+            fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+        }
 
         std::string cache_type;
         if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
             fprintf(stderr, "wiping cache...\n");
             fb_queue_erase("cache");
-            fb_perform_format(transport, "cache", 1, nullptr, nullptr);
+            fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
         }
     }
     if (wants_set_active) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 90d8474..8539e23 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,8 @@
+#include "fs.h"
+
 #include "fastboot.h"
 #include "make_ext4fs.h"
 #include "make_f2fs.h"
-#include "fs.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -13,24 +14,32 @@
 
 #include <sparse/sparse.h>
 
-static int generate_ext4_image(int fd, long long partSize)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
 {
-    make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
-
+    if (initial_dir.empty()) {
+        make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+    } else {
+        make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+    }
     return 0;
 }
 
 #ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
 {
+    if (!initial_dir.empty()) {
+        fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
+        return -1;
+    }
     return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
 }
 #endif
 
 static const struct fs_generator {
-
     const char* fs_type;  //must match what fastboot reports for partition type
-    int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+    //returns 0 or error value
+    int (*generate)(int fd, long long partSize, const std::string& initial_dir);
 
 } generators[] = {
     { "ext4", generate_ext4_image},
@@ -48,7 +57,8 @@
     return nullptr;
 }
 
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+    const std::string& initial_dir)
 {
-    return gen->generate(tmpFileNo, partSize);
+    return gen->generate(tmpFileNo, partSize, initial_dir);
 }
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 289488b..0a68507 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,11 +1,13 @@
 #ifndef _FS_H_
 #define _FS_H_
 
+#include <string>
 #include <stdint.h>
 
 struct fs_generator;
 
 const struct fs_generator* fs_get_generator(const std::string& fs_type);
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+    const std::string& initial_dir);
 
 #endif
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index beb95de..1c7da30 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -88,6 +88,16 @@
                     msg->data.removed.finger.fid,
                     msg->data.removed.finger.gid);
             break;
+        case FINGERPRINT_TEMPLATE_ENUMERATING:
+            ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
+                    msg->data.enumerated.finger.fid,
+                    msg->data.enumerated.finger.gid,
+                    msg->data.enumerated.remaining_templates);
+            callback->onEnumerate(device,
+                    msg->data.enumerated.finger.fid,
+                    msg->data.enumerated.finger.gid,
+                    msg->data.enumerated.remaining_templates);
+            break;
         default:
             ALOGE("invalid msg type: %d", msg->type);
             return;
@@ -158,6 +168,11 @@
     return mDevice->remove(mDevice, groupId, fingerId);
 }
 
+int32_t FingerprintDaemonProxy::enumerate() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
+    return mDevice->enumerate(mDevice);
+}
+
 uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
     return mDevice->get_authenticator_id(mDevice);
 }
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 871c0e6..145b4c9 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -40,6 +40,7 @@
         virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
         virtual int32_t stopAuthentication();
         virtual int32_t remove(int32_t fingerId, int32_t groupId);
+        virtual int32_t enumerate();
         virtual uint64_t getAuthenticatorId();
         virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
         virtual int64_t openHal();
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
index 7131793..bc4af56 100644
--- a/fingerprintd/IFingerprintDaemon.cpp
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -125,6 +125,16 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case ENUMERATE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = enumerate();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
         case GET_AUTHENTICATOR_ID: {
             CHECK_INTERFACE(IFingerprintDaemon, data, reply);
             if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 1eb4ac1..23c36ff 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -44,6 +44,7 @@
            CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
            INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
            POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
+           ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
         };
 
         IFingerprintDaemon() { }
@@ -60,6 +61,7 @@
         virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
         virtual int32_t stopAuthentication() = 0;
         virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+        virtual int32_t enumerate() = 0;
         virtual uint64_t getAuthenticatorId() = 0;
         virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
         virtual int64_t openHal() = 0;
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 44d8020..19838c9 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -74,13 +74,13 @@
         return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
-            int32_t sz) {
+    virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
         Parcel data, reply;
         data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
         data.writeInt64(devId);
-        data.writeInt32Array(sz, fpIds);
-        data.writeInt32Array(sz, gpIds);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        data.writeInt32(rem);
         return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
index 6e32213..e343cb4 100644
--- a/fingerprintd/IFingerprintDaemonCallback.h
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -44,8 +44,7 @@
         virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
         virtual status_t onError(int64_t devId, int32_t error) = 0;
         virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
-        virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
-                int32_t sz) = 0;
+        virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0;
 
         DECLARE_META_INTERFACE(FingerprintDaemonCallback);
 };
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 02aff55..2d28b76 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,6 +101,7 @@
     char tmpmnt_opts[64] = "errors=remount-ro";
     char *e2fsck_argv[] = {
         E2FSCK_BIN,
+        "-f",
         "-y",
         blk_device
     };
@@ -439,12 +440,32 @@
     return ret;
 }
 
+static bool needs_block_encryption(const struct fstab_rec* rec)
+{
+    if (device_is_force_encrypted() && fs_mgr_is_encryptable(rec)) return true;
+    if (rec->fs_mgr_flags & MF_FORCECRYPT) return true;
+    if (rec->fs_mgr_flags & MF_CRYPT) {
+        /* Check for existence of convert_fde breadcrumb file */
+        char convert_fde_name[PATH_MAX];
+        snprintf(convert_fde_name, sizeof(convert_fde_name),
+                 "%s/misc/vold/convert_fde", rec->mount_point);
+        if (access(convert_fde_name, F_OK) == 0) return true;
+    }
+    if (rec->fs_mgr_flags & MF_FORCEFDEORFBE) {
+        /* Check for absence of convert_fbe breadcrumb file */
+        char convert_fbe_name[PATH_MAX];
+        snprintf(convert_fbe_name, sizeof(convert_fbe_name),
+                 "%s/convert_fbe", rec->mount_point);
+        if (access(convert_fbe_name, F_OK) != 0) return true;
+    }
+    return false;
+}
+
 // Check to see if a mountable volume has encryption requirements
-static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec)
+static int handle_encryptable(const struct fstab_rec* rec)
 {
     /* If this is block encryptable, need to trigger encryption */
-    if (   (rec->fs_mgr_flags & MF_FORCECRYPT)
-        || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
+    if (needs_block_encryption(rec)) {
         if (umount(rec->mount_point) == 0) {
             return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
         } else {
@@ -452,48 +473,15 @@
                     rec->mount_point, strerror(errno));
             return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
         }
-    }
-
+    } else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
     // Deal with file level encryption
-    if (rec->fs_mgr_flags & MF_FILEENCRYPTION) {
-        // Default or not yet initialized encryption requires no more work here
-        if (!e4crypt_non_default_key(rec->mount_point)) {
-            INFO("%s is default file encrypted\n", rec->mount_point);
-            return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED;
-        }
-
-        INFO("%s is non-default file encrypted\n", rec->mount_point);
-
-        // Uses non-default key, so must unmount and set up temp file system
-        if (umount(rec->mount_point)) {
-            ERROR("Failed to umount %s - rebooting\n", rec->mount_point);
-            return FS_MGR_MNTALL_FAIL;
-        }
-
-        if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) {
-            ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point);
-            return FS_MGR_MNTALL_FAIL;
-        }
-
-        // Mount data temporarily so we can access unencrypted dir
-        char tmp_mnt[PATH_MAX];
-        strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt));
-        strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt));
-        if (mkdir(tmp_mnt, 0700)) {
-            ERROR("Failed to create temp mount point\n");
-            return FS_MGR_MNTALL_FAIL;
-        }
-
-        if (fs_mgr_do_mount(fstab, rec->mount_point,
-                            rec->blk_device, tmp_mnt)) {
-            ERROR("Error temp mounting encrypted file system\n");
-            return FS_MGR_MNTALL_FAIL;
-        }
-
-        return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
+        INFO("%s is file encrypted\n", rec->mount_point);
+        return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
+    } else if (fs_mgr_is_encryptable(rec)) {
+        return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+    } else {
+        return FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
     }
-
-    return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
 }
 
 /* When multiple fstab records share the same mount_point, it will
@@ -504,7 +492,7 @@
 int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
-    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
     int error_count = 0;
     int mret = -1;
     int mount_errno = 0;
@@ -568,15 +556,15 @@
 
         /* Deal with encryptability. */
         if (!mret) {
-            int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]);
+            int status = handle_encryptable(&fstab->recs[attempted_idx]);
 
             if (status == FS_MGR_MNTALL_FAIL) {
                 /* Fatal error - no point continuing */
                 return status;
             }
 
-            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
-                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
+                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                     // Log and continue
                     ERROR("Only one encryptable/encrypted partition supported\n");
                 }
@@ -881,7 +869,8 @@
         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
             continue;
         }
-        if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
+        if (!(fstab->recs[i].fs_mgr_flags
+              & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
             continue;
         }
 
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index c63ff67..0b52e00 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -52,7 +52,7 @@
     info.len = (off64_t)dev_sz;
 
     /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
-    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL);
     if (rc) {
         ERROR("make_ext4fs returned %d.\n", rc);
     }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index cf35b3f..c8c624d 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -64,6 +64,7 @@
     { "encryptable=",MF_CRYPT },
     { "forceencrypt=",MF_FORCECRYPT },
     { "fileencryption",MF_FILEENCRYPTION },
+    { "forcefdeorfbe=",MF_FORCEFDEORFBE },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -140,6 +141,11 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
+                    /* The forcefdeorfbe flag is followed by an = and the
+                     * location of the keys.  Get it and return it.
+                     */
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
                 } 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.
@@ -464,7 +470,7 @@
 
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
-    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
+    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
 }
 
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
@@ -472,6 +478,11 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
+}
+
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ba0e097..181b6cd 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
 #define MF_FILEENCRYPTION 0x2000
 #define MF_FORMATTABLE  0x4000
 #define MF_SLOTSELECT   0x8000
+#define MF_FORCEFDEORFBE 0x10000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 27fccf7..0404dbd 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -74,12 +74,12 @@
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
-#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5
-#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4
-#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
-#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
-#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
-#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
+#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
+#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
+#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
+#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
 #define FS_MGR_MNTALL_FAIL -1
 int fs_mgr_mount_all(struct fstab *fstab);
 
@@ -102,6 +102,7 @@
 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);
+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);
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index c504f92..47a8bfa 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -18,9 +18,8 @@
 #include <iostream>
 
 #include <gtest/gtest.h>
-#include <UniquePtr.h>
-
 #include <hardware/hw_auth_token.h>
+#include <UniquePtr.h>
 
 #include "../SoftGateKeeper.h"
 
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 69647de..46a866a 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -40,6 +40,8 @@
 #define FAKE_BATTERY_CAPACITY 42
 #define FAKE_BATTERY_TEMPERATURE 424
 #define ALWAYS_PLUGGED_CAPACITY 100
+#define MILLION 1.0e6
+#define DEFAULT_VBUS_VOLTAGE 5000000
 
 namespace android {
 
@@ -62,6 +64,7 @@
     props->chargerUsbOnline = false;
     props->chargerWirelessOnline = false;
     props->maxChargingCurrent = 0;
+    props->maxChargingVoltage = 0;
     props->batteryStatus = BATTERY_STATUS_UNKNOWN;
     props->batteryHealth = BATTERY_HEALTH_UNKNOWN;
     props->batteryPresent = false;
@@ -255,6 +258,7 @@
         props.batteryTechnology = String8(buf);
 
     unsigned int i;
+    double MaxPower = 0;
 
     for (i = 0; i < mChargerNames.size(); i++) {
         String8 path;
@@ -283,11 +287,23 @@
                 path.clear();
                 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
                                   mChargerNames[i].string());
-                if (access(path.string(), R_OK) == 0) {
-                    int maxChargingCurrent = getIntField(path);
-                    if (props.maxChargingCurrent < maxChargingCurrent) {
-                        props.maxChargingCurrent = maxChargingCurrent;
-                    }
+                int ChargingCurrent =
+                    (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
+
+                path.clear();
+                path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
+                                  mChargerNames[i].string());
+
+                int ChargingVoltage =
+                    (access(path.string(), R_OK) == 0) ? getIntField(path) :
+                    DEFAULT_VBUS_VOLTAGE;
+
+                double power = ((double)ChargingCurrent / MILLION) *
+                        ((double)ChargingVoltage / MILLION);
+                if (MaxPower < power) {
+                    props.maxChargingCurrent = ChargingCurrent;
+                    props.maxChargingVoltage = ChargingVoltage;
+                    MaxPower = power;
                 }
             }
         }
@@ -416,9 +432,10 @@
     int v;
     char vs[128];
 
-    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d\n",
+    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
              props.chargerAcOnline, props.chargerUsbOnline,
-             props.chargerWirelessOnline, props.maxChargingCurrent);
+             props.chargerWirelessOnline, props.maxChargingCurrent,
+             props.maxChargingVoltage);
     write(fd, vs, strlen(vs));
     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
              props.batteryStatus, props.batteryHealth, props.batteryPresent);
@@ -637,7 +654,7 @@
             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
-	if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
         if (mHealthdConfig->batteryFullChargePath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index 70f0b92..be9e819 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -40,11 +40,18 @@
 #endif
 
 /*
- * Ensure that directory exists with given mode and owners.
+ * Ensure that directory exists with given mode and owners.  If it exists
+ * with a different mode or owners, they are fixed to match the given values.
  */
 extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
 
 /*
+ * Ensure that directory exists with given mode and owners.  If it exists
+ * with different owners, they are not fixed and -1 is returned.
+ */
+extern int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
+/*
  * Read single plaintext integer from given file, correctly handling files
  * partially written with fs_write_atomic_int().
  */
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
index 635ddb1..7e7f815 100644
--- a/include/cutils/multiuser.h
+++ b/include/cutils/multiuser.h
@@ -26,6 +26,8 @@
 // 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;
@@ -33,6 +35,7 @@
 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);
 
 #ifdef __cplusplus
 }
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
index 6a8d570..591bd44 100644
--- a/include/cutils/sched_policy.h
+++ b/include/cutils/sched_policy.h
@@ -29,6 +29,7 @@
     SP_SYSTEM     = 2,  // can't be used with set_sched_policy()
     SP_AUDIO_APP  = 3,
     SP_AUDIO_SYS  = 4,
+    SP_TOP_APP    = 5,
     SP_CNT,
     SP_MAX        = SP_CNT - 1,
     SP_SYSTEM_DEFAULT = SP_FOREGROUND,
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index 04238a6..c3ea1ed 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -19,7 +19,10 @@
 #ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
 #define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
 
+/* Android private interfaces */
+
 #include <stdint.h>
+#include <sys/types.h>
 
 #include <log/log.h>
 #include <log/log_read.h>
@@ -95,4 +98,35 @@
     char data[];
 } android_log_event_string_t;
 
+#if defined(__cplusplus)
+extern "C" {
 #endif
+
+#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
+#define ANDROID_LOG_PMSG_FILE_SEQUENCE     1000
+
+ssize_t __android_log_pmsg_file_write(
+        log_id_t logId,
+        char prio,
+        const char *filename,
+        const char *buf, size_t len);
+
+#define LOG_ID_ANY      ((log_id_t)-1)
+#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
+
+/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
+typedef ssize_t (*__android_log_pmsg_file_read_fn)(
+        log_id_t logId,
+        char prio,
+        const char *filename,
+        const char *buf, size_t len, void *arg);
+
+ssize_t __android_log_pmsg_file_read(
+        log_id_t logId, char prio, const char *prefix,
+        __android_log_pmsg_file_read_fn fn, void *arg);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_ */
diff --git a/include/system/graphics.h b/include/system/graphics.h
index cf2d7de..880cb9f 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -17,6 +17,7 @@
 #ifndef SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
 #define SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
 
+#include <stddef.h>
 #include <stdint.h>
 
 #ifdef __cplusplus
@@ -552,6 +553,37 @@
  * which describes both gamma curve and numeric range (within the bit depth).
  *
  * Other dataspaces include depth measurement data from a depth camera.
+ *
+ * A dataspace is comprised of a number of fields.
+ *
+ * Version
+ * --------
+ * The top 2 bits represent the revision of the field specification. This is
+ * currently always 0.
+ *
+ *
+ * bits    31-30 29                      -                          0
+ *        +-----+----------------------------------------------------+
+ * fields | Rev |            Revision specific fields                |
+ *        +-----+----------------------------------------------------+
+ *
+ * Field layout for version = 0:
+ * ----------------------------
+ *
+ * A dataspace is comprised of the following fields:
+ *      Standard
+ *      Transfer function
+ *      Range
+ *
+ * bits    31-30 29-27 26 -  22 21 -  16 15             -           0
+ *        +-----+-----+--------+--------+----------------------------+
+ * fields |  0  |Range|Transfer|Standard|    Legacy and custom       |
+ *        +-----+-----+--------+--------+----------------------------+
+ *          VV    RRR   TTTTT    SSSSSS    LLLLLLLL       LLLLLLLL
+ *
+ * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
+ * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
+ * or a custom value.
  */
 
 typedef enum android_dataspace {
@@ -580,14 +612,309 @@
     HAL_DATASPACE_ARBITRARY = 0x1,
 
     /*
-     * RGB Colorspaces
-     * -----------------
+     * Color-description aspects
      *
-     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
-     * of x and y specified by ISO 11664-1.
+     * The following aspects define various characteristics of the color
+     * specification. These represent bitfields, so that a data space value
+     * can specify each of them independently.
+     */
+
+    HAL_DATASPACE_STANDARD_SHIFT = 16,
+
+    /*
+     * Standard aspect
+     *
+     * Defines the chromaticity coordinates of the source primaries in terms of
+     * the CIE 1931 definition of x and y specified in ISO 11664-1.
+     */
+    HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT,  // 0x3F
+
+    /*
+     * Chromacity coordinates are unknown or are determined by the application.
+     * Implementations shall use the following suggested standards:
+     *
+     * All YCbCr formats: BT709 if size is 720p or larger (since most video
+     *                    content is letterboxed this corresponds to width is
+     *                    1280 or greater, or height is 720 or greater).
+     *                    BT601_625 if size is smaller than 720p or is JPEG.
+     * All RGB formats:   BT709.
+     *
+     * For all other formats standard is undefined, and implementations should use
+     * an appropriate standard for the data represented.
+     */
+    HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+     * for RGB conversion.
+     */
+    HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+     * for RGB conversion.
+     */
+    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+     * for RGB conversion (as in SMPTE 240M).
+     */
+    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion.
+     */
+    HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion using the linear domain.
+     */
+    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x      y
+     *  green           0.21   0.71
+     *  blue            0.14   0.08
+     *  red             0.67   0.33
+     *  white (C)       0.310  0.316
+     *
+     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+     * for RGB conversion.
+     */
+    HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    /*
+     * Primaries:       x       y
+     *  green           0.243   0.692
+     *  blue            0.145   0.049
+     *  red             0.681   0.319
+     *  white (C)       0.310   0.316
+     *
+     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+     * for RGB conversion.
+     */
+    HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
+
+    HAL_DATASPACE_TRANSFER_SHIFT = 22,
+
+    /*
+     * Transfer aspect
      *
      * Transfer characteristics are the opto-electronic transfer characteristic
      * at the source as a function of linear optical intensity (luminance).
+     *
+     * For digital signals, E corresponds to the recorded value. Normally, the
+     * transfer function is applied in RGB space to each of the R, G and B
+     * components independently. This may result in color shift that can be
+     * minized by applying the transfer function in Lab space only for the L
+     * component. Implementation may apply the transfer function in RGB space
+     * for all pixel formats if desired.
+     */
+
+    HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT,  // 0x1F
+
+    /*
+     * Transfer characteristics are unknown or are determined by the
+     * application.
+     *
+     * Implementations should use the following transfer functions:
+     *
+     * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
+     * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
+     *
+     * For all other formats transfer function is undefined, and implementations
+     * should use an appropriate standard for the data represented.
+     */
+    HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * Transfer characteristic curve:
+     *  E = L
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * Transfer characteristic curve:
+     *
+     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
+     *   = 12.92 * L                  for 0 <= L < 0.0031308
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * BT.601 525, BT.601 625, BT.709, BT.2020
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
+     *    = 4.500 * L                 for 0 <= L < 0.018
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * Assumed display gamma 2.2.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.2)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     *  display gamma 2.8.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.8)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * SMPTE ST 2084
+     *
+     * Transfer characteristic curve:
+     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+     *  c2 = 32 * 2413 / 4096 = 18.8515625
+     *  c3 = 32 * 2392 / 4096 = 18.6875
+     *  m = 128 * 2523 / 4096 = 78.84375
+     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
+     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+     *          L = 1 corresponds to 10000 cd/m2
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    /*
+     * ARIB STD-B67 Hybrid Log Gamma
+     *
+     * Transfer characteristic curve:
+     *  E = r * L^0.5                 for 0 <= L <= 1
+     *    = a * ln(L - b) + c         for 1 < L
+     *  a = 0.17883277
+     *  b = 0.28466892
+     *  c = 0.55991073
+     *  r = 0.5
+     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+     *          to reference white level of 100 cd/m2
+     *      E - corresponding electrical signal
+     */
+    HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
+
+    HAL_DATASPACE_RANGE_SHIFT = 27,
+
+    /*
+     * Range aspect
+     *
+     * Defines the range of values corresponding to the unit range of 0-1.
+     * This is defined for YCbCr only, but can be expanded to RGB space.
+     */
+    HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT,  // 0x7
+
+    /*
+     * Range is unknown or are determined by the application.  Implementations
+     * shall use the following suggested ranges:
+     *
+     * All YCbCr formats: limited range.
+     * All RGB or RGBA formats (including RAW and Bayer): full range.
+     * All Y formats: full range
+     *
+     * For all other formats range is undefined, and implementations should use
+     * an appropriate range for the data represented.
+     */
+    HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
+
+    /*
+     * Full range uses all values for Y, Cb and Cr from
+     * 0 to 2^b-1, where b is the bit depth of the color format.
+     */
+    HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
+
+    /*
+     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+     * the color format.
+     *
+     * E.g. For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     */
+    HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
+
+    /*
+     * Legacy dataspaces
      */
 
     /*
@@ -600,34 +927,30 @@
      * The values are encoded using the full range ([0,255] for 8-bit) for all
      * components.
      */
-    HAL_DATASPACE_SRGB_LINEAR = 0x200,
+    HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
+
+    HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
+            HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
+
 
     /*
      * sRGB gamma encoding:
      *
      * The red, green and blue components are stored in sRGB space, and
-     * converted to linear space when read, using the standard sRGB to linear
-     * equation:
-     *
-     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
-     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
-     *
-     * When written the inverse transformation is performed:
-     *
-     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
-     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
-     *
+     * converted to linear space when read, using the SRGB transfer function
+     * for each of the R, G and B components. When written, the inverse
+     * transformation is performed.
      *
      * The alpha component, if present, is always stored in linear space and
      * is left unmodified when read or written.
      *
-     * The RGB primaries and the white point are the same as BT.709.
-     *
-     * The values are encoded using the full range ([0,255] for 8-bit) for all
-     * components.
-     *
+     * Use full range and BT.709 standard.
      */
-    HAL_DATASPACE_SRGB = 0x201,
+    HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
+
+    HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
+            HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
+
 
     /*
      * YCbCr Colorspaces
@@ -645,94 +968,53 @@
      *
      * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
      *
-     * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
-     *  E = 4.500 L, 0.018 > L >= 0
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     *
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     * Use full range, BT.601 transfer and BT.601_625 standard.
      */
-    HAL_DATASPACE_JFIF = 0x101,
+    HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
+
+    HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
+            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 625-line
      *
      * Standard-definition television, 625 Lines (PAL)
      *
-     * For 8-bit-depth formats:
-     * Luma (Y) samples should range from 16 to 235, inclusive
-     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
-     *
-     * For 10-bit-depth formats:
-     * Luma (Y) samples should range from 64 to 940, inclusive
-     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
-     *
-     * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
-     *  E = 4.500 L, 0.018 > L >= 0
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     *
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     * Use limited range, BT.601 transfer and BT.601_625 standard.
      */
-    HAL_DATASPACE_BT601_625 = 0x102,
+    HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
+
+    HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
+            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
+
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 525-line
      *
      * Standard-definition television, 525 Lines (NTSC)
      *
-     * For 8-bit-depth formats:
-     * Luma (Y) samples should range from 16 to 235, inclusive
-     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
-     *
-     * For 10-bit-depth formats:
-     * Luma (Y) samples should range from 64 to 940, inclusive
-     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
-     *
-     * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
-     *  E = 4.500 L, 0.018 > L >= 0
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     *
-     * Primaries:       x       y
-     *  green           0.310   0.595
-     *  blue            0.155   0.070
-     *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
+     * Use limited range, BT.601 transfer and BT.601_525 standard.
      */
-    HAL_DATASPACE_BT601_525 = 0x103,
+    HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
+
+    HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
+            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
 
     /*
      * ITU-R Recommendation 709 (BT.709)
      *
      * High-definition television
      *
-     * For 8-bit-depth formats:
-     * Luma (Y) samples should range from 16 to 235, inclusive
-     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
-     *
-     * For 10-bit-depth formats:
-     * Luma (Y) samples should range from 64 to 940, inclusive
-     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
-     *
-     * Primaries:       x       y
-     *  green           0.300   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     * Use limited range, BT.709 transfer and BT.709 standard.
      */
-    HAL_DATASPACE_BT709 = 0x104,
+    HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
+
+    HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
+            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
+
+    /*
+     * Data spaces for non-color formats
+     */
 
     /*
      * The buffer contains depth ranging measurements from a depth camera.
diff --git a/include/system/radio.h b/include/system/radio.h
index a088526..9e291c8 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -94,6 +94,7 @@
     radio_rds_t         rds;        /* RDS variants supported */
     bool                ta;         /* Traffic Announcement supported */
     bool                af;         /* Alternate Frequency supported */
+    bool                ea;         /* Emergency announcements supported */
 } radio_hal_fm_band_config_t;
 
 /* Additional attributes for an AM band configuration */
@@ -184,6 +185,7 @@
     RADIO_EVENT_METADATA    = 4,  /* New meta data received */
     RADIO_EVENT_TA          = 5,  /* Traffic announcement start or stop */
     RADIO_EVENT_AF_SWITCH   = 6,  /* Switch to Alternate Frequency */
+    RADIO_EVENT_EA          = 7,  /* Emergency announcement start or stop */
     // begin framework only events
     RADIO_EVENT_CONTROL     = 100, /* loss/gain of tuner control */
     RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
@@ -195,7 +197,8 @@
     radio_event_type_t  type;       /* event type */
     int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
     union {
-        bool                    on;     /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+        /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
+        bool                    on;
         radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
         radio_program_info_t    info;   /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
         radio_metadata_t        *metadata; /* RADIO_EVENT_METADATA */
diff --git a/include/system/window.h b/include/system/window.h
index 508ce00..1ca093f 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -25,6 +25,7 @@
 #include <sys/cdefs.h>
 #include <system/graphics.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #ifndef __UNUSED
 #define __UNUSED __attribute__((__unused__))
@@ -311,6 +312,8 @@
     NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
     NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19,
     NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
+    NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE    = 21,
+    NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -351,7 +354,8 @@
     NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
 };
 
-/* parameter for NATIVE_WINDOW_SET_SCALING_MODE */
+/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
+ * keep in sync with Surface.java in frameworks/base */
 enum {
     /* the window content is not updated (frozen) until a buffer of
      * the window size is received (enqueued)
@@ -949,6 +953,29 @@
             rects, numRects);
 }
 
+/*
+ * native_window_set_single_buffer_mode(..., bool singleBufferMode)
+ * Enable/disable single buffer mode
+ */
+static inline int native_window_set_single_buffer_mode(
+        struct ANativeWindow* window,
+        bool singleBufferMode)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE,
+            singleBufferMode);
+}
+
+/*
+ * native_window_set_auto_refresh(..., autoRefresh)
+ * Enable/disable auto refresh when in single buffer mode
+ */
+static inline int native_window_set_auto_refresh(
+        struct ANativeWindow* window,
+        bool autoRefresh)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
+}
+
 __END_DECLS
 
 #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 4350ec1..88b5b44 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -219,6 +219,9 @@
                             int length,
                             unsigned int timeout);
 
+/** Reset USB bus for the device */
+int usb_device_reset(struct usb_device *device);
+
 /* Creates a new usb_request. */
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc);
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 1532b7e..3792db7 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -45,7 +45,7 @@
     virtual             ~Thread();
 
     // Start the thread in threadLoop() which needs to be implemented.
-    virtual status_t    run(    const char* name = 0,
+    virtual status_t    run(    const char* name,
                                 int32_t priority = PRIORITY_DEFAULT,
                                 size_t stack = 0);
     
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 3591a6b..7dc60ae 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -152,6 +152,9 @@
  * if this file entry contains a data descriptor footer. To verify crc32s
  * and length, a call to VerifyCrcAndLengths must be made after entry data
  * has been processed.
+ *
+ * On non-Windows platforms this method does not modify internal state and
+ * can be called concurrently.
  */
 int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
                   ZipEntry* data);
diff --git a/init/Android.mk b/init/Android.mk
index 66ce8a8..d8b574f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -89,8 +89,8 @@
     libsquashfs_utils \
     liblogwrap \
     libcutils \
-    libbase \
     libext4_utils_static \
+    libbase \
     libutils \
     libc \
     libselinux \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 35f1a9e..2e72832 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -501,16 +501,16 @@
         property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
-        /* If fs_mgr determined this is an unencrypted device, then trigger
-         * that action.
-         */
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
+        property_set("ro.crypto.state", "unsupported");
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
     } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
         ret = wipe_data_via_recovery();
         /* If reboot worked, there is no return. */
-    } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
+    } else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
             return -1;
         }
@@ -520,13 +520,6 @@
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
-    } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
-        if (e4crypt_install_keyring()) {
-            return -1;
-        }
-        property_set("ro.crypto.state", "encrypted");
-        property_set("ro.crypto.type", "file");
-        property_set("vold.decrypt", "trigger_restart_min_framework");
     } else if (ret > 0) {
         ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
     }
@@ -884,11 +877,8 @@
                                      do_installkeys_ensure_dir_exists);
 }
 
-static int do_setusercryptopolicies(const std::vector<std::string>& args) {
-    if (!is_file_crypto()) {
-        return 0;
-    }
-    return e4crypt_set_user_crypto_policies(args[1].c_str());
+static int do_init_user0(const std::vector<std::string>& args) {
+    return e4crypt_do_init_user0();
 }
 
 BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
@@ -907,6 +897,7 @@
         {"export",                  {2,     2,    do_export}},
         {"hostname",                {1,     1,    do_hostname}},
         {"ifup",                    {1,     1,    do_ifup}},
+        {"init_user0",              {0,     0,    do_init_user0}},
         {"insmod",                  {1,     kMax, do_insmod}},
         {"installkey",              {1,     1,    do_installkey}},
         {"load_persist_props",      {0,     0,    do_load_persist_props}},
@@ -923,7 +914,6 @@
         {"rmdir",                   {1,     1,    do_rmdir}},
         {"setprop",                 {2,     2,    do_setprop}},
         {"setrlimit",               {3,     3,    do_setrlimit}},
-        {"setusercryptopolicies",   {1,     1,    do_setusercryptopolicies}},
         {"start",                   {1,     1,    do_start}},
         {"stop",                    {1,     1,    do_stop}},
         {"swapon_all",              {1,     1,    do_swapon_all}},
diff --git a/init/init.cpp b/init/init.cpp
index b1e3a9d..69f0595 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -353,7 +353,7 @@
             && set_mmap_rnd_bits_min(16, 16, true)) {
         ret = 0;
     }
-#elif defined(__x86__64__)
+#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)) {
@@ -372,6 +372,11 @@
 #else
     ERROR("Unknown architecture\n");
 #endif
+
+#ifdef __BRILLO__
+    // TODO: b/27794137
+    ret = 0;
+#endif
     if (ret == -1) {
         ERROR("Unable to set adequate mmap entropy value!\n");
         security_failure();
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 45c7add..5e2ef0b 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -37,7 +37,8 @@
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
 
-int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+static int fs_prepare_dir_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
+        int allow_fixup) {
     // Check if path needs to be created
     struct stat sb;
     if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
@@ -54,10 +55,22 @@
         ALOGE("Not a directory: %s", path);
         return -1;
     }
-    if (((sb.st_mode & ALL_PERMS) == mode) && (sb.st_uid == uid) && (sb.st_gid == gid)) {
+    int owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
+    int mode_match = ((sb.st_mode & ALL_PERMS) == mode);
+    if (owner_match && mode_match) {
         return 0;
-    } else {
+    } else if (allow_fixup) {
         goto fixup;
+    } else {
+        if (!owner_match) {
+            ALOGE("Expected path %s with owner %d:%d but found %d:%d",
+                    path, uid, gid, sb.st_uid, sb.st_gid);
+            return -1;
+        } else {
+            ALOGW("Expected path %s with mode %o but found %o",
+                    path, mode, (sb.st_mode & ALL_PERMS));
+            return 0;
+        }
     }
 
 create:
@@ -81,6 +94,14 @@
     return 0;
 }
 
+int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    return fs_prepare_dir_impl(path, mode, uid, gid, 1);
+}
+
+int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    return fs_prepare_dir_impl(path, mode, uid, gid, 0);
+}
+
 int fs_read_atomic_int(const char* path, int* out_value) {
     int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
     if (fd == -1) {
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 6d50adc..0abfcbf 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -79,6 +79,7 @@
     { 00500, AID_ROOT,   AID_ROOT,   0, "config" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
     { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
     { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
@@ -117,7 +118,6 @@
     { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
     { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
     { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
-    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
     { 00440, AID_ROOT,      AID_ROOT,      0, "system/etc/recovery.img" },
@@ -126,6 +126,7 @@
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-ephemeral/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 7c74bb8..0f4427b 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -27,3 +27,9 @@
 uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
     return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
 }
+
+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;
+
+}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 6bba3a7..1a26695 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -62,8 +62,10 @@
 
 #ifdef USE_CPUSETS
 // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+static int system_bg_cpuset_fd = -1;
 static int bg_cpuset_fd = -1;
 static int fg_cpuset_fd = -1;
+static int ta_cpuset_fd = -1; // special cpuset for top app
 static int bg_schedboost_fd = -1;
 static int fg_schedboost_fd = -1;
 #endif
@@ -130,15 +132,19 @@
         fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/cpuset/background/tasks";
         bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+        filename = "/dev/cpuset/system-background/tasks";
+        system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+        filename = "/dev/cpuset/top-app/tasks";
+        ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+
 #ifdef USE_SCHEDBOOST
-        filename = "/sys/fs/cgroup/stune/foreground/tasks";
+        filename = "/dev/stune/foreground/tasks";
         fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        filename = "/sys/fs/cgroup/stune/tasks";
+        filename = "/dev/stune/tasks";
         bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
 #endif
     }
 #endif
-
 }
 
 /*
@@ -260,8 +266,8 @@
     policy = _policy(policy);
     pthread_once(&the_once, __initialize);
 
-    int fd;
-    int boost_fd;
+    int fd = -1;
+    int boost_fd = -1;
     switch (policy) {
     case SP_BACKGROUND:
         fd = bg_cpuset_fd;
@@ -273,6 +279,14 @@
         fd = fg_cpuset_fd;
         boost_fd = fg_schedboost_fd;
         break;
+    case SP_TOP_APP :
+        fd = ta_cpuset_fd;
+        boost_fd = fg_schedboost_fd;
+        break;
+    case SP_SYSTEM:
+        fd = system_bg_cpuset_fd;
+        boost_fd = bg_schedboost_fd;
+        break;
     default:
         boost_fd = fd = -1;
         break;
@@ -330,6 +344,7 @@
     case SP_FOREGROUND:
     case SP_AUDIO_APP:
     case SP_AUDIO_SYS:
+    case SP_TOP_APP:
         SLOGD("^^^ tid %d (%s)", tid, thread_name);
         break;
     case SP_SYSTEM:
@@ -350,6 +365,7 @@
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
+        case SP_TOP_APP:
             fd = fg_cgroup_fd;
             break;
         default:
@@ -404,6 +420,7 @@
        [SP_SYSTEM]     = "  ",
        [SP_AUDIO_APP]  = "aa",
        [SP_AUDIO_SYS]  = "as",
+       [SP_TOP_APP]    = "ta",
     };
     if ((policy < SP_CNT) && (strings[policy] != NULL))
         return strings[policy];
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 607d667..59c696b 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -15,20 +15,29 @@
 //
 
 liblog_sources = [
-    "logd_write.c",
     "log_event_list.c",
     "log_event_write.c",
+    "logger_write.c",
+    "config_write.c",
+    "logger_name.c",
+    "logger_lock.c",
 ]
 liblog_host_sources = [
     "fake_log_device.c",
     //"event.logtags",
+    "fake_writer.c",
 ]
 liblog_target_sources = [
     "event_tag_map.c",
+    "config_read.c",
     "log_time.cpp",
     "log_is_loggable.c",
     "logprint.c",
-    "log_read.c",
+    "pmsg_reader.c",
+    "pmsg_writer.c",
+    "logd_reader.c",
+    "logd_writer.c",
+    "logger_read.c",
 ]
 
 // Shared and static library for host and device
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 6d53a4a..01c8e77 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,10 +24,14 @@
 # so make sure we do not regret hard-coding it as follows:
 liblog_cflags := -DLIBLOG_LOG_TAG=1005
 
-liblog_sources := logd_write.c log_event_list.c log_event_write.c
+liblog_sources := log_event_list.c log_event_write.c logger_write.c
+liblog_sources += config_write.c logger_name.c logger_lock.c
 liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
+liblog_host_sources += fake_writer.c
 liblog_target_sources := $(liblog_sources) event_tag_map.c
-liblog_target_sources += log_time.cpp log_is_loggable.c logprint.c log_read.c
+liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
+liblog_target_sources += pmsg_reader.c pmsg_writer.c
+liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
 
 # Shared and static library for host
 # ========================================================
diff --git a/liblog/config_read.c b/liblog/config_read.c
new file mode 100644
index 0000000..1f54152
--- /dev/null
+++ b/liblog/config_read.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "config_read.h"
+#include "logger.h"
+
+LIBLOG_HIDDEN struct listnode __android_log_transport_read =
+    { &__android_log_transport_read, &__android_log_transport_read };
+LIBLOG_HIDDEN struct listnode __android_log_persist_read =
+    { &__android_log_persist_read, &__android_log_persist_read };
+
+static void __android_log_add_transport(
+        struct listnode *list, struct android_log_transport_read *transport) {
+    size_t i;
+
+    /* Try to keep one functioning transport for each log buffer id */
+    for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+        struct android_log_transport_read *transp;
+
+        if (list_empty(list)) {
+            if (!transport->available || ((*transport->available)(i) >= 0)) {
+                list_add_tail(list, &transport->node);
+                return;
+            }
+        } else {
+            read_transport_for_each(transp, list) {
+                if (!transp->available) {
+                    return;
+                }
+                if (((*transp->available)(i) < 0) &&
+                        (!transport->available ||
+                            ((*transport->available)(i) >= 0))) {
+                    list_add_tail(list, &transport->node);
+                    return;
+                }
+            }
+        }
+    }
+}
+
+LIBLOG_HIDDEN void __android_log_config_read() {
+#if (FAKE_LOG_DEVICE == 0)
+    extern struct android_log_transport_read logdLoggerRead;
+    extern struct android_log_transport_read pmsgLoggerRead;
+
+    __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
+    __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
+#endif
+}
diff --git a/liblog/config_read.h b/liblog/config_read.h
new file mode 100644
index 0000000..67f4c20
--- /dev/null
+++ b/liblog/config_read.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_CONFIG_READ_H__
+#define _LIBLOG_CONFIG_READ_H__
+
+#include <cutils/list.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+extern LIBLOG_HIDDEN struct listnode __android_log_transport_read;
+extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
+
+#define read_transport_for_each(transp, transports)                         \
+    for (transp = node_to_item((transports)->next,                          \
+                               struct android_log_transport_read, node);    \
+         (transp != node_to_item(transports,                                \
+                                 struct android_log_transport_read, node)); \
+         transp = node_to_item(transp->node.next,                           \
+                               struct android_log_transport_read, node))    \
+
+#define read_transport_for_each_safe(transp, n, transports)                 \
+    for (transp = node_to_item((transports)->next,                          \
+                               struct android_log_transport_read, node),    \
+         n = transp->node.next;                                             \
+         (transp != node_to_item(transports,                                \
+                                 struct android_log_transport_read, node)); \
+         transp = node_to_item(n, struct android_log_transport_read, node), \
+         n = transp->node.next)
+
+LIBLOG_HIDDEN void __android_log_config_read();
+
+__END_DECLS
+
+#endif /* _LIBLOG_CONFIG_READ_H__ */
diff --git a/liblog/config_write.c b/liblog/config_write.c
new file mode 100644
index 0000000..d689f63
--- /dev/null
+++ b/liblog/config_write.c
@@ -0,0 +1,66 @@
+/*
+ * 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 "config_write.h"
+#include "logger.h"
+
+LIBLOG_HIDDEN struct listnode __android_log_transport_write =
+    { &__android_log_transport_write, &__android_log_transport_write };
+LIBLOG_HIDDEN struct listnode __android_log_persist_write =
+    { &__android_log_persist_write, &__android_log_persist_write};
+
+static void __android_log_add_transport(
+        struct listnode *list, struct android_log_transport_write *transport) {
+    size_t i;
+
+    /* Try to keep one functioning transport for each log buffer id */
+    for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+        struct android_log_transport_write *transp;
+
+        if (list_empty(list)) {
+            if (!transport->available || ((*transport->available)(i) >= 0)) {
+                list_add_tail(list, &transport->node);
+                return;
+            }
+        } else {
+            write_transport_for_each(transp, list) {
+                if (!transp->available) {
+                    return;
+                }
+                if (((*transp->available)(i) < 0) &&
+                        (!transport->available ||
+                            ((*transport->available)(i) >= 0))) {
+                    list_add_tail(list, &transport->node);
+                    return;
+                }
+            }
+        }
+    }
+}
+
+LIBLOG_HIDDEN void __android_log_config_write() {
+#if (FAKE_LOG_DEVICE == 0)
+    extern struct android_log_transport_write logdLoggerWrite;
+    extern struct android_log_transport_write pmsgLoggerWrite;
+
+    __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
+    __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
+#else
+    extern struct android_log_transport_write fakeLoggerWrite;
+
+    __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
+#endif
+}
diff --git a/liblog/config_write.h b/liblog/config_write.h
new file mode 100644
index 0000000..3a02a4e
--- /dev/null
+++ b/liblog/config_write.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_CONFIG_WRITE_H__
+#define _LIBLOG_CONFIG_WRITE_H__
+
+#include <cutils/list.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+extern LIBLOG_HIDDEN struct listnode __android_log_transport_write;
+extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
+
+#define write_transport_for_each(transp, transports)                         \
+    for (transp = node_to_item((transports)->next,                           \
+                               struct android_log_transport_write, node);    \
+         (transp != node_to_item(transports,                                 \
+                                 struct android_log_transport_write, node)); \
+         transp = node_to_item(transp->node.next,                            \
+                               struct android_log_transport_write, node))    \
+
+#define write_transport_for_each_safe(transp, n, transports)                 \
+    for (transp = node_to_item((transports)->next,                           \
+                               struct android_log_transport_write, node),    \
+         n = transp->node.next;                                              \
+         (transp != node_to_item(transports,                                 \
+                                 struct android_log_transport_write, node)); \
+         transp = node_to_item(n, struct android_log_transport_write, node), \
+         n = transp->node.next)
+
+LIBLOG_HIDDEN void __android_log_config_write();
+
+__END_DECLS
+
+#endif /* _LIBLOG_CONFIG_WRITE_H__ */
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 870c69a..64d872a 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -24,7 +24,7 @@
 #include <log/event_tag_map.h>
 #include <log/log.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 #define OUT_TAG "EventTagMap"
 
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index c73e03e..cc67f3e 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -31,7 +31,7 @@
 #include <log/logd.h>
 
 #include "fake_log_device.h"
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 #define kMaxTagLen  16      /* from the long-dead utils/Log.cpp */
 
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 672b446..4529b5d 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -19,7 +19,7 @@
 
 #include <sys/types.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 struct iovec;
 
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
new file mode 100644
index 0000000..dab8bc5
--- /dev/null
+++ b/liblog/fake_writer.c
@@ -0,0 +1,82 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <log/log.h>
+
+#include "config_write.h"
+#include "fake_log_device.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static int fakeOpen();
+static void fakeClose();
+static int fakeWrite(log_id_t log_id, struct timespec *ts,
+                     struct iovec *vec, size_t nr);
+
+static int logFds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
+
+LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = {
+    .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node },
+    .context.private = &logFds,
+    .name = "fake",
+    .available = NULL,
+    .open = fakeOpen,
+    .close = fakeClose,
+    .write = fakeWrite,
+};
+
+static int fakeOpen() {
+    int i;
+
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        char buf[sizeof("/dev/log_security")];
+        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+        logFds[i] = fakeLogOpen(buf, O_WRONLY);
+    }
+    return 0;
+}
+
+static void fakeClose() {
+    int i;
+
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        fakeLogClose(logFds[i]);
+        logFds[i] = -1;
+    }
+}
+
+static int fakeWrite(log_id_t log_id, struct timespec *ts __unused,
+                      struct iovec *vec, size_t nr)
+{
+    ssize_t ret;
+    int logFd;
+
+    if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
+        return -EBADF;
+    }
+
+    logFd = logFds[(int)log_id];
+    ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
+    if (ret < 0) {
+        ret = -errno;
+    }
+
+    return ret;
+}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a77c56e..64d9024 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -25,7 +25,7 @@
 #include <log/log.h>
 #include <log/logger.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
 
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 3535b94..b9827a1 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,7 +18,7 @@
 
 #include <log/log.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 #define MAX_SUBTAG_LEN 32
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 47fde20..551fa76 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,7 +23,7 @@
 
 #include <android/log.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
 
diff --git a/liblog/log_cdefs.h b/liblog/log_portability.h
similarity index 65%
rename from liblog/log_cdefs.h
rename to liblog/log_portability.h
index 3a52625..3ad2060 100644
--- a/liblog/log_cdefs.h
+++ b/liblog/log_portability.h
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef _LIBLOG_CDEFS_H__
-#define _LIBLOG_CDEFS_H__
+#ifndef _LIBLOG_PORTABILITY_H__
+#define _LIBLOG_PORTABILITY_H__
 
 #include <sys/cdefs.h>
+#include <unistd.h>
+
+/* Helpful private sys/cdefs.h like definitions */
 
 /* Declare this library function hidden and internal */
 #if defined(_WIN32)
@@ -46,9 +49,34 @@
 #define LIBLOG_WEAK __attribute__((weak,visibility("default")))
 #endif
 
+/* possible missing definitions in sys/cdefs.h */
+
+/* DECLS */
+#ifndef __BEGIN_DECLS
+#if defined(__cplusplus)
+#define __BEGIN_DECLS           extern "C" {
+#define __END_DECLS             }
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+#endif
+
 /* Unused argument. For C code only, remove symbol name for C++ */
 #ifndef __unused
 #define __unused        __attribute__((__unused__))
 #endif
 
-#endif /* _LIBLOG_CDEFS_H__ */
+/* possible missing definitions in unistd.h */
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    __typeof__(exp) _rc;                   \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#endif /* _LIBLOG_PORTABILITY_H__ */
diff --git a/liblog/log_read.c b/liblog/log_read.c
deleted file mode 100644
index 4b83944..0000000
--- a/liblog/log_read.c
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
-** Copyright 2013-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 <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stddef.h>
-#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <cutils/list.h>
-#include <cutils/sockets.h>
-#include <log/log.h>
-#include <log/logger.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "log_cdefs.h"
-
-/* branchless on many architectures. */
-#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
-
-/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
-
-#if defined(_WIN32)
-
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
-    errno = ENOSYS;
-    return -ENOSYS;
-}
-
-#else /* !_WIN32 */
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <sys/types.h>
-
-/* Private copy of ../libcutils/socket_local.h prevent library loops */
-#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
-#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
-/* End of ../libcutils/socket_local.h */
-
-#define LISTEN_BACKLOG 4
-
-/* Documented in header file. */
-LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
-                                        struct sockaddr_un *p_addr,
-                                        socklen_t *alen)
-{
-    memset (p_addr, 0, sizeof (*p_addr));
-    size_t namelen;
-
-    switch (namespaceId) {
-    case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#if defined(__linux__)
-        namelen  = strlen(name);
-
-        /* Test with length +1 for the *initial* '\0'. */
-        if ((namelen + 1) > sizeof(p_addr->sun_path)) {
-            goto error;
-        }
-
-        /*
-         * Note: The path in this case is *not* supposed to be
-         * '\0'-terminated. ("man 7 unix" for the gory details.)
-         */
-
-        p_addr->sun_path[0] = 0;
-        memcpy(p_addr->sun_path + 1, name, namelen);
-#else
-        /* this OS doesn't have the Linux abstract namespace */
-
-        namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
-        /* unix_path_max appears to be missing on linux */
-        if (namelen > sizeof(*p_addr)
-                - offsetof(struct sockaddr_un, sun_path) - 1) {
-            goto error;
-        }
-
-        strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
-        strcat(p_addr->sun_path, name);
-#endif
-        break;
-
-    case ANDROID_SOCKET_NAMESPACE_RESERVED:
-        namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
-        /* unix_path_max appears to be missing on linux */
-        if (namelen > sizeof(*p_addr)
-                - offsetof(struct sockaddr_un, sun_path) - 1) {
-            goto error;
-        }
-
-        strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
-        strcat(p_addr->sun_path, name);
-        break;
-
-    case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
-        namelen = strlen(name);
-        /* unix_path_max appears to be missing on linux */
-        if (namelen > sizeof(*p_addr)
-                - offsetof(struct sockaddr_un, sun_path) - 1) {
-            goto error;
-        }
-
-        strcpy(p_addr->sun_path, name);
-        break;
-
-    default:
-        /* invalid namespace id */
-        return -1;
-    }
-
-    p_addr->sun_family = AF_LOCAL;
-    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
-    return 0;
-error:
-    return -1;
-}
-
-/**
- * connect to peer named "name" on fd
- * returns same fd or -1 on error.
- * fd is not closed on error. that's your job.
- *
- * Used by AndroidSocketImpl
- */
-LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
-                                            int namespaceId, int type __unused)
-{
-    struct sockaddr_un addr;
-    socklen_t alen;
-    int err;
-
-    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
-
-    if (err < 0) {
-        goto error;
-    }
-
-    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
-        goto error;
-    }
-
-    return fd;
-
-error:
-    return -1;
-}
-
-/**
- * connect to peer named "name"
- * returns fd or -1 on error
- */
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
-    int s;
-
-    s = socket(AF_LOCAL, type, 0);
-    if(s < 0) return -1;
-
-    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
-        close(s);
-        return -1;
-    }
-
-    return s;
-}
-
-#endif /* !_WIN32 */
-/* End of ../libcutils/socket_local_client.c */
-
-#define logger_for_each(logger, logger_list) \
-    for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
-         logger != node_to_item(&(logger_list)->node, struct logger, node); \
-         logger = node_to_item((logger)->node.next, struct logger, node))
-
-/* In the future, we would like to make this list extensible */
-static const char *LOG_NAME[LOG_ID_MAX] = {
-    [LOG_ID_MAIN] = "main",
-    [LOG_ID_RADIO] = "radio",
-    [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash",
-    [LOG_ID_SECURITY] = "security",
-    [LOG_ID_KERNEL] = "kernel",
-};
-
-LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
-{
-    if (log_id >= LOG_ID_MAX) {
-        log_id = LOG_ID_MAIN;
-    }
-    return LOG_NAME[log_id];
-}
-
-LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
-{
-    const char *b;
-    int ret;
-
-    if (!logName) {
-        return -1; /* NB: log_id_t is unsigned */
-    }
-    b = strrchr(logName, '/');
-    if (!b) {
-        b = logName;
-    } else {
-        ++b;
-    }
-
-    for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
-        const char *l = LOG_NAME[ret];
-        if (l && !strcmp(b, l)) {
-            return ret;
-        }
-    }
-    return -1;   /* should never happen */
-}
-
-struct logger_list {
-    struct listnode node;
-    int mode;
-    unsigned int tail;
-    log_time start;
-    pid_t pid;
-    int sock;
-};
-
-struct logger {
-    struct listnode node;
-    struct logger_list *top;
-    log_id_t id;
-};
-
-/* android_logger_alloc unimplemented, no use case */
-/* android_logger_free not exported */
-static void android_logger_free(struct logger *logger)
-{
-    if (!logger) {
-        return;
-    }
-
-    list_remove(&logger->node);
-
-    free(logger);
-}
-
-/* android_logger_alloc unimplemented, no use case */
-
-/* method for getting the associated sublog id */
-LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
-{
-    return logger->id;
-}
-
-/* worker for sending the command to the logger */
-static ssize_t send_log_msg(struct logger *logger,
-                            const char *msg, char *buf, size_t buf_size)
-{
-    ssize_t ret;
-    size_t len;
-    char *cp;
-    int errno_save = 0;
-    int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                   SOCK_STREAM);
-    if (sock < 0) {
-        return sock;
-    }
-
-    if (msg) {
-        snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
-    }
-
-    len = strlen(buf) + 1;
-    ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
-    if (ret <= 0) {
-        goto done;
-    }
-
-    len = buf_size;
-    cp = buf;
-    while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
-        struct pollfd p;
-
-        if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
-            break;
-        }
-
-        len -= ret;
-        cp += ret;
-
-        memset(&p, 0, sizeof(p));
-        p.fd = sock;
-        p.events = POLLIN;
-
-        /* Give other side 20ms to refill pipe */
-        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
-
-        if (ret <= 0) {
-            break;
-        }
-
-        if (!(p.revents & POLLIN)) {
-            ret = 0;
-            break;
-        }
-    }
-
-    if (ret >= 0) {
-        ret += buf_size - len;
-    }
-
-done:
-    if ((ret == -1) && errno) {
-        errno_save = errno;
-    }
-    close(sock);
-    if (errno_save) {
-        errno = errno_save;
-    }
-    return ret;
-}
-
-static int check_log_success(char *buf, ssize_t ret)
-{
-    if (ret < 0) {
-        return ret;
-    }
-
-    if (strncmp(buf, "success", 7)) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    return 0;
-}
-
-/* Determine the credentials of the caller */
-static bool uid_has_log_permission(uid_t uid)
-{
-    return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
-}
-
-static uid_t get_best_effective_uid()
-{
-    uid_t euid;
-    uid_t uid;
-    gid_t gid;
-    ssize_t i;
-    static uid_t last_uid = (uid_t) -1;
-
-    if (last_uid != (uid_t) -1) {
-        return last_uid;
-    }
-    uid = getuid();
-    if (uid_has_log_permission(uid)) {
-        return last_uid = uid;
-    }
-    euid = geteuid();
-    if (uid_has_log_permission(euid)) {
-        return last_uid = euid;
-    }
-    gid = getgid();
-    if (uid_has_log_permission(gid)) {
-        return last_uid = gid;
-    }
-    gid = getegid();
-    if (uid_has_log_permission(gid)) {
-        return last_uid = gid;
-    }
-    i = getgroups((size_t) 0, NULL);
-    if (i > 0) {
-        gid_t list[i];
-
-        getgroups(i, list);
-        while (--i >= 0) {
-            if (uid_has_log_permission(list[i])) {
-                return last_uid = list[i];
-            }
-        }
-    }
-    return last_uid = uid;
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
-{
-    char buf[512];
-
-    if (logger->top->mode & ANDROID_LOG_PSTORE) {
-        if (uid_has_log_permission(get_best_effective_uid())) {
-            return unlink("/sys/fs/pstore/pmsg-ramoops-0");
-        }
-        errno = EPERM;
-        return -1;
-    }
-    return check_log_success(buf,
-        send_log_msg(logger, "clear %d", buf, sizeof(buf)));
-}
-
-/* returns the total size of the log's ring buffer */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
-{
-    char buf[512];
-
-    ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
-    if (ret < 0) {
-        return ret;
-    }
-
-    if ((buf[0] < '0') || ('9' < buf[0])) {
-        return -1;
-    }
-
-    return atol(buf);
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
-                                                  unsigned long size)
-{
-    char buf[512];
-
-    snprintf(buf, sizeof(buf), "setLogSize %d %lu",
-        logger ? logger->id : (unsigned) -1, size);
-
-    return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
-}
-
-/*
- * returns the readable size of the log's ring buffer (that is, amount of the
- * log consumed)
- */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
-        struct logger *logger)
-{
-    char buf[512];
-
-    ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
-    if (ret < 0) {
-        return ret;
-    }
-
-    if ((buf[0] < '0') || ('9' < buf[0])) {
-        return -1;
-    }
-
-    return atol(buf);
-}
-
-/*
- * returns the logger version
- */
-LIBLOG_ABI_PUBLIC int android_logger_get_log_version(
-        struct logger *logger __unused)
-{
-    return 4;
-}
-
-/*
- * returns statistics
- */
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
-        struct logger_list *logger_list,
-        char *buf, size_t len)
-{
-    struct logger *logger;
-    char *cp = buf;
-    size_t remaining = len;
-    size_t n;
-
-    n = snprintf(cp, remaining, "getStatistics");
-    n = min(n, remaining);
-    remaining -= n;
-    cp += n;
-
-    logger_for_each(logger, logger_list) {
-        n = snprintf(cp, remaining, " %d", logger->id);
-        n = min(n, remaining);
-        remaining -= n;
-        cp += n;
-    }
-
-    if (logger_list->pid) {
-        snprintf(cp, remaining, " pid=%u", logger_list->pid);
-    }
-
-    return send_log_msg(NULL, NULL, buf, len);
-}
-
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
-        struct logger_list *logger_list __unused,
-        char *buf, size_t len)
-{
-    return send_log_msg(NULL, "getPruneList", buf, len);
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
-        struct logger_list *logger_list __unused,
-        char *buf, size_t len)
-{
-    const char cmd[] = "setPruneList ";
-    const size_t cmdlen = sizeof(cmd) - 1;
-
-    if (strlen(buf) > (len - cmdlen)) {
-        return -ENOMEM; /* KISS */
-    }
-    memmove(buf + cmdlen, buf, len - cmdlen);
-    buf[len - 1] = '\0';
-    memcpy(buf, cmd, cmdlen);
-
-    return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
-}
-
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
-        int mode,
-        unsigned int tail,
-        pid_t pid)
-{
-    struct logger_list *logger_list;
-
-    logger_list = calloc(1, sizeof(*logger_list));
-    if (!logger_list) {
-        return NULL;
-    }
-
-    list_init(&logger_list->node);
-    logger_list->mode = mode;
-    logger_list->start.tv_sec = 0;
-    logger_list->start.tv_nsec = 0;
-    logger_list->tail = tail;
-    logger_list->pid = pid;
-    logger_list->sock = -1;
-
-    return logger_list;
-}
-
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
-        int mode,
-        log_time start,
-        pid_t pid)
-{
-    struct logger_list *logger_list;
-
-    logger_list = calloc(1, sizeof(*logger_list));
-    if (!logger_list) {
-        return NULL;
-    }
-
-    list_init(&logger_list->node);
-    logger_list->mode = mode;
-    logger_list->start = start;
-    logger_list->tail = 0;
-    logger_list->pid = pid;
-    logger_list->sock = -1;
-
-    return logger_list;
-}
-
-/* android_logger_list_register unimplemented, no use case */
-/* android_logger_list_unregister unimplemented, no use case */
-
-/* Open the named log and add it to the logger list */
-LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
-        struct logger_list *logger_list,
-        log_id_t id)
-{
-    struct logger *logger;
-
-    if (!logger_list || (id >= LOG_ID_MAX)) {
-        goto err;
-    }
-
-    logger_for_each(logger, logger_list) {
-        if (logger->id == id) {
-            goto ok;
-        }
-    }
-
-    logger = calloc(1, sizeof(*logger));
-    if (!logger) {
-        goto err;
-    }
-
-    logger->id = id;
-    list_add_tail(&logger_list->node, &logger->node);
-    logger->top = logger_list;
-    goto ok;
-
-err:
-    logger = NULL;
-ok:
-    return logger;
-}
-
-/* Open the single named log and make it part of a new logger list */
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
-        log_id_t id,
-        int mode,
-        unsigned int tail,
-        pid_t pid)
-{
-    struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
-    if (!logger_list) {
-        return NULL;
-    }
-
-    if (!android_logger_open(logger_list, id)) {
-        android_logger_list_free(logger_list);
-        return NULL;
-    }
-
-    return logger_list;
-}
-
-static int android_logger_list_read_pstore(struct logger_list *logger_list,
-                                           struct log_msg *log_msg)
-{
-    ssize_t ret;
-    off_t current, next;
-    uid_t uid;
-    struct logger *logger;
-    struct __attribute__((__packed__)) {
-        android_pmsg_log_header_t p;
-        android_log_header_t l;
-    } buf;
-    static uint8_t preread_count;
-    bool is_system;
-
-    memset(log_msg, 0, sizeof(*log_msg));
-
-    if (logger_list->sock < 0) {
-        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
-
-        if (fd < 0) {
-            return -errno;
-        }
-        logger_list->sock = fd;
-        preread_count = 0;
-    }
-
-    while(1) {
-        if (preread_count < sizeof(buf)) {
-            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
-                                          &buf.p.magic + preread_count,
-                                          sizeof(buf) - preread_count));
-            if (ret < 0) {
-                return -errno;
-            }
-            preread_count += ret;
-        }
-        if (preread_count != sizeof(buf)) {
-            return preread_count ? -EIO : -EAGAIN;
-        }
-        if ((buf.p.magic != LOGGER_MAGIC)
-         || (buf.p.len <= sizeof(buf))
-         || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
-         || (buf.l.id >= LOG_ID_MAX)
-         || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
-            do {
-                memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
-            } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
-            continue;
-        }
-        preread_count = 0;
-
-        logger_for_each(logger, logger_list) {
-            if (buf.l.id != logger->id) {
-                continue;
-            }
-
-            if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
-             && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
-              || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
-               && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
-                break;
-            }
-
-            if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
-                break;
-            }
-
-            uid = get_best_effective_uid();
-            is_system = uid_has_log_permission(uid);
-            if (!is_system && (uid != buf.p.uid)) {
-                break;
-            }
-
-            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
-                                          is_system ?
-                                              log_msg->entry_v4.msg :
-                                              log_msg->entry_v3.msg,
-                                          buf.p.len - sizeof(buf)));
-            if (ret < 0) {
-                return -errno;
-            }
-            if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
-                return -EIO;
-            }
-
-            log_msg->entry_v4.len = buf.p.len - sizeof(buf);
-            log_msg->entry_v4.hdr_size = is_system ?
-                sizeof(log_msg->entry_v4) :
-                sizeof(log_msg->entry_v3);
-            log_msg->entry_v4.pid = buf.p.pid;
-            log_msg->entry_v4.tid = buf.l.tid;
-            log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
-            log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
-            log_msg->entry_v4.lid = buf.l.id;
-            if (is_system) {
-                log_msg->entry_v4.uid = buf.p.uid;
-            }
-
-            return ret;
-        }
-
-        current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
-                                           (off_t)0, SEEK_CUR));
-        if (current < 0) {
-            return -errno;
-        }
-        next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
-                                        (off_t)(buf.p.len - sizeof(buf)),
-                                        SEEK_CUR));
-        if (next < 0) {
-            return -errno;
-        }
-        if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
-            return -EIO;
-        }
-    }
-}
-
-static void caught_signal(int signum __unused)
-{
-}
-
-/* Read from the selected logs */
-LIBLOG_ABI_PUBLIC int android_logger_list_read(
-        struct logger_list *logger_list,
-        struct log_msg *log_msg)
-{
-    int ret, e;
-    struct logger *logger;
-    struct sigaction ignore;
-    struct sigaction old_sigaction;
-    unsigned int old_alarm = 0;
-
-    if (!logger_list) {
-        return -EINVAL;
-    }
-
-    if (logger_list->mode & ANDROID_LOG_PSTORE) {
-        return android_logger_list_read_pstore(logger_list, log_msg);
-    }
-
-    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
-        memset(&ignore, 0, sizeof(ignore));
-        ignore.sa_handler = caught_signal;
-        sigemptyset(&ignore.sa_mask);
-    }
-
-    if (logger_list->sock < 0) {
-        char buffer[256], *cp, c;
-
-        int sock = socket_local_client("logdr",
-                                       ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                       SOCK_SEQPACKET);
-        if (sock < 0) {
-            if ((sock == -1) && errno) {
-                return -errno;
-            }
-            return sock;
-        }
-
-        strcpy(buffer,
-               (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
-        cp = buffer + strlen(buffer);
-
-        strcpy(cp, " lids");
-        cp += 5;
-        c = '=';
-        int remaining = sizeof(buffer) - (cp - buffer);
-        logger_for_each(logger, logger_list) {
-            ret = snprintf(cp, remaining, "%c%u", c, logger->id);
-            ret = min(ret, remaining);
-            remaining -= ret;
-            cp += ret;
-            c = ',';
-        }
-
-        if (logger_list->tail) {
-            ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
-            ret = min(ret, remaining);
-            remaining -= ret;
-            cp += ret;
-        }
-
-        if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
-            if (logger_list->mode & ANDROID_LOG_WRAP) {
-                // ToDo: alternate API to allow timeout to be adjusted.
-                ret = snprintf(cp, remaining, " timeout=%u",
-                               ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
-                ret = min(ret, remaining);
-                remaining -= ret;
-                cp += ret;
-            }
-            ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
-                           logger_list->start.tv_sec,
-                           logger_list->start.tv_nsec);
-            ret = min(ret, remaining);
-            remaining -= ret;
-            cp += ret;
-        }
-
-        if (logger_list->pid) {
-            ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
-            ret = min(ret, remaining);
-            cp += ret;
-        }
-
-        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
-            /* Deal with an unresponsive logd */
-            sigaction(SIGALRM, &ignore, &old_sigaction);
-            old_alarm = alarm(30);
-        }
-        ret = write(sock, buffer, cp - buffer);
-        e = errno;
-        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
-            if (e == EINTR) {
-                e = ETIMEDOUT;
-            }
-            alarm(old_alarm);
-            sigaction(SIGALRM, &old_sigaction, NULL);
-        }
-
-        if (ret <= 0) {
-            close(sock);
-            if ((ret == -1) && e) {
-                return -e;
-            }
-            if (ret == 0) {
-                return -EIO;
-            }
-            return ret;
-        }
-
-        logger_list->sock = sock;
-    }
-
-    while(1) {
-        memset(log_msg, 0, sizeof(*log_msg));
-
-        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
-            /* particularily useful if tombstone is reporting for logd */
-            sigaction(SIGALRM, &ignore, &old_sigaction);
-            old_alarm = alarm(30);
-        }
-        /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
-        ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
-        e = errno;
-        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
-            if ((ret == 0) || (e == EINTR)) {
-                e = EAGAIN;
-                ret = -1;
-            }
-            alarm(old_alarm);
-            sigaction(SIGALRM, &old_sigaction, NULL);
-        }
-
-        if ((ret == -1) && e) {
-            return -e;
-        }
-        return ret;
-    }
-    /* NOTREACH */
-    return ret;
-}
-
-/* Close all the logs */
-LIBLOG_ABI_PUBLIC void android_logger_list_free(
-        struct logger_list *logger_list)
-{
-    if (logger_list == NULL) {
-        return;
-    }
-
-    while (!list_empty(&logger_list->node)) {
-        struct listnode *node = list_head(&logger_list->node);
-        struct logger *logger = node_to_item(node, struct logger, node);
-        android_logger_free(logger);
-    }
-
-    if (logger_list->sock >= 0) {
-        close (logger_list->sock);
-    }
-
-    free(logger_list);
-}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index b6af222..d2bf181 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -21,7 +21,7 @@
 
 #include <log/log_read.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
 LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
new file mode 100644
index 0000000..d844104
--- /dev/null
+++ b/liblog/logd_reader.c
@@ -0,0 +1,670 @@
+/*
+ * 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 <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_read.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+
+static int logdAvailable(log_id_t LogId);
+static int logdVersion(struct android_log_logger *logger,
+                       struct android_log_transport_context *transp);
+static int logdRead(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp,
+                    struct log_msg *log_msg);
+static int logdPoll(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp);
+static void logdClose(struct android_log_logger_list *logger_list,
+                      struct android_log_transport_context *transp);
+static int logdClear(struct android_log_logger *logger,
+                     struct android_log_transport_context *transp);
+static ssize_t logdSetSize(struct android_log_logger *logger,
+                           struct android_log_transport_context *transp,
+                           size_t size);
+static ssize_t logdGetSize(struct android_log_logger *logger,
+                           struct android_log_transport_context *transp);
+static ssize_t logdGetReadableSize(struct android_log_logger *logger,
+                                   struct android_log_transport_context *transp);
+static ssize_t logdGetPrune(struct android_log_logger_list *logger,
+                            struct android_log_transport_context *transp,
+                            char *buf, size_t len);
+static ssize_t logdSetPrune(struct android_log_logger_list *logger,
+                            struct android_log_transport_context *transp,
+                            char *buf, size_t len);
+static ssize_t logdGetStats(struct android_log_logger_list *logger,
+                            struct android_log_transport_context *transp,
+                            char *buf, size_t len);
+
+LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
+    .node = { &logdLoggerRead.node, &logdLoggerRead.node },
+    .name = "logd",
+    .available = logdAvailable,
+    .version = logdVersion,
+    .read = logdRead,
+    .poll = logdPoll,
+    .close = logdClose,
+    .clear = logdClear,
+    .getSize = logdGetSize,
+    .setSize = logdSetSize,
+    .getReadableSize = logdGetSize,
+    .getPrune = logdGetPrune,
+    .setPrune = logdSetPrune,
+    .getStats = logdGetStats,
+};
+
+static int logdAvailable(log_id_t logId)
+{
+    if (logId > LOG_ID_KERNEL) {
+        return -EINVAL;
+    }
+    if (logId == LOG_ID_SECURITY) {
+        uid_t uid = __android_log_uid();
+        if (uid != AID_SYSTEM) {
+            return -EPERM;
+        }
+    }
+    if (access("/dev/socket/logdw", W_OK) == 0) {
+        return 0;
+    }
+    return -EBADF;
+}
+
+/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
+
+#if defined(_WIN32)
+
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -ENOSYS;
+}
+
+#else /* !_WIN32 */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+/* Private copy of ../libcutils/socket_local.h prevent library loops */
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+/* End of ../libcutils/socket_local.h */
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
+                                        struct sockaddr_un *p_addr,
+                                        socklen_t *alen)
+{
+    memset (p_addr, 0, sizeof (*p_addr));
+    size_t namelen;
+
+    switch (namespaceId) {
+    case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#if defined(__linux__)
+        namelen  = strlen(name);
+
+        /* Test with length +1 for the *initial* '\0'. */
+        if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+            goto error;
+        }
+
+        /*
+         * Note: The path in this case is *not* supposed to be
+         * '\0'-terminated. ("man 7 unix" for the gory details.)
+         */
+
+        p_addr->sun_path[0] = 0;
+        memcpy(p_addr->sun_path + 1, name, namelen);
+#else
+        /* this OS doesn't have the Linux abstract namespace */
+
+        namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+        strcat(p_addr->sun_path, name);
+#endif
+        break;
+
+    case ANDROID_SOCKET_NAMESPACE_RESERVED:
+        namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+        strcat(p_addr->sun_path, name);
+        break;
+
+    case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+        namelen = strlen(name);
+        /* unix_path_max appears to be missing on linux */
+        if (namelen > sizeof(*p_addr)
+                - offsetof(struct sockaddr_un, sun_path) - 1) {
+            goto error;
+        }
+
+        strcpy(p_addr->sun_path, name);
+        break;
+
+    default:
+        /* invalid namespace id */
+        return -1;
+    }
+
+    p_addr->sun_family = AF_LOCAL;
+    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+    return 0;
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
+                                            int namespaceId, int type __unused)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+        goto error;
+    }
+
+    return fd;
+
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
+{
+    int s;
+
+    s = socket(AF_LOCAL, type, 0);
+    if(s < 0) return -1;
+
+    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
+#endif /* !_WIN32 */
+/* End of ../libcutils/socket_local_client.c */
+
+/* worker for sending the command to the logger */
+static ssize_t send_log_msg(struct android_log_logger *logger,
+                            const char *msg, char *buf, size_t buf_size)
+{
+    ssize_t ret;
+    size_t len;
+    char *cp;
+    int errno_save = 0;
+    int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    if (sock < 0) {
+        return sock;
+    }
+
+    if (msg) {
+        snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned) -1);
+    }
+
+    len = strlen(buf) + 1;
+    ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+    if (ret <= 0) {
+        goto done;
+    }
+
+    len = buf_size;
+    cp = buf;
+    while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+        struct pollfd p;
+
+        if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+            break;
+        }
+
+        len -= ret;
+        cp += ret;
+
+        memset(&p, 0, sizeof(p));
+        p.fd = sock;
+        p.events = POLLIN;
+
+        /* Give other side 20ms to refill pipe */
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+        if (ret <= 0) {
+            break;
+        }
+
+        if (!(p.revents & POLLIN)) {
+            ret = 0;
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ret += buf_size - len;
+    }
+
+done:
+    if ((ret == -1) && errno) {
+        errno_save = errno;
+    }
+    close(sock);
+    if (errno_save) {
+        errno = errno_save;
+    }
+    return ret;
+}
+
+static int check_log_success(char *buf, ssize_t ret)
+{
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (strncmp(buf, "success", 7)) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    return 0;
+}
+
+static int logdClear(struct android_log_logger *logger,
+                     struct android_log_transport_context *transp __unused)
+{
+    char buf[512];
+
+    return check_log_success(buf,
+        send_log_msg(logger, "clear %d", buf, sizeof(buf)));
+}
+
+/* returns the total size of the log's ring buffer */
+static ssize_t logdGetSize(struct android_log_logger *logger,
+                           struct android_log_transport_context *transp __unused)
+{
+    char buf[512];
+
+    ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if ((buf[0] < '0') || ('9' < buf[0])) {
+        return -1;
+    }
+
+    return atol(buf);
+}
+
+static ssize_t logdSetSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp __unused,
+        size_t size)
+{
+    char buf[512];
+
+    snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
+
+    return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+static ssize_t logdGetReadableSize(
+       struct android_log_logger *logger,
+       struct android_log_transport_context *transp __unused)
+{
+    char buf[512];
+
+    ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if ((buf[0] < '0') || ('9' < buf[0])) {
+        return -1;
+    }
+
+    return atol(buf);
+}
+
+/*
+ * returns the logger version
+ */
+static int logdVersion(
+        struct android_log_logger *logger __unused,
+        struct android_log_transport_context *transp __unused)
+{
+    uid_t uid = __android_log_uid();
+    return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
+}
+
+/*
+ * returns statistics
+ */
+static ssize_t logdGetStats(struct android_log_logger_list *logger_list,
+                            struct android_log_transport_context *transp __unused,
+                            char *buf, size_t len)
+{
+    struct android_log_logger *logger;
+    char *cp = buf;
+    size_t remaining = len;
+    size_t n;
+
+    n = snprintf(cp, remaining, "getStatistics");
+    n = min(n, remaining);
+    remaining -= n;
+    cp += n;
+
+    logger_for_each(logger, logger_list) {
+        n = snprintf(cp, remaining, " %d", logger->logId);
+        n = min(n, remaining);
+        remaining -= n;
+        cp += n;
+    }
+
+    if (logger_list->pid) {
+        snprintf(cp, remaining, " pid=%u", logger_list->pid);
+    }
+
+    return send_log_msg(NULL, NULL, buf, len);
+}
+
+static ssize_t logdGetPrune(
+        struct android_log_logger_list *logger_list __unused,
+        struct android_log_transport_context *transp __unused,
+        char *buf, size_t len)
+{
+    return send_log_msg(NULL, "getPruneList", buf, len);
+}
+
+static ssize_t logdSetPrune(
+        struct android_log_logger_list *logger_list __unused,
+        struct android_log_transport_context *transp __unused,
+        char *buf, size_t len)
+{
+    const char cmd[] = "setPruneList ";
+    const size_t cmdlen = sizeof(cmd) - 1;
+
+    if (strlen(buf) > (len - cmdlen)) {
+        return -ENOMEM; /* KISS */
+    }
+    memmove(buf + cmdlen, buf, len - cmdlen);
+    buf[len - 1] = '\0';
+    memcpy(buf, cmd, cmdlen);
+
+    return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
+}
+
+
+static void caught_signal(int signum __unused)
+{
+}
+
+static int logdOpen(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp)
+{
+    struct android_log_logger *logger;
+    struct sigaction ignore;
+    struct sigaction old_sigaction;
+    unsigned int old_alarm = 0;
+    char buffer[256], *cp, c;
+    int e, ret, remaining;
+
+    int sock = transp->context.sock;
+    if (sock > 0) {
+        return sock;
+    }
+
+    if (!logger_list) {
+        return -EINVAL;
+    }
+
+    sock = socket_local_client("logdr",
+                               ANDROID_SOCKET_NAMESPACE_RESERVED,
+                               SOCK_SEQPACKET);
+    if (sock == 0) {
+        /* Guarantee not file descriptor zero */
+        int newsock = socket_local_client("logdr",
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_SEQPACKET);
+        close(sock);
+        sock = newsock;
+    }
+    if (sock <= 0) {
+        if ((sock == -1) && errno) {
+            return -errno;
+        }
+        return sock;
+    }
+
+    strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ?
+            "dumpAndClose" : "stream");
+    cp = buffer + strlen(buffer);
+
+    strcpy(cp, " lids");
+    cp += 5;
+    c = '=';
+    remaining = sizeof(buffer) - (cp - buffer);
+    logger_for_each(logger, logger_list) {
+        ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
+        ret = min(ret, remaining);
+        remaining -= ret;
+        cp += ret;
+        c = ',';
+    }
+
+    if (logger_list->tail) {
+        ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+        ret = min(ret, remaining);
+        remaining -= ret;
+        cp += ret;
+    }
+
+    if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+        if (logger_list->mode & ANDROID_LOG_WRAP) {
+            // ToDo: alternate API to allow timeout to be adjusted.
+            ret = snprintf(cp, remaining, " timeout=%u",
+                           ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
+            ret = min(ret, remaining);
+            remaining -= ret;
+            cp += ret;
+        }
+        ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+                       logger_list->start.tv_sec,
+                       logger_list->start.tv_nsec);
+        ret = min(ret, remaining);
+        remaining -= ret;
+        cp += ret;
+    }
+
+    if (logger_list->pid) {
+        ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+        ret = min(ret, remaining);
+        cp += ret;
+    }
+
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+        /* Deal with an unresponsive logd */
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
+        /* particularily useful if tombstone is reporting for logd */
+        sigaction(SIGALRM, &ignore, &old_sigaction);
+        old_alarm = alarm(30);
+    }
+    ret = write(sock, buffer, cp - buffer);
+    e = errno;
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+        if (e == EINTR) {
+            e = ETIMEDOUT;
+        }
+        alarm(old_alarm);
+        sigaction(SIGALRM, &old_sigaction, NULL);
+    }
+
+    if (ret <= 0) {
+        close(sock);
+        if ((ret == -1) && e) {
+            return -e;
+        }
+        if (ret == 0) {
+            return -EIO;
+        }
+        return ret;
+    }
+
+    return transp->context.sock = sock;
+}
+
+/* Read from the selected logs */
+static int logdRead(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp,
+                    struct log_msg *log_msg)
+{
+    int ret, e;
+    struct sigaction ignore;
+    struct sigaction old_sigaction;
+    unsigned int old_alarm = 0;
+
+    ret = logdOpen(logger_list, transp);
+    if (ret < 0) {
+        return ret;
+    }
+
+    memset(log_msg, 0, sizeof(*log_msg));
+
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
+        /* particularily useful if tombstone is reporting for logd */
+        sigaction(SIGALRM, &ignore, &old_sigaction);
+        old_alarm = alarm(30);
+    }
+
+    /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+    ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+    e = errno;
+
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+        if ((ret == 0) || (e == EINTR)) {
+            e = EAGAIN;
+            ret = -1;
+        }
+        alarm(old_alarm);
+        sigaction(SIGALRM, &old_sigaction, NULL);
+    }
+
+    if ((ret == -1) && e) {
+        return -e;
+    }
+    return ret;
+}
+
+static int logdPoll(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp)
+{
+    struct pollfd p;
+
+    int ret = logdOpen(logger_list, transp);
+    if (ret < 0) {
+        return ret;
+    }
+
+    memset(&p, 0, sizeof(p));
+    p.fd = ret;
+    p.events = POLLIN;
+    ret = poll(&p, 1, 20);
+    if ((ret > 0) && !(p.revents & POLLIN)) {
+        ret = 0;
+    }
+    if ((ret == -1) && errno) {
+        return -errno;
+    }
+    return ret;
+}
+
+/* Close all the logs */
+static void logdClose(struct android_log_logger_list *logger_list __unused,
+                      struct android_log_transport_context *transp)
+{
+    if (transp->context.sock > 0) {
+        close (transp->context.sock);
+        transp->context.sock = -1;
+    }
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
deleted file mode 100644
index 85a4aab..0000000
--- a/liblog/logd_write.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * Copyright (C) 2007-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.
- */
-#if (FAKE_LOG_DEVICE == 0)
-#include <endian.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#if (FAKE_LOG_DEVICE == 0)
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif
-#include <time.h>
-#include <unistd.h>
-
-#ifdef __BIONIC__
-#include <android/set_abort_message.h>
-#endif
-
-#include <log/event_tag_map.h>
-#include <log/logd.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "log_cdefs.h"
-
-#define LOG_BUF_SIZE 1024
-
-#if FAKE_LOG_DEVICE
-/* This will be defined when building for the host. */
-#include "fake_log_device.h"
-#endif
-
-static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static void lock()
-{
-    /*
-     * If we trigger a signal handler in the middle of locked activity and the
-     * signal handler logs a message, we could get into a deadlock state.
-     */
-    pthread_mutex_lock(&log_init_lock);
-}
-
-static int trylock()
-{
-    return pthread_mutex_trylock(&log_init_lock);
-}
-
-static void unlock()
-{
-    pthread_mutex_unlock(&log_init_lock);
-}
-
-#else   /* !defined(_WIN32) */
-
-#define lock() ((void)0)
-#define trylock() (0) /* success */
-#define unlock() ((void)0)
-
-#endif  /* !defined(_WIN32) */
-
-#if FAKE_LOG_DEVICE
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
-#else
-static int logd_fd = -1;
-static int pstore_fd = -1;
-#endif
-
-/*
- * This is used by the C++ code to decide if it should write logs through
- * the C code.  Basically, if /dev/socket/logd is available, we're running in
- * the simulator rather than a desktop tool and want to use the device.
- */
-static enum {
-    kLogUninitialized, kLogNotAvailable, kLogAvailable
-} g_log_status = kLogUninitialized;
-
-LIBLOG_ABI_PUBLIC int __android_log_dev_available()
-{
-    if (g_log_status == kLogUninitialized) {
-        if (access("/dev/socket/logdw", W_OK) == 0)
-            g_log_status = kLogAvailable;
-        else
-            g_log_status = kLogNotAvailable;
-    }
-
-    return (g_log_status == kLogAvailable);
-}
-
-/* log_init_lock assumed */
-static int __write_to_log_initialize()
-{
-    int i, ret = 0;
-
-#if FAKE_LOG_DEVICE
-    for (i = 0; i < LOG_ID_MAX; i++) {
-        char buf[sizeof("/dev/log_security")];
-        snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
-        log_fds[i] = fakeLogOpen(buf, O_WRONLY);
-    }
-#else
-    if (pstore_fd < 0) {
-        pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
-    }
-
-    if (logd_fd < 0) {
-        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
-        if (i < 0) {
-            ret = -errno;
-        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
-            ret = -errno;
-            close(i);
-        } else {
-            struct sockaddr_un un;
-            memset(&un, 0, sizeof(struct sockaddr_un));
-            un.sun_family = AF_UNIX;
-            strcpy(un.sun_path, "/dev/socket/logdw");
-
-            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
-                                           sizeof(struct sockaddr_un))) < 0) {
-                ret = -errno;
-                close(i);
-            } else {
-                logd_fd = i;
-            }
-        }
-    }
-#endif
-
-    return ret;
-}
-
-static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
-{
-    ssize_t ret;
-#if FAKE_LOG_DEVICE
-    int log_fd;
-
-    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
-        log_fd = log_fds[(int)log_id];
-    } else {
-        return -EBADF;
-    }
-    do {
-        ret = fakeLogWritev(log_fd, vec, nr);
-        if (ret < 0) {
-            ret = -errno;
-        }
-    } while (ret == -EINTR);
-#else
-    static const unsigned header_length = 2;
-    struct iovec newVec[nr + header_length];
-    android_log_header_t header;
-    android_pmsg_log_header_t pmsg_header;
-    struct timespec ts;
-    size_t i, payload_size;
-    static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
-    static pid_t last_pid = (pid_t) -1;
-    static atomic_int_fast32_t dropped;
-    static atomic_int_fast32_t dropped_security;
-
-    if (!nr) {
-        return -EINVAL;
-    }
-
-    if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
-        last_uid = getuid();
-    }
-    if (last_pid == (pid_t) -1) {
-        last_pid = getpid();
-    }
-    if (log_id == LOG_ID_SECURITY) {
-        if (vec[0].iov_len < 4) {
-            return -EINVAL;
-        }
-        /* Matches clientHasLogCredentials() in logd */
-        if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT) && (last_uid != AID_LOG)) {
-            uid_t uid = geteuid();
-            if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
-                gid_t gid = getgid();
-                if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
-                    gid = getegid();
-                    if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
-                        int num_groups;
-                        gid_t *groups;
-
-                        num_groups = getgroups(0, NULL);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                        groups = calloc(num_groups, sizeof(gid_t));
-                        if (!groups) {
-                            return -ENOMEM;
-                        }
-                        num_groups = getgroups(num_groups, groups);
-                        while (num_groups > 0) {
-                            if (groups[num_groups - 1] == AID_LOG) {
-                                break;
-                            }
-                            --num_groups;
-                        }
-                        free(groups);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                    }
-                }
-            }
-        }
-        if (!__android_log_security()) {
-            atomic_store(&dropped_security, 0);
-            return -EPERM;
-        }
-    } else if (log_id == LOG_ID_EVENTS) {
-        static atomic_uintptr_t map;
-        int ret;
-        const char *tag;
-        EventTagMap *m, *f;
-
-        if (vec[0].iov_len < 4) {
-            return -EINVAL;
-        }
-
-        tag = NULL;
-        f = NULL;
-        m = (EventTagMap *)atomic_load(&map);
-
-        if (!m) {
-            ret = trylock();
-            m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
-            if (!m) {
-                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
-                if (ret) { /* trylock failed, use local copy, mark for close */
-                    f = m;
-                } else {
-                    if (!m) { /* One chance to open map file */
-                        m = (EventTagMap *)(uintptr_t)-1LL;
-                    }
-                    atomic_store(&map, (uintptr_t)m);
-                }
-            }
-            if (!ret) { /* trylock succeeded, unlock */
-                unlock();
-            }
-        }
-        if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
-            tag = android_lookupEventTag(
-                                    m,
-                                    htole32(((uint32_t *)vec[0].iov_base)[0]));
-        }
-        ret = __android_log_is_loggable(ANDROID_LOG_INFO,
-                                        tag,
-                                        ANDROID_LOG_VERBOSE);
-        if (f) { /* local copy marked for close */
-            android_closeEventTagMap(f);
-        }
-        if (!ret) {
-            return -EPERM;
-        }
-    } else {
-        /* Validate the incoming tag, tag content can not split across iovec */
-        char prio = ANDROID_LOG_VERBOSE;
-        const char *tag = vec[0].iov_base;
-        size_t len = vec[0].iov_len;
-        if (!tag) {
-            len = 0;
-        }
-        if (len > 0) {
-            prio = *tag;
-            if (len > 1) {
-                --len;
-                ++tag;
-            } else {
-                len = vec[1].iov_len;
-                tag = ((const char *)vec[1].iov_base);
-                if (!tag) {
-                    len = 0;
-                }
-            }
-        }
-        /* tag must be nul terminated */
-        if (strnlen(tag, len) >= len) {
-            tag = NULL;
-        }
-
-        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-            return -EPERM;
-        }
-    }
-
-    /*
-     *  struct {
-     *      // what we provide to pstore
-     *      android_pmsg_log_header_t pmsg_header;
-     *      // what we provide to socket
-     *      android_log_header_t header;
-     *      // caller provides
-     *      union {
-     *          struct {
-     *              char     prio;
-     *              char     payload[];
-     *          } string;
-     *          struct {
-     *              uint32_t tag
-     *              char     payload[];
-     *          } binary;
-     *      };
-     *  };
-     */
-
-    clock_gettime(android_log_clockid(), &ts);
-
-    pmsg_header.magic = LOGGER_MAGIC;
-    pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
-    pmsg_header.uid = last_uid;
-    pmsg_header.pid = last_pid;
-
-    header.tid = gettid();
-    header.realtime.tv_sec = ts.tv_sec;
-    header.realtime.tv_nsec = ts.tv_nsec;
-
-    newVec[0].iov_base   = (unsigned char *) &pmsg_header;
-    newVec[0].iov_len    = sizeof(pmsg_header);
-    newVec[1].iov_base   = (unsigned char *) &header;
-    newVec[1].iov_len    = sizeof(header);
-
-    if (logd_fd > 0) {
-        int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
-                                                    memory_order_relaxed);
-        if (snapshot) {
-            android_log_event_int_t buffer;
-
-            header.id = LOG_ID_SECURITY;
-            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
-            buffer.payload.type = EVENT_TYPE_INT;
-            buffer.payload.data = htole32(snapshot);
-
-            newVec[2].iov_base = &buffer;
-            newVec[2].iov_len  = sizeof(buffer);
-
-            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
-            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped_security, snapshot,
-                                          memory_order_relaxed);
-            }
-        }
-        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-        if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
-                                                  "liblog",
-                                                  ANDROID_LOG_VERBOSE)) {
-            android_log_event_int_t buffer;
-
-            header.id = LOG_ID_EVENTS;
-            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
-            buffer.payload.type = EVENT_TYPE_INT;
-            buffer.payload.data = htole32(snapshot);
-
-            newVec[2].iov_base = &buffer;
-            newVec[2].iov_len  = sizeof(buffer);
-
-            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
-            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped, snapshot,
-                                          memory_order_relaxed);
-            }
-        }
-    }
-
-    header.id = log_id;
-
-    for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
-        newVec[i].iov_base = vec[i - header_length].iov_base;
-        payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
-
-        if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
-            newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
-            if (newVec[i].iov_len) {
-                ++i;
-            }
-            payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
-            break;
-        }
-    }
-    pmsg_header.len += payload_size;
-
-    if (pstore_fd >= 0) {
-        TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
-    }
-
-    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
-        /*
-         * ignore log messages we send to ourself (logd).
-         * Such log messages are often generated by libraries we depend on
-         * which use standard Android logging.
-         */
-        return 0;
-    }
-
-    if (logd_fd < 0) {
-        return -EBADF;
-    }
-
-    /*
-     * The write below could be lost, but will never block.
-     *
-     * To logd, we drop the pmsg_header
-     *
-     * ENOTCONN occurs if logd dies.
-     * EAGAIN occurs if logd is overloaded.
-     */
-    ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
-    if (ret < 0) {
-        ret = -errno;
-        if (ret == -ENOTCONN) {
-            lock();
-            close(logd_fd);
-            logd_fd = -1;
-            ret = __write_to_log_initialize();
-            unlock();
-
-            if (ret < 0) {
-                return ret;
-            }
-
-            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
-            if (ret < 0) {
-                ret = -errno;
-            }
-        }
-    }
-
-    if (ret > (ssize_t)sizeof(header)) {
-        ret -= sizeof(header);
-    } else if (ret == -EAGAIN) {
-        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
-        if (log_id == LOG_ID_SECURITY) {
-            atomic_fetch_add_explicit(&dropped_security, 1,
-                                      memory_order_relaxed);
-        }
-    }
-#endif
-
-    return ret;
-}
-
-#if FAKE_LOG_DEVICE
-static const char *LOG_NAME[LOG_ID_MAX] = {
-    [LOG_ID_MAIN] = "main",
-    [LOG_ID_RADIO] = "radio",
-    [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash",
-    [LOG_ID_SECURITY] = "security",
-    [LOG_ID_KERNEL] = "kernel",
-};
-
-LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
-{
-    if (log_id >= LOG_ID_MAX) {
-        log_id = LOG_ID_MAIN;
-    }
-    return LOG_NAME[log_id];
-}
-#endif
-
-static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
-{
-    lock();
-
-    if (write_to_log == __write_to_log_init) {
-        int ret;
-
-        ret = __write_to_log_initialize();
-        if (ret < 0) {
-            unlock();
-#if (FAKE_LOG_DEVICE == 0)
-            if (pstore_fd >= 0) {
-                __write_to_log_daemon(log_id, vec, nr);
-            }
-#endif
-            return ret;
-        }
-
-        write_to_log = __write_to_log_daemon;
-    }
-
-    unlock();
-
-    return write_to_log(log_id, vec, nr);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
-                                          const char *msg)
-{
-    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
-                                              const char *tag, const char *msg)
-{
-    struct iovec vec[3];
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if ((bufID != LOG_ID_RADIO) &&
-         (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS"))) {
-            bufID = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-#if __BIONIC__
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-#endif
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(bufID, vec, 3);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
-                                           const char *fmt, va_list ap)
-{
-    char buf[LOG_BUF_SIZE];
-
-    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-
-    return __android_log_write(prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
-                                          const char *fmt, ...)
-{
-    va_list ap;
-    char buf[LOG_BUF_SIZE];
-
-    va_start(ap, fmt);
-    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-    va_end(ap);
-
-    return __android_log_write(prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
-                                              const char *tag,
-                                              const char *fmt, ...)
-{
-    va_list ap;
-    char buf[LOG_BUF_SIZE];
-
-    va_start(ap, fmt);
-    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-    va_end(ap);
-
-    return __android_log_buf_write(bufID, prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC void __android_log_assert(
-        const char *cond,
-        const char *tag,
-        const char *fmt, ...)
-{
-    char buf[LOG_BUF_SIZE];
-
-    if (fmt) {
-        va_list ap;
-        va_start(ap, fmt);
-        vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-        va_end(ap);
-    } else {
-        /* Msg not provided, log condition.  N.B. Do not use cond directly as
-         * format string as it could contain spurious '%' syntax (e.g.
-         * "%d" in "blocks%devs == 0").
-         */
-        if (cond)
-            snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
-        else
-            strcpy(buf, "Unspecified assertion failed");
-    }
-
-    __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    abort(); /* abort so we have a chance to debug the situation */
-    /* NOTREACHED */
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
-                                           const void *payload, size_t len)
-{
-    struct iovec vec[2];
-
-    vec[0].iov_base = &tag;
-    vec[0].iov_len = sizeof(tag);
-    vec[1].iov_base = (void*)payload;
-    vec[1].iov_len = len;
-
-    return write_to_log(LOG_ID_EVENTS, vec, 2);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
-                                                    const void *payload,
-                                                    size_t len)
-{
-    struct iovec vec[2];
-
-    vec[0].iov_base = &tag;
-    vec[0].iov_len = sizeof(tag);
-    vec[1].iov_base = (void*)payload;
-    vec[1].iov_len = len;
-
-    return write_to_log(LOG_ID_SECURITY, vec, 2);
-}
-
-/*
- * Like __android_log_bwrite, but takes the type as well.  Doesn't work
- * for the general case where we're generating lists of stuff, but very
- * handy if we just want to dump an integer into the log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
-                                            const void *payload, size_t len)
-{
-    struct iovec vec[3];
-
-    vec[0].iov_base = &tag;
-    vec[0].iov_len = sizeof(tag);
-    vec[1].iov_base = &type;
-    vec[1].iov_len = sizeof(type);
-    vec[2].iov_base = (void*)payload;
-    vec[2].iov_len = len;
-
-    return write_to_log(LOG_ID_EVENTS, vec, 3);
-}
-
-/*
- * Like __android_log_bwrite, but used for writing strings to the
- * event log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
-{
-    struct iovec vec[4];
-    char type = EVENT_TYPE_STRING;
-    uint32_t len = strlen(payload);
-
-    vec[0].iov_base = &tag;
-    vec[0].iov_len = sizeof(tag);
-    vec[1].iov_base = &type;
-    vec[1].iov_len = sizeof(type);
-    vec[2].iov_base = &len;
-    vec[2].iov_len = sizeof(len);
-    vec[3].iov_base = (void*)payload;
-    vec[3].iov_len = len;
-
-    return write_to_log(LOG_ID_EVENTS, vec, 4);
-}
-
-/*
- * Like __android_log_security_bwrite, but used for writing strings to the
- * security log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
-                                                     const char *payload)
-{
-    struct iovec vec[4];
-    char type = EVENT_TYPE_STRING;
-    uint32_t len = strlen(payload);
-
-    vec[0].iov_base = &tag;
-    vec[0].iov_len = sizeof(tag);
-    vec[1].iov_base = &type;
-    vec[1].iov_len = sizeof(type);
-    vec[2].iov_base = &len;
-    vec[2].iov_len = sizeof(len);
-    vec[3].iov_base = (void*)payload;
-    vec[3].iov_len = len;
-
-    return write_to_log(LOG_ID_SECURITY, vec, 4);
-}
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
new file mode 100644
index 0000000..696237d
--- /dev/null
+++ b/liblog/logd_writer.c
@@ -0,0 +1,267 @@
+/*
+ * 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 <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+
+static int logdAvailable(log_id_t LogId);
+static int logdOpen();
+static void logdClose();
+static int logdWrite(log_id_t logId, struct timespec *ts,
+                     struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
+    .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
+    .context.sock = -1,
+    .name = "logd",
+    .available = logdAvailable,
+    .open = logdOpen,
+    .close = logdClose,
+    .write = logdWrite,
+};
+
+/* log_init_lock assumed */
+static int logdOpen()
+{
+    int i, ret = 0;
+
+    if (logdLoggerWrite.context.sock < 0) {
+        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        if (i < 0) {
+            ret = -errno;
+        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
+            ret = -errno;
+            close(i);
+        } else {
+            struct sockaddr_un un;
+            memset(&un, 0, sizeof(struct sockaddr_un));
+            un.sun_family = AF_UNIX;
+            strcpy(un.sun_path, "/dev/socket/logdw");
+
+            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+                                           sizeof(struct sockaddr_un))) < 0) {
+                ret = -errno;
+                close(i);
+            } else {
+                logdLoggerWrite.context.sock = i;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static void logdClose()
+{
+    if (logdLoggerWrite.context.sock >= 0) {
+        close(logdLoggerWrite.context.sock);
+        logdLoggerWrite.context.sock = -1;
+    }
+}
+
+static int logdAvailable(log_id_t logId)
+{
+    if (logId > LOG_ID_SECURITY) {
+        return -EINVAL;
+    }
+    if (logId == LOG_ID_SECURITY) {
+        uid_t uid = __android_log_uid();
+        if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
+            return -EPERM;
+        }
+    }
+    if (logdLoggerWrite.context.sock < 0) {
+        if (access("/dev/socket/logdw", W_OK) == 0) {
+            return 0;
+        }
+        return -EBADF;
+    }
+    return 1;
+}
+
+static int logdWrite(log_id_t logId, struct timespec *ts,
+                     struct iovec *vec, size_t nr)
+{
+    ssize_t ret;
+    static const unsigned headerLength = 1;
+    struct iovec newVec[nr + headerLength];
+    android_log_header_t header;
+    size_t i, payloadSize;
+    static atomic_int_fast32_t dropped;
+    static atomic_int_fast32_t droppedSecurity;
+
+    if (logdLoggerWrite.context.sock < 0) {
+        return -EBADF;
+    }
+
+    /* logd, after initialization and priv drop */
+    if (__android_log_uid() == AID_LOGD) {
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    header.tid = gettid();
+    header.realtime.tv_sec = ts->tv_sec;
+    header.realtime.tv_nsec = ts->tv_nsec;
+
+    newVec[0].iov_base = (unsigned char *)&header;
+    newVec[0].iov_len  = sizeof(header);
+
+    if (logdLoggerWrite.context.sock > 0) {
+        int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
+                                                    memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_SECURITY;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[headerLength].iov_base = &buffer;
+            newVec[headerLength].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&droppedSecurity, snapshot,
+                                          memory_order_relaxed);
+            }
+        }
+        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
+                                                  "liblog",
+                                                  ANDROID_LOG_VERBOSE)) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_EVENTS;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[headerLength].iov_base = &buffer;
+            newVec[headerLength].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped, snapshot,
+                                          memory_order_relaxed);
+            }
+        }
+    }
+
+    header.id = logId;
+
+    for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+        newVec[i].iov_base = vec[i - headerLength].iov_base;
+        payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+        if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            break;
+        }
+    }
+
+    /*
+     * The write below could be lost, but will never block.
+     *
+     * ENOTCONN occurs if logd dies.
+     * EAGAIN occurs if logd is overloaded.
+     */
+    ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+    if (ret < 0) {
+        ret = -errno;
+        if (ret == -ENOTCONN) {
+            __android_log_lock();
+            logdClose();
+            ret = logdOpen();
+            __android_log_unlock();
+
+            if (ret < 0) {
+                return ret;
+            }
+
+            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+            if (ret < 0) {
+                ret = -errno;
+            }
+        }
+    }
+
+    if (ret > (ssize_t)sizeof(header)) {
+        ret -= sizeof(header);
+    } else if (ret == -EAGAIN) {
+        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+        if (logId == LOG_ID_SECURITY) {
+            atomic_fetch_add_explicit(&droppedSecurity, 1,
+                                      memory_order_relaxed);
+        }
+    }
+
+    return ret;
+}
diff --git a/liblog/logger.h b/liblog/logger.h
new file mode 100644
index 0000000..61bc396
--- /dev/null
+++ b/liblog/logger.h
@@ -0,0 +1,159 @@
+/*
+ * 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 _LIBLOG_LOGGER_H__
+#define _LIBLOG_LOGGER_H__
+
+#include <stdbool.h>
+#include <log/uio.h>
+
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/log_read.h>
+#include <log/logger.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+/* Union, sock or fd of zero is not allowed unless static initialized */
+union android_log_context {
+  void *private;
+  int sock;
+  int fd;
+  struct listnode *node;
+};
+
+struct android_log_transport_write {
+  struct listnode node;
+  const char *name;
+  union android_log_context context; /* Initialized by static allocation */
+
+  int (*available)(log_id_t logId);
+  int (*open)();
+  void (*close)();
+  int (*write)(log_id_t logId, struct timespec *ts, struct iovec *vec, size_t nr);
+};
+
+struct android_log_logger_list;
+struct android_log_transport_context;
+struct android_log_logger;
+
+struct android_log_transport_read {
+  struct listnode node;
+  const char *name;
+
+  int (*available)(log_id_t logId);
+  int (*version)(struct android_log_logger *logger,
+                 struct android_log_transport_context *transp);
+  void (*close)(struct android_log_logger_list *logger_list,
+                struct android_log_transport_context *transp);
+
+  /*
+   * Expect all to instantiate open on any call, so we do not have
+   * an expicit open call
+   */
+  int (*read)(struct android_log_logger_list *logger_list,
+              struct android_log_transport_context *transp,
+              struct log_msg *log_msg);
+  /* Assumption is only called if not ANDROID_LOG_NONBLOCK */
+  int (*poll)(struct android_log_logger_list *logger_list,
+              struct android_log_transport_context *transp);
+
+  int (*clear)(struct android_log_logger *logger,
+               struct android_log_transport_context *transp);
+  ssize_t (*setSize)(struct android_log_logger *logger,
+                     struct android_log_transport_context *transp,
+                     size_t size);
+  ssize_t (*getSize)(struct android_log_logger *logger,
+                     struct android_log_transport_context *transp);
+  ssize_t (*getReadableSize)(struct android_log_logger *logger,
+                             struct android_log_transport_context *transp);
+
+  ssize_t (*getPrune)(struct android_log_logger_list *logger_list,
+                      struct android_log_transport_context *transp,
+                      char *buf, size_t len);
+  ssize_t (*setPrune)(struct android_log_logger_list *logger_list,
+                      struct android_log_transport_context *transp,
+                      char *buf, size_t len);
+  ssize_t (*getStats)(struct android_log_logger_list *logger_list,
+                      struct android_log_transport_context *transp,
+                      char *buf, size_t len);
+};
+
+struct android_log_logger_list {
+  struct listnode logger;
+  struct listnode transport;
+  int mode;
+  unsigned int tail;
+  log_time start;
+  pid_t pid;
+};
+
+struct android_log_logger {
+  struct listnode node;
+  struct android_log_logger_list *parent;
+
+  log_id_t logId;
+};
+
+struct android_log_transport_context {
+  struct listnode node;
+  union android_log_context context; /* zero init per-transport context */
+  struct android_log_logger_list *parent;
+
+  struct android_log_transport_read *transport;
+  unsigned logMask;
+  int ret;
+  struct log_msg logMsg; /* valid is logMsg.len != 0 */
+};
+
+/* assumes caller has structures read-locked, single threaded, or fenced */
+#define transport_context_for_each(transp, logger_list)              \
+  for (transp = node_to_item((logger_list)->transport.next,          \
+                             struct android_log_transport_context,   \
+                             node);                                  \
+       (transp != node_to_item(&(logger_list)->transport,            \
+                               struct android_log_transport_context, \
+                               node)) &&                             \
+           (transp->parent == (logger_list));                        \
+       transp = node_to_item(transp->node.next,                      \
+                             struct android_log_transport_context, node))
+
+#define logger_for_each(logp, logger_list)                          \
+    for (logp = node_to_item((logger_list)->logger.next,            \
+                             struct android_log_logger, node);      \
+         (logp != node_to_item(&(logger_list)->logger,              \
+                               struct android_log_logger, node)) && \
+             (logp->parent == (logger_list));                       \
+         logp = node_to_item((logp)->node.next,                     \
+                             struct android_log_logger, node))
+
+/* OS specific dribs and drabs */
+
+#if defined(_WIN32)
+typedef uint32_t uid_t;
+#endif
+
+LIBLOG_HIDDEN uid_t __android_log_uid();
+LIBLOG_HIDDEN pid_t __android_log_pid();
+LIBLOG_HIDDEN void __android_log_lock();
+LIBLOG_HIDDEN int __android_log_trylock();
+LIBLOG_HIDDEN void __android_log_unlock();
+
+__END_DECLS
+
+#endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_lock.c b/liblog/logger_lock.c
new file mode 100644
index 0000000..ee979bd
--- /dev/null
+++ b/liblog/logger_lock.c
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/*
+ * Some OS specific dribs and drabs (locking etc).
+ */
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#include <private/android_filesystem_config.h>
+
+#include "logger.h"
+
+LIBLOG_HIDDEN uid_t __android_log_uid()
+{
+#if defined(_WIN32)
+    return AID_SYSTEM;
+#else
+    static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+    if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+        last_uid = getuid();
+    }
+    return last_uid;
+#endif
+}
+
+LIBLOG_HIDDEN pid_t __android_log_pid()
+{
+    static pid_t last_pid = (pid_t) -1;
+
+    if (last_pid == (pid_t) -1) {
+        last_pid = getpid();
+    }
+    return last_pid;
+}
+
+#if !defined(_WIN32)
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+LIBLOG_HIDDEN void __android_log_lock()
+{
+#if !defined(_WIN32)
+    /*
+     * If we trigger a signal handler in the middle of locked activity and the
+     * signal handler logs a message, we could get into a deadlock state.
+     */
+    pthread_mutex_lock(&log_init_lock);
+#endif
+}
+
+LIBLOG_HIDDEN int __android_log_trylock()
+{
+#if !defined(_WIN32)
+    return pthread_mutex_trylock(&log_init_lock);
+#else
+    return 0;
+#endif
+}
+
+LIBLOG_HIDDEN void __android_log_unlock()
+{
+#if !defined(_WIN32)
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+}
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
new file mode 100644
index 0000000..b7ccac5
--- /dev/null
+++ b/liblog/logger_name.c
@@ -0,0 +1,65 @@
+/*
+** Copyright 2013-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 <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#include "log_portability.h"
+
+/* In the future, we would like to make this list extensible */
+static const char *LOG_NAME[LOG_ID_MAX] = {
+    [LOG_ID_MAIN] = "main",
+    [LOG_ID_RADIO] = "radio",
+    [LOG_ID_EVENTS] = "events",
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
+    [LOG_ID_KERNEL] = "kernel",
+};
+
+LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
+{
+    if (log_id >= LOG_ID_MAX) {
+        log_id = LOG_ID_MAIN;
+    }
+    return LOG_NAME[log_id];
+}
+
+LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
+{
+    const char *b;
+    int ret;
+
+    if (!logName) {
+        return -1; /* NB: log_id_t is unsigned */
+    }
+    b = strrchr(logName, '/');
+    if (!b) {
+        b = logName;
+    } else {
+        ++b;
+    }
+
+    for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+        const char *l = LOG_NAME[ret];
+        if (l && !strcmp(b, l)) {
+            return ret;
+        }
+    }
+    return -1;   /* should never happen */
+}
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
new file mode 100644
index 0000000..f15c7cd
--- /dev/null
+++ b/liblog/logger_read.c
@@ -0,0 +1,474 @@
+/*
+** Copyright 2013-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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+#include "config_read.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* android_logger_alloc unimplemented, no use case */
+/* android_logger_free not exported */
+static void android_logger_free(struct logger *logger)
+{
+    struct android_log_logger *logger_internal =
+            (struct android_log_logger *)logger;
+
+    if (!logger_internal) {
+        return;
+    }
+
+    list_remove(&logger_internal->node);
+
+    free(logger_internal);
+}
+
+/* android_logger_alloc unimplemented, no use case */
+
+/* method for getting the associated sublog id */
+LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
+{
+    return ((struct android_log_logger *)logger)->logId;
+}
+
+static int init_transport_context(struct android_log_logger_list *logger_list)
+{
+    struct android_log_transport_read *transport;
+    struct listnode *node;
+
+    if (!logger_list) {
+        return -EINVAL;
+    }
+
+    if (list_empty(&logger_list->logger)) {
+        return -EINVAL;
+    }
+
+    if (!list_empty(&logger_list->transport)) {
+        return 0;
+    }
+
+    __android_log_lock();
+    /* mini __write_to_log_initialize() to populate transports */
+    if (list_empty(&__android_log_transport_read) &&
+            list_empty(&__android_log_persist_read)) {
+        __android_log_config_read();
+    }
+    __android_log_unlock();
+
+    node = (logger_list->mode & ANDROID_LOG_PSTORE) ?
+            &__android_log_persist_read : &__android_log_transport_read;
+
+    read_transport_for_each(transport, node) {
+        struct android_log_transport_context *transp;
+        struct android_log_logger *logger;
+        unsigned logMask = 0;
+
+        logger_for_each(logger, logger_list) {
+            log_id_t logId = logger->logId;
+
+            if (transport->read &&
+                    (!transport->available ||
+                        (transport->available(logId) >= 0))) {
+                logMask |= 1 << logId;
+            }
+        }
+        if (!logMask) {
+            continue;
+        }
+        transp = calloc(1, sizeof(*transp));
+        if (!transp) {
+            return -ENOMEM;
+        }
+        transp->parent = logger_list;
+        transp->transport = transport;
+        transp->logMask = logMask;
+        transp->ret = 1;
+        list_add_tail(&logger_list->transport, &transp->node);
+    }
+    if (list_empty(&logger_list->transport)) {
+        return -ENODEV;
+    }
+    return 0;
+}
+
+#define LOGGER_FUNCTION(logger, def, func, args...)                           \
+    ssize_t ret = -EINVAL;                                                    \
+    struct android_log_transport_context *transp;                             \
+    struct android_log_logger *logger_internal =                              \
+            (struct android_log_logger *)logger;                              \
+                                                                              \
+    if (!logger_internal) {                                                   \
+        return ret;                                                           \
+    }                                                                         \
+    ret = init_transport_context(logger_internal->parent);                    \
+    if (ret < 0) {                                                            \
+        return ret;                                                           \
+    }                                                                         \
+                                                                              \
+    ret = (def);                                                              \
+    transport_context_for_each(transp, logger_internal->parent) {             \
+        if ((transp->logMask & (1 << logger_internal->logId)) &&              \
+                transp->transport && transp->transport->func) {               \
+            ssize_t retval = (transp->transport->func)(logger_internal,       \
+                                                       transp, ## args);      \
+            if ((ret >= 0) || (ret == (def))) {                               \
+                ret = retval;                                                 \
+            }                                                                 \
+        }                                                                     \
+    }                                                                         \
+    return ret
+
+LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
+{
+    LOGGER_FUNCTION(logger, -ENODEV, clear);
+}
+
+/* returns the total size of the log's ring buffer */
+LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
+{
+    LOGGER_FUNCTION(logger, -ENODEV, getSize);
+}
+
+LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
+                                                  unsigned long size)
+{
+    LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
+        struct logger *logger)
+{
+    LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
+}
+
+/*
+ * returns the logger version
+ */
+LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger)
+{
+    LOGGER_FUNCTION(logger, 4, version);
+}
+
+#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                 \
+    struct android_log_transport_context *transp;                             \
+    struct android_log_logger_list *logger_list_internal =                    \
+            (struct android_log_logger_list *)logger_list;                    \
+                                                                              \
+    ssize_t ret = init_transport_context(logger_list_internal);               \
+    if (ret < 0) {                                                            \
+        return ret;                                                           \
+    }                                                                         \
+                                                                              \
+    ret = (def);                                                              \
+    transport_context_for_each(transp, logger_list_internal) {                \
+        if (transp->transport && (transp->transport->func)) {                 \
+            ssize_t retval = (transp->transport->func)(logger_list_internal,  \
+                                                       transp, ## args);      \
+            if ((ret >= 0) || (ret == (def))) {                               \
+                ret = retval;                                                 \
+            }                                                                 \
+        }                                                                     \
+    }                                                                         \
+    return ret
+
+/*
+ * returns statistics
+ */
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
+        struct logger_list *logger_list,
+        char *buf, size_t len)
+{
+    LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
+        struct logger_list *logger_list,
+        char *buf, size_t len)
+{
+    LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
+        struct logger_list *logger_list,
+        char *buf, size_t len)
+{
+    LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
+        int mode,
+        unsigned int tail,
+        pid_t pid)
+{
+    struct android_log_logger_list *logger_list;
+
+    logger_list = calloc(1, sizeof(*logger_list));
+    if (!logger_list) {
+        return NULL;
+    }
+
+    list_init(&logger_list->logger);
+    list_init(&logger_list->transport);
+    logger_list->mode = mode;
+    logger_list->tail = tail;
+    logger_list->pid = pid;
+
+    return (struct logger_list *)logger_list;
+}
+
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
+        int mode,
+        log_time start,
+        pid_t pid)
+{
+    struct android_log_logger_list *logger_list;
+
+    logger_list = calloc(1, sizeof(*logger_list));
+    if (!logger_list) {
+        return NULL;
+    }
+
+    list_init(&logger_list->logger);
+    list_init(&logger_list->transport);
+    logger_list->mode = mode;
+    logger_list->start = start;
+    logger_list->pid = pid;
+
+    return (struct logger_list *)logger_list;
+}
+
+/* android_logger_list_register unimplemented, no use case */
+/* android_logger_list_unregister unimplemented, no use case */
+
+/* Open the named log and add it to the logger list */
+LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
+        struct logger_list *logger_list,
+        log_id_t logId)
+{
+    struct android_log_logger_list *logger_list_internal =
+            (struct android_log_logger_list *)logger_list;
+    struct android_log_logger *logger;
+
+    if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
+        goto err;
+    }
+
+    logger_for_each(logger, logger_list_internal) {
+        if (logger->logId == logId) {
+            goto ok;
+        }
+    }
+
+    logger = calloc(1, sizeof(*logger));
+    if (!logger) {
+        goto err;
+    }
+
+    logger->logId = logId;
+    list_add_tail(&logger_list_internal->logger, &logger->node);
+    logger->parent = logger_list_internal;
+
+    /* Reset known transports to re-evaluate, we just added one */
+    while (!list_empty(&logger_list_internal->transport)) {
+        struct listnode *node = list_head(&logger_list_internal->transport);
+        struct android_log_transport_context *transp =
+                node_to_item(node, struct android_log_transport_context, node);
+
+        list_remove(&transp->node);
+        free(transp);
+    }
+    goto ok;
+
+err:
+    logger = NULL;
+ok:
+    return (struct logger *)logger;
+}
+
+/* Open the single named log and make it part of a new logger list */
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
+        log_id_t logId,
+        int mode,
+        unsigned int tail,
+        pid_t pid)
+{
+    struct logger_list *logger_list =
+            android_logger_list_alloc(mode, tail, pid);
+
+    if (!logger_list) {
+        return NULL;
+    }
+
+    if (!android_logger_open(logger_list, logId)) {
+        android_logger_list_free(logger_list);
+        return NULL;
+    }
+
+    return logger_list;
+}
+
+/* Read from the selected logs */
+LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
+                                               struct log_msg *log_msg)
+{
+    struct android_log_transport_context *transp;
+    struct android_log_logger_list *logger_list_internal =
+            (struct android_log_logger_list *)logger_list;
+
+    int ret = init_transport_context(logger_list_internal);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* at least one transport */
+    transp = node_to_item(logger_list_internal->transport.next,
+                          struct android_log_transport_context, node);
+
+    /* more than one transport? */
+    if (transp->node.next != &logger_list_internal->transport) {
+        /* Poll and merge sort the entries if from multiple transports */
+        struct android_log_transport_context *oldest = NULL;
+        int ret;
+        int polled = 0;
+        do {
+            if (polled) {
+                sched_yield();
+            }
+            ret = -1000;
+            polled = 0;
+            do {
+                int retval = transp->ret;
+                if ((retval > 0) && !transp->logMsg.entry.len) {
+                    if (!transp->transport->read) {
+                        retval = transp->ret = 0;
+                    } else if ((logger_list_internal->mode &
+                                ANDROID_LOG_NONBLOCK) ||
+                            !transp->transport->poll) {
+                        retval = transp->ret = (*transp->transport->read)(
+                                logger_list_internal,
+                                transp,
+                                &transp->logMsg);
+                    } else {
+                        int pollval = (*transp->transport->poll)(
+                                logger_list_internal, transp);
+                        if (pollval <= 0) {
+                            sched_yield();
+                            pollval = (*transp->transport->poll)(
+                                    logger_list_internal, transp);
+                        }
+                        polled = 1;
+                        if (pollval < 0) {
+                            if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
+                                return -EAGAIN;
+                            }
+                            retval = transp->ret = pollval;
+                        } else if (pollval > 0) {
+                            retval = transp->ret = (*transp->transport->read)(
+                                    logger_list_internal,
+                                    transp,
+                                    &transp->logMsg);
+                        }
+                    }
+                }
+                if (ret < retval) {
+                    ret = retval;
+                }
+                if ((transp->ret > 0) && transp->logMsg.entry.len &&
+                        (!oldest ||
+                            (oldest->logMsg.entry.sec >
+                                transp->logMsg.entry.sec) ||
+                            ((oldest->logMsg.entry.sec ==
+                                    transp->logMsg.entry.sec) &&
+                                (oldest->logMsg.entry.nsec >
+                                    transp->logMsg.entry.nsec)))) {
+                    oldest = transp;
+                }
+                transp = node_to_item(transp->node.next,
+                                      struct android_log_transport_context,
+                                      node);
+            } while (transp != node_to_item(
+                    &logger_list_internal->transport,
+                    struct android_log_transport_context,
+                    node));
+            if (!oldest &&
+                    (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
+                return (ret < 0) ? ret : -EAGAIN;
+            }
+            transp = node_to_item(logger_list_internal->transport.next,
+                                  struct android_log_transport_context, node);
+        } while (!oldest && (ret > 0));
+        if (!oldest) {
+            return ret;
+        }
+        memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
+                    (oldest->logMsg.entry.hdr_size ?
+                        oldest->logMsg.entry.hdr_size :
+                        sizeof(struct logger_entry)));
+        oldest->logMsg.entry.len = 0; /* Mark it as copied */
+        return oldest->ret;
+    }
+
+    /* if only one, no need to copy into transport_context and merge-sort */
+    return (transp->transport->read)(logger_list_internal, transp, log_msg);
+}
+
+/* Close all the logs */
+LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
+{
+    struct android_log_logger_list *logger_list_internal =
+            (struct android_log_logger_list *)logger_list;
+
+    if (logger_list_internal == NULL) {
+        return;
+    }
+
+    while (!list_empty(&logger_list_internal->transport)) {
+        struct listnode *node = list_head(&logger_list_internal->transport);
+        struct android_log_transport_context *transp =
+                node_to_item(node, struct android_log_transport_context, node);
+
+        if (transp->transport && transp->transport->close) {
+            (*transp->transport->close)(logger_list_internal, transp);
+        }
+        list_remove(&transp->node);
+        free(transp);
+    }
+
+    while (!list_empty(&logger_list_internal->logger)) {
+        struct listnode *node = list_head(&logger_list_internal->logger);
+        struct android_log_logger *logger =
+                node_to_item(node, struct android_log_logger, node);
+        android_logger_free((struct logger *)logger);
+    }
+
+    free(logger_list_internal);
+}
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
new file mode 100644
index 0000000..a4155e9
--- /dev/null
+++ b/liblog/logger_write.c
@@ -0,0 +1,509 @@
+/*
+ * 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 <errno.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
+#include <log/event_tag_map.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+#define LOG_BUF_SIZE 1024
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code.  Basically, if /dev/socket/logd is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+    kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+
+LIBLOG_ABI_PUBLIC int __android_log_dev_available()
+{
+    struct android_log_transport_write *node;
+    size_t i;
+
+    if (list_empty(&__android_log_transport_write)) {
+        return kLogUninitialized;
+    }
+    for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+        write_transport_for_each(node, &__android_log_transport_write) {
+            if (node->write &&
+                    (!node->available || ((*node->available)(i) >= 0))) {
+                return kLogAvailable;
+            }
+        }
+    }
+    return kLogNotAvailable;
+}
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+    struct android_log_transport_write *transport;
+    struct listnode *n;
+    int i = 0, ret = 0;
+
+    __android_log_config_write();
+    write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+        if (!transport->open || ((*transport->open)() < 0)) {
+            if (transport->close) {
+                (*transport->close)();
+            }
+            list_remove(&transport->node);
+            continue;
+        }
+        ++ret;
+    }
+    write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+        if (!transport->open || ((*transport->open)() < 0)) {
+            if (transport->close) {
+                (*transport->close)();
+            }
+            list_remove(&transport->node);
+            continue;
+        }
+        ++i;
+    }
+    if (!ret && !i) {
+        return -ENODEV;
+    }
+
+    return ret;
+}
+
+/*
+ * Extract a 4-byte value from a byte stream. le32toh open coded
+ */
+static inline uint32_t get4LE(const uint8_t* src)
+{
+    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+    struct android_log_transport_write *node;
+    int ret;
+    struct timespec ts;
+    size_t len, i;
+
+    for (len = i = 0; i < nr; ++i) {
+        len += vec[i].iov_len;
+    }
+    if (!len) {
+        return -EINVAL;
+    }
+
+#if defined(__BIONIC__)
+    if (log_id == LOG_ID_SECURITY) {
+        uid_t uid;
+
+        if (vec[0].iov_len < 4) {
+            return -EINVAL;
+        }
+
+        uid = __android_log_uid();
+        /* Matches clientHasLogCredentials() in logd */
+        if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+            uid = geteuid();
+            if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+                gid_t gid = getgid();
+                if ((gid != AID_SYSTEM) &&
+                        (gid != AID_ROOT) &&
+                        (gid != AID_LOG)) {
+                    gid = getegid();
+                    if ((gid != AID_SYSTEM) &&
+                            (gid != AID_ROOT) &&
+                            (gid != AID_LOG)) {
+                        int num_groups;
+                        gid_t *groups;
+
+                        num_groups = getgroups(0, NULL);
+                        if (num_groups <= 0) {
+                            return -EPERM;
+                        }
+                        groups = calloc(num_groups, sizeof(gid_t));
+                        if (!groups) {
+                            return -ENOMEM;
+                        }
+                        num_groups = getgroups(num_groups, groups);
+                        while (num_groups > 0) {
+                            if (groups[num_groups - 1] == AID_LOG) {
+                                break;
+                            }
+                            --num_groups;
+                        }
+                        free(groups);
+                        if (num_groups <= 0) {
+                            return -EPERM;
+                        }
+                    }
+                }
+            }
+        }
+        if (!__android_log_security()) {
+            /* If only we could reset downstream logd counter */
+            return -EPERM;
+        }
+    } else if (log_id == LOG_ID_EVENTS) {
+        static atomic_uintptr_t map;
+        const char *tag;
+        EventTagMap *m, *f;
+
+        if (vec[0].iov_len < 4) {
+            return -EINVAL;
+        }
+
+        tag = NULL;
+        f = NULL;
+        m = (EventTagMap *)atomic_load(&map);
+
+        if (!m) {
+            ret = __android_log_trylock();
+            m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
+            if (!m) {
+                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+                if (ret) { /* trylock failed, use local copy, mark for close */
+                    f = m;
+                } else {
+                    if (!m) { /* One chance to open map file */
+                        m = (EventTagMap *)(uintptr_t)-1LL;
+                    }
+                    atomic_store(&map, (uintptr_t)m);
+                }
+            }
+            if (!ret) { /* trylock succeeded, unlock */
+                __android_log_unlock();
+            }
+        }
+        if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
+            tag = android_lookupEventTag(m, get4LE(vec[0].iov_base));
+        }
+        ret = __android_log_is_loggable(ANDROID_LOG_INFO,
+                                        tag,
+                                        ANDROID_LOG_VERBOSE);
+        if (f) { /* local copy marked for close */
+            android_closeEventTagMap(f);
+        }
+        if (!ret) {
+            return -EPERM;
+        }
+    } else {
+        /* Validate the incoming tag, tag content can not split across iovec */
+        char prio = ANDROID_LOG_VERBOSE;
+        const char *tag = vec[0].iov_base;
+        size_t len = vec[0].iov_len;
+        if (!tag) {
+            len = 0;
+        }
+        if (len > 0) {
+            prio = *tag;
+            if (len > 1) {
+                --len;
+                ++tag;
+            } else {
+                len = vec[1].iov_len;
+                tag = ((const char *)vec[1].iov_base);
+                if (!tag) {
+                    len = 0;
+                }
+            }
+        }
+        /* tag must be nul terminated */
+        if (strnlen(tag, len) >= len) {
+            tag = NULL;
+        }
+
+        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+            return -EPERM;
+        }
+    }
+
+    clock_gettime(android_log_clockid(), &ts);
+#else
+    /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        ts.tv_sec = tv.tv_sec;
+        ts.tv_nsec = tv.tv_usec * 1000;
+    }
+#endif
+
+    ret = 0;
+    write_transport_for_each(node, &__android_log_transport_write) {
+        if (node->write) {
+            ssize_t retval;
+            retval = (*node->write)(log_id, &ts, vec, nr);
+            if (ret >= 0) {
+                ret = retval;
+            }
+        }
+    }
+
+    write_transport_for_each(node, &__android_log_persist_write) {
+        if (node->write) {
+            (void)(*node->write)(log_id, &ts, vec, nr);
+        }
+    }
+
+    return ret;
+}
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+    __android_log_lock();
+
+    if (write_to_log == __write_to_log_init) {
+        int ret;
+
+        ret = __write_to_log_initialize();
+        if (ret < 0) {
+            __android_log_unlock();
+            if (!list_empty(&__android_log_persist_write)) {
+                __write_to_log_daemon(log_id, vec, nr);
+            }
+            return ret;
+        }
+
+        write_to_log = __write_to_log_daemon;
+    }
+
+    __android_log_unlock();
+
+    return write_to_log(log_id, vec, nr);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
+                                          const char *msg)
+{
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
+                                              const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+    char tmp_tag[32];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if ((bufID != LOG_ID_RADIO) &&
+         (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS"))) {
+            bufID = LOG_ID_RADIO;
+            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
+
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(bufID, vec, 3);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
+                                           const char *fmt, va_list ap)
+{
+    char buf[LOG_BUF_SIZE];
+
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
+                                          const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_write(prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
+                                              const char *tag,
+                                              const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag,
+                                            const char *fmt, ...)
+{
+    char buf[LOG_BUF_SIZE];
+
+    if (fmt) {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+        va_end(ap);
+    } else {
+        /* Msg not provided, log condition.  N.B. Do not use cond directly as
+         * format string as it could contain spurious '%' syntax (e.g.
+         * "%d" in "blocks%devs == 0").
+         */
+        if (cond)
+            snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+        else
+            strcpy(buf, "Unspecified assertion failed");
+    }
+
+    __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+    abort(); /* abort so we have a chance to debug the situation */
+    /* NOTREACHED */
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
+                                           const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
+                                                    const void *payload,
+                                                    size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_SECURITY, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well.  Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
+                                            const void *payload, size_t len)
+{
+    struct iovec vec[3];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = (void*)payload;
+    vec[2].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
+
+/*
+ * Like __android_log_security_bwrite, but used for writing strings to the
+ * security log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
+                                                     const char *payload)
+{
+    struct iovec vec[4];
+    char type = EVENT_TYPE_STRING;
+    uint32_t len = strlen(payload);
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = &type;
+    vec[1].iov_len = sizeof(type);
+    vec[2].iov_base = &len;
+    vec[2].iov_len = sizeof(len);
+    vec[3].iov_base = (void*)payload;
+    vec[3].iov_len = len;
+
+    return write_to_log(LOG_ID_SECURITY, vec, 4);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 02df8dd..d7de864 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -34,7 +34,7 @@
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
new file mode 100644
index 0000000..5695e8a
--- /dev/null
+++ b/liblog/pmsg_reader.c
@@ -0,0 +1,587 @@
+/*
+ * 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_read.h"
+#include "logger.h"
+
+static int pmsgAvailable(log_id_t logId);
+static int pmsgVersion(struct android_log_logger *logger,
+                       struct android_log_transport_context *transp);
+static int pmsgRead(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp,
+                    struct log_msg *log_msg);
+static void pmsgClose(struct android_log_logger_list *logger_list,
+                      struct android_log_transport_context *transp);
+static int pmsgClear(struct android_log_logger *logger,
+                     struct android_log_transport_context *transp);
+
+LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = {
+    .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node },
+    .name = "pmsg",
+    .available = pmsgAvailable,
+    .version = pmsgVersion,
+    .read = pmsgRead,
+    .poll = NULL,
+    .close = pmsgClose,
+    .clear = pmsgClear,
+    .setSize = NULL,
+    .getSize = NULL,
+    .getReadableSize = NULL,
+    .getPrune = NULL,
+    .setPrune = NULL,
+    .getStats = NULL,
+};
+
+static int pmsgAvailable(log_id_t logId)
+{
+    if (logId > LOG_ID_SECURITY) {
+        return -EINVAL;
+    }
+    if (access("/dev/pmsg0", W_OK) == 0) {
+        return 0;
+    }
+    return -EBADF;
+}
+
+/* Determine the credentials of the caller */
+static bool uid_has_log_permission(uid_t uid)
+{
+    return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+}
+
+static uid_t get_best_effective_uid()
+{
+    uid_t euid;
+    uid_t uid;
+    gid_t gid;
+    ssize_t i;
+    static uid_t last_uid = (uid_t) -1;
+
+    if (last_uid != (uid_t) -1) {
+        return last_uid;
+    }
+    uid = __android_log_uid();
+    if (uid_has_log_permission(uid)) {
+        return last_uid = uid;
+    }
+    euid = geteuid();
+    if (uid_has_log_permission(euid)) {
+        return last_uid = euid;
+    }
+    gid = getgid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    gid = getegid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    i = getgroups((size_t) 0, NULL);
+    if (i > 0) {
+        gid_t list[i];
+
+        getgroups(i, list);
+        while (--i >= 0) {
+            if (uid_has_log_permission(list[i])) {
+                return last_uid = list[i];
+            }
+        }
+    }
+    return last_uid = uid;
+}
+
+static int pmsgClear(struct android_log_logger *logger __unused,
+                     struct android_log_transport_context *transp __unused)
+{
+    if (uid_has_log_permission(get_best_effective_uid())) {
+        return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+    }
+    errno = EPERM;
+    return -1;
+}
+
+/*
+ * returns the logger version
+ */
+static int pmsgVersion(struct android_log_logger *logger __unused,
+                       struct android_log_transport_context *transp __unused)
+{
+    return 4;
+}
+
+static int pmsgRead(struct android_log_logger_list *logger_list,
+                    struct android_log_transport_context *transp,
+                    struct log_msg *log_msg)
+{
+    ssize_t ret;
+    off_t current, next;
+    uid_t uid;
+    struct android_log_logger *logger;
+    struct __attribute__((__packed__)) {
+        android_pmsg_log_header_t p;
+        android_log_header_t l;
+    } buf;
+    static uint8_t preread_count;
+    bool is_system;
+
+    memset(log_msg, 0, sizeof(*log_msg));
+
+    if (transp->context.fd <= 0) {
+        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+
+        if (fd < 0) {
+            return -errno;
+        }
+        if (fd == 0) { /* Argggg */
+            fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+            close(0);
+            if (fd < 0) {
+                return -errno;
+            }
+        }
+        transp->context.fd = fd;
+        preread_count = 0;
+    }
+
+    while(1) {
+        if (preread_count < sizeof(buf)) {
+            ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+                                          &buf.p.magic + preread_count,
+                                          sizeof(buf) - preread_count));
+            if (ret < 0) {
+                return -errno;
+            }
+            preread_count += ret;
+        }
+        if (preread_count != sizeof(buf)) {
+            return preread_count ? -EIO : -EAGAIN;
+        }
+        if ((buf.p.magic != LOGGER_MAGIC)
+         || (buf.p.len <= sizeof(buf))
+         || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
+         || (buf.l.id >= LOG_ID_MAX)
+         || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+            do {
+                memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+            } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+            continue;
+        }
+        preread_count = 0;
+
+        if ((transp->logMask & (1 << buf.l.id)) &&
+                ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
+                    ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
+                        ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
+                            (logger_list->start.tv_nsec <=
+                                buf.l.realtime.tv_nsec)))) &&
+                (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
+            uid = get_best_effective_uid();
+            is_system = uid_has_log_permission(uid);
+            if (is_system || (uid == buf.p.uid)) {
+                ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+                                          is_system ?
+                                              log_msg->entry_v4.msg :
+                                              log_msg->entry_v3.msg,
+                                          buf.p.len - sizeof(buf)));
+                if (ret < 0) {
+                    return -errno;
+                }
+                if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+                    return -EIO;
+                }
+
+                log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+                log_msg->entry_v4.hdr_size = is_system ?
+                    sizeof(log_msg->entry_v4) :
+                    sizeof(log_msg->entry_v3);
+                log_msg->entry_v4.pid = buf.p.pid;
+                log_msg->entry_v4.tid = buf.l.tid;
+                log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
+                log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
+                log_msg->entry_v4.lid = buf.l.id;
+                if (is_system) {
+                    log_msg->entry_v4.uid = buf.p.uid;
+                }
+
+                return ret;
+            }
+        }
+
+        current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+                                           (off_t)0, SEEK_CUR));
+        if (current < 0) {
+            return -errno;
+        }
+        next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+                                        (off_t)(buf.p.len - sizeof(buf)),
+                                        SEEK_CUR));
+        if (next < 0) {
+            return -errno;
+        }
+        if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+            return -EIO;
+        }
+    }
+}
+
+static void pmsgClose(struct android_log_logger_list *logger_list __unused,
+                      struct android_log_transport_context *transp) {
+    if (transp->context.fd > 0) {
+        close (transp->context.fd);
+    }
+    transp->context.fd = 0;
+}
+
+LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
+        log_id_t logId,
+        char prio,
+        const char *prefix,
+        __android_log_pmsg_file_read_fn fn, void *arg) {
+    ssize_t ret;
+    struct android_log_logger_list logger_list;
+    struct android_log_transport_context transp;
+    struct content {
+        struct listnode node;
+        union {
+            struct logger_entry_v4 entry;
+            struct logger_entry_v4 entry_v4;
+            struct logger_entry_v3 entry_v3;
+            struct logger_entry_v2 entry_v2;
+            struct logger_entry    entry_v1;
+        };
+    } *content;
+    struct names {
+        struct listnode node;
+        struct listnode content;
+        log_id_t id;
+        char prio;
+        char name[];
+    } *names;
+    struct listnode name_list;
+    struct listnode *node, *n;
+    size_t len, prefix_len;
+
+    if (!fn) {
+        return -EINVAL;
+    }
+
+    /* Add just enough clues in logger_list and transp to make API function */
+    memset(&logger_list, 0, sizeof(logger_list));
+    memset(&transp, 0, sizeof(transp));
+
+    logger_list.mode = ANDROID_LOG_PSTORE |
+                       ANDROID_LOG_NONBLOCK |
+                       ANDROID_LOG_RDONLY;
+    transp.logMask = (unsigned)-1;
+    if (logId != LOG_ID_ANY) {
+        transp.logMask = (1 << logId);
+    }
+    transp.logMask &= ~((1 << LOG_ID_KERNEL) |
+                        (1 << LOG_ID_EVENTS) |
+                        (1 << LOG_ID_SECURITY));
+    if (!transp.logMask) {
+        return -EINVAL;
+    }
+
+    /* Initialize name list */
+    list_init(&name_list);
+
+    ret = SSIZE_MAX;
+
+    /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
+    prefix_len = 0;
+    if (prefix) {
+        const char *prev = NULL, *last = NULL, *cp = prefix;
+        while ((cp = strpbrk(cp, "/:"))) {
+            prev = last;
+            last = cp;
+            cp = cp + 1;
+        }
+        if (prev) {
+            prefix = prev + 1;
+        }
+        prefix_len = strlen(prefix);
+    }
+
+    /* Read the file content */
+    while (pmsgRead(&logger_list, &transp, &transp.logMsg) > 0) {
+        char *cp;
+        size_t hdr_size = transp.logMsg.entry.hdr_size ?
+            transp.logMsg.entry.hdr_size : sizeof(transp.logMsg.entry_v1);
+        char *msg = (char *)&transp.logMsg + hdr_size;
+        char *split = NULL;
+
+        /* Check for invalid sequence number */
+        if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
+                ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+                    ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE)) {
+            continue;
+        }
+
+        /* Determine if it has <dirbase>:<filebase> format for tag */
+        len = transp.logMsg.entry.len - sizeof(prio);
+        for (cp = msg + sizeof(prio);
+                *cp && isprint(*cp) && !isspace(*cp) && --len;
+                ++cp) {
+            if (*cp == ':') {
+                if (split) {
+                    break;
+                }
+                split = cp;
+            }
+        }
+        if (*cp || !split) {
+            continue;
+        }
+
+        /* Filters */
+        if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
+            size_t offset;
+            /*
+             *   Allow : to be a synonym for /
+             * Things we do dealing with const char * and do not alloc
+             */
+            split = strchr(prefix, ':');
+            if (split) {
+                continue;
+            }
+            split = strchr(prefix, '/');
+            if (!split) {
+                continue;
+            }
+            offset = split - prefix;
+            if ((msg[offset + sizeof(prio)] != ':') ||
+                    strncmp(msg + sizeof(prio), prefix, offset)) {
+                continue;
+            }
+            ++offset;
+            if ((prefix_len > offset) &&
+                    strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
+                continue;
+            }
+        }
+
+        if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
+            continue;
+        }
+
+        /* check if there is an existing entry */
+        list_for_each(node, &name_list) {
+            names = node_to_item(node, struct names, node);
+            if (!strcmp(names->name, msg + sizeof(prio)) &&
+                    (names->id == transp.logMsg.entry.lid) &&
+                    (names->prio == *msg)) {
+                break;
+            }
+        }
+
+        /* We do not have an existing entry, create and add one */
+        if (node == &name_list) {
+            static const char numbers[] = "0123456789";
+            unsigned long long nl;
+
+            len = strlen(msg + sizeof(prio)) + 1;
+            names = calloc(1, sizeof(*names) + len);
+            if (!names) {
+                ret = -ENOMEM;
+                break;
+            }
+            strcpy(names->name, msg + sizeof(prio));
+            names->id = transp.logMsg.entry.lid;
+            names->prio = *msg;
+            list_init(&names->content);
+            /*
+             * Insert in reverse numeric _then_ alpha sorted order as
+             * representative of log rotation:
+             *
+             *   log.10
+             *   klog.10
+             *   . . .
+             *   log.2
+             *   klog.2
+             *   log.1
+             *   klog.1
+             *   log
+             *   klog
+             *
+             * thus when we present the content, we are provided the oldest
+             * first, which when 'refreshed' could spill off the end of the
+             * pmsg FIFO but retaining the newest data for last with best
+             * chances to survive.
+             */
+            nl = 0;
+            cp = strpbrk(names->name, numbers);
+            if (cp) {
+                nl = strtoull(cp, NULL, 10);
+            }
+            list_for_each_reverse(node, &name_list) {
+                struct names *a_name = node_to_item(node, struct names, node);
+                const char *r = a_name->name;
+                int compare = 0;
+
+                unsigned long long nr = 0;
+                cp = strpbrk(r, numbers);
+                if (cp) {
+                    nr = strtoull(cp, NULL, 10);
+                }
+                if (nr != nl) {
+                    compare = (nl > nr) ? 1 : -1;
+                }
+                if (compare == 0) {
+                    compare = strcmp(names->name, r);
+                }
+                if (compare <= 0) {
+                    break;
+                }
+            }
+            list_add_head(node, &names->node);
+        }
+
+        /* Remove any file fragments that match our sequence number */
+        list_for_each_safe(node, n, &names->content) {
+            content = node_to_item(node, struct content, node);
+            if (transp.logMsg.entry.nsec == content->entry.nsec) {
+                list_remove(&content->node);
+                free(content);
+            }
+        }
+
+        /* Add content */
+        content = calloc(1, sizeof(content->node) +
+                hdr_size + transp.logMsg.entry.len);
+        if (!content) {
+            ret = -ENOMEM;
+            break;
+        }
+        memcpy(&content->entry, &transp.logMsg.entry,
+               hdr_size + transp.logMsg.entry.len);
+
+        /* Insert in sequence number sorted order, to ease reconstruction */
+        list_for_each_reverse(node, &names->content) {
+            if ((node_to_item(node, struct content, node))->entry.nsec <
+                    transp.logMsg.entry.nsec) {
+                break;
+            }
+        }
+        list_add_head(node, &content->node);
+    }
+    pmsgClose(&logger_list, &transp);
+
+    /* Progress through all the collected files */
+    list_for_each_safe(node, n, &name_list) {
+        struct listnode *content_node, *m;
+        char *buf;
+        size_t sequence, tag_len;
+
+        names = node_to_item(node, struct names, node);
+
+        /* Construct content into a linear buffer */
+        buf = NULL;
+        len = 0;
+        sequence = 0;
+        tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
+        list_for_each_safe(content_node, m, &names->content) {
+            ssize_t add_len;
+
+            content = node_to_item(content_node, struct content, node);
+            add_len = content->entry.len - tag_len - sizeof(prio);
+            if (add_len <= 0) {
+                list_remove(content_node);
+                free(content);
+                continue;
+            }
+
+            if (!buf) {
+                buf = malloc(sizeof(char));
+                if (!buf) {
+                    ret = -ENOMEM;
+                    list_remove(content_node);
+                    free(content);
+                    continue;
+                }
+                *buf = '\0';
+            }
+
+            /* Missing sequence numbers */
+            while (sequence < content->entry.nsec) {
+                /* plus space for enforced nul */
+                buf = realloc(buf, len + sizeof(char) + sizeof(char));
+                if (!buf) {
+                    break;
+                }
+                buf[len] = '\f'; /* Mark missing content with a form feed */
+                buf[++len] = '\0';
+                sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
+            }
+            if (!buf) {
+                ret = -ENOMEM;
+                list_remove(content_node);
+                free(content);
+                continue;
+            }
+            /* plus space for enforced nul */
+            buf = realloc(buf, len + add_len + sizeof(char));
+            if (!buf) {
+                ret = -ENOMEM;
+                list_remove(content_node);
+                free(content);
+                continue;
+            }
+            memcpy(buf + len,
+                   (char *)&content->entry + content->entry.hdr_size +
+                       tag_len + sizeof(prio),
+                   add_len);
+            len += add_len;
+            buf[len] = '\0'; /* enforce trailing hidden nul */
+            sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
+
+            list_remove(content_node);
+            free(content);
+        }
+        if (buf) {
+            if (len) {
+                /* Buffer contains enforced trailing nul just beyond length */
+                ssize_t r;
+                *strchr(names->name, ':') = '/'; /* Convert back to filename */
+                r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
+                if ((ret >= 0) && (r > 0)) {
+                    if (ret == SSIZE_MAX) {
+                        ret = r;
+                    } else {
+                        ret += r;
+                    }
+                } else if (r < ret) {
+                    ret = r;
+                }
+            }
+            free(buf);
+        }
+        list_remove(node);
+        free(names);
+    }
+    return (ret == SSIZE_MAX) ? -ENOENT : ret;
+}
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
new file mode 100644
index 0000000..7034ceb
--- /dev/null
+++ b/liblog/pmsg_writer.c
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+/*
+ * pmsg write handler
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static int pmsgOpen();
+static void pmsgClose();
+static int pmsgAvailable(log_id_t logId);
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+                      struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
+    .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
+    .context.fd = -1,
+    .name = "pmsg",
+    .available = pmsgAvailable,
+    .open = pmsgOpen,
+    .close = pmsgClose,
+    .write = pmsgWrite,
+};
+
+static int pmsgOpen()
+{
+    if (pmsgLoggerWrite.context.fd < 0) {
+        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    }
+
+    return pmsgLoggerWrite.context.fd;
+}
+
+static void pmsgClose()
+{
+    if (pmsgLoggerWrite.context.fd >= 0) {
+        close(pmsgLoggerWrite.context.fd);
+        pmsgLoggerWrite.context.fd = -1;
+    }
+}
+
+static int pmsgAvailable(log_id_t logId)
+{
+    if (logId > LOG_ID_SECURITY) {
+        return -EINVAL;
+    }
+    if (pmsgLoggerWrite.context.fd < 0) {
+        if (access("/dev/pmsg0", W_OK) == 0) {
+            return 0;
+        }
+        return -EBADF;
+    }
+    return 1;
+}
+
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+                      struct iovec *vec, size_t nr)
+{
+    static const unsigned headerLength = 2;
+    struct iovec newVec[nr + headerLength];
+    android_log_header_t header;
+    android_pmsg_log_header_t pmsgHeader;
+    size_t i, payloadSize;
+    ssize_t ret;
+
+    if (pmsgLoggerWrite.context.fd < 0) {
+        return -EBADF;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsgHeader;
+     *      // what we provide to file
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    pmsgHeader.magic = LOGGER_MAGIC;
+    pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
+    pmsgHeader.uid = __android_log_uid();
+    pmsgHeader.pid = __android_log_pid();
+
+    header.id = logId;
+    header.tid = gettid();
+    header.realtime.tv_sec = ts->tv_sec;
+    header.realtime.tv_nsec = ts->tv_nsec;
+
+    newVec[0].iov_base   = (unsigned char *)&pmsgHeader;
+    newVec[0].iov_len    = sizeof(pmsgHeader);
+    newVec[1].iov_base   = (unsigned char *)&header;
+    newVec[1].iov_len    = sizeof(header);
+
+    for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+        newVec[i].iov_base = vec[i - headerLength].iov_base;
+        payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+        if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
+            break;
+        }
+    }
+    pmsgHeader.len += payloadSize;
+
+    ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+    if (ret < 0) {
+        ret = errno ? -errno : -ENOTCONN;
+    }
+
+    if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
+        ret -= sizeof(header) - sizeof(pmsgHeader);
+    }
+
+    return ret;
+}
+
+/*
+ * Virtual pmsg filesystem
+ *
+ * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
+ * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
+ * file.
+ *
+ * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
+ */
+
+static inline const char *strnrchr(const char *buf, size_t len, char c) {
+    const char *cp = buf + len;
+    while ((--cp > buf) && (*cp != c));
+    if (cp <= buf) {
+        return buf + len;
+    }
+    return cp;
+}
+
+/* Write a buffer as filename references (tag = <basedir>:<basename>) */
+LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(
+        log_id_t logId,
+        char prio,
+        const char *filename,
+        const char *buf, size_t len) {
+    int fd;
+    size_t length, packet_len;
+    const char *tag;
+    char *cp, *slash;
+    struct timespec ts;
+    struct iovec vec[3];
+
+    /* Make sure the logId value is not a bad idea */
+    if ((logId == LOG_ID_KERNEL) ||       /* Verbotten */
+            (logId == LOG_ID_EVENTS) ||   /* Do not support binary content */
+            (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
+            ((unsigned)logId >= 32)) {    /* fit within logMask on arch32 */
+        return -EINVAL;
+    }
+
+    clock_gettime(android_log_clockid(), &ts);
+
+    cp = strdup(filename);
+    if (!cp) {
+        return -ENOMEM;
+    }
+
+    fd = pmsgLoggerWrite.context.fd;
+    if (fd < 0) {
+        __android_log_lock();
+        fd = pmsgOpen();
+        __android_log_unlock();
+        if (fd < 0) {
+            return -EBADF;
+        }
+    }
+
+    tag = cp;
+    slash = strrchr(cp, '/');
+    if (slash) {
+        *slash = ':';
+        slash = strrchr(cp, '/');
+        if (slash) {
+            tag = slash + 1;
+        }
+    }
+
+    length = strlen(tag) + 1;
+    packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
+
+    vec[0].iov_base = &prio;
+    vec[0].iov_len  = sizeof(char);
+    vec[1].iov_base = (unsigned char *)tag;
+    vec[1].iov_len  = length;
+
+    for (ts.tv_nsec = 0, length = len;
+            length;
+            ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
+        ssize_t ret;
+        size_t transfer;
+
+        if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+                ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
+            len -= length;
+            break;
+        }
+
+        transfer = length;
+        if (transfer > packet_len) {
+            transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
+            if ((transfer < length) && (buf[transfer] == '\n')) {
+                ++transfer;
+            }
+        }
+
+        vec[2].iov_base = (unsigned char *)buf;
+        vec[2].iov_len  = transfer;
+
+        ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+
+        if (ret <= 0) {
+            free(cp);
+            return ret;
+        }
+        length -= transfer;
+        buf += transfer;
+    }
+    free(cp);
+    return len;
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 2767f73..941b9b9 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -957,7 +957,10 @@
 trouble: the fashion of the world is to avoid\n\
 cost, and you encounter it\n\
 LEONATO\n\
-Never came trouble to my house in the likeness of your grace";
+Never came trouble to my house in the likeness of your grace,\n\
+for trouble being gone, comfort should remain, but\n\
+when you depart from me, sorrow abides and happiness\n\
+takes his leave.";
 
 TEST(liblog, max_payload) {
     pid_t pid = getpid();
@@ -2520,3 +2523,56 @@
     EXPECT_LE(0, android_log_destroy(&ctx));
     ASSERT_TRUE(NULL == ctx);
 }
+
+static const char __pmsg_file[] =
+        "/data/william-shakespeare/MuchAdoAboutNothing.txt";
+
+TEST(liblog, __android_log_pmsg_file_write) {
+    EXPECT_LT(0, __android_log_pmsg_file_write(
+            LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+            __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
+    fprintf(stderr, "Reboot, ensure file %s matches\n"
+                    "with liblog.__android_log_msg_file_read test\n",
+                    __pmsg_file);
+}
+
+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);
+    EXPECT_EQ(LOG_ID_CRASH, logId);
+    EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
+    EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
+    EXPECT_EQ(len, sizeof(max_payload_buf));
+    EXPECT_EQ(0, strcmp(max_payload_buf, buf));
+
+    ++signaled;
+    if ((len != sizeof(max_payload_buf)) ||
+            strcmp(max_payload_buf, buf)) {
+        fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
+    }
+    return !arg ||
+           (LOG_ID_CRASH != logId) ||
+           (ANDROID_LOG_VERBOSE != prio) ||
+           !strstr(__pmsg_file, filename) ||
+           (len != sizeof(max_payload_buf)) ||
+           !!strcmp(max_payload_buf, buf) ? -ENOEXEC : 1;
+}
+
+TEST(liblog, __android_log_pmsg_file_read) {
+    signaled = 0;
+
+    ssize_t ret = __android_log_pmsg_file_read(
+            LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+            __pmsg_file, __pmsg_fn, NULL);
+
+    if (ret == -ENOENT) {
+        fprintf(stderr,
+            "No pre-boot results of liblog.__android_log_mesg_file_write to "
+            "compare with,\n"
+            "false positive test result.\n");
+        return;
+    }
+
+    EXPECT_LT(0, ret);
+    EXPECT_EQ(1U, signaled);
+}
diff --git a/liblog/uio.c b/liblog/uio.c
index d0184dc..ac0558f 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -20,7 +20,7 @@
 
 #include <log/uio.h>
 
-#include "log_cdefs.h"
+#include "log_portability.h"
 
 LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count)
 {
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 899c98c..e6b37ed 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -46,7 +46,8 @@
                               jobject class_loader,
                               bool is_shared,
                               jstring java_library_path,
-                              jstring java_permitted_path) {
+                              jstring java_permitted_path,
+                              int32_t target_sdk_version) {
     ScopedUtfChars library_path(env, java_library_path);
 
     std::string permitted_path;
@@ -55,7 +56,7 @@
       permitted_path = path.c_str();
     }
 
-    if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
+    if (!initialized_ && !InitPublicNamespace(library_path.c_str(), target_sdk_version)) {
       return nullptr;
     }
 
@@ -122,12 +123,26 @@
   }
 
  private:
-  bool InitPublicNamespace(const char* library_path) {
+  bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) {
+    std::string publicNativeLibraries = public_libraries_;
+
+    // TODO (dimitry): This is a workaround for http://b/26436837
+    // will be removed before the release.
+    if (target_sdk_version <= 23) {
+      // check if libart.so is loaded.
+      void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD);
+      if (handle != nullptr) {
+        publicNativeLibraries += ":libart.so";
+        dlclose(handle);
+      }
+    }
+    // END OF WORKAROUND
+
     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
     // namespace which is the library_path of the classloader.
-    initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+    initialized_ = android_init_namespaces(publicNativeLibraries.c_str(), library_path);
 
     return initialized_;
   }
@@ -172,7 +187,8 @@
                                                  class_loader,
                                                  is_shared,
                                                  library_path,
-                                                 permitted_path);
+                                                 permitted_path,
+                                                 target_sdk_version);
   if (ns == nullptr) {
     return env->NewStringUTF(dlerror());
   }
@@ -199,7 +215,7 @@
   if (ns == nullptr) {
     // This is the case where the classloader was not created by ApplicationLoaders
     // In this case we create an isolated not-shared namespace for it.
-    ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
+    ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr, target_sdk_version);
     if (ns == nullptr) {
       return nullptr;
     }
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 281b6c8..ce7c3ba 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -4,7 +4,6 @@
 LOCAL_SRC_FILES := \
         dhcpclient.c \
         dhcpmsg.c \
-        dhcp_utils.c \
         ifc_utils.c \
         packet.c
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
deleted file mode 100644
index c6b9fe4..0000000
--- a/libnetutils/dhcp_utils.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright 2008, 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.
- */
-
-/* Utilities for managing the dhcpcd DHCP client daemon */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include <cutils/properties.h>
-
-static const char DAEMON_NAME[]        = "dhcpcd";
-static const char DAEMON_PROP_NAME[]   = "init.svc.dhcpcd";
-static const char HOSTNAME_PROP_NAME[] = "net.hostname";
-static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";
-static const char DHCP_CONFIG_PATH[]   = "/system/etc/dhcpcd/dhcpcd.conf";
-static const int NAP_TIME = 200;   /* wait for 200ms at a time */
-                                  /* when polling for property values */
-static const char DAEMON_NAME_RENEW[]  = "iprenew";
-static char errmsg[100] = "\0";
-/* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
- * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
- * and other properties on a successful bind
- */
-#define MAX_INTERFACE_LENGTH 25
-
-/*
- * P2p interface names increase sequentially p2p-p2p0-1, p2p-p2p0-2.. after
- * group formation. This does not work well with system properties which can quickly
- * exhaust or for specifiying a dhcp start target in init which requires
- * interface to be pre-defined in init.rc file.
- *
- * This function returns a common string p2p for all p2p interfaces.
- */
-void get_p2p_interface_replacement(const char *interface, char *p2p_interface) {
-    /* Use p2p for any interface starting with p2p. */
-    if (strncmp(interface, "p2p",3) == 0) {
-        strncpy(p2p_interface, "p2p", MAX_INTERFACE_LENGTH);
-    } else {
-        strncpy(p2p_interface, interface, MAX_INTERFACE_LENGTH);
-    }
-}
-
-/*
- * Wait for a system property to be assigned a specified value.
- * If desired_value is NULL, then just wait for the property to
- * be created with any value. maxwait is the maximum amount of
- * time in seconds to wait before giving up.
- */
-static int wait_for_property(const char *name, const char *desired_value, int maxwait)
-{
-    char value[PROPERTY_VALUE_MAX] = {'\0'};
-    int maxnaps = (maxwait * 1000) / NAP_TIME;
-
-    if (maxnaps < 1) {
-        maxnaps = 1;
-    }
-
-    while (maxnaps-- >= 0) {
-        if (property_get(name, value, NULL)) {
-            if (desired_value == NULL ||
-                    strcmp(value, desired_value) == 0) {
-                return 0;
-            }
-        }
-        if (maxnaps >= 0) {
-            usleep(NAP_TIME * 1000);
-        }
-    }
-    return -1; /* failure */
-}
-
-static int fill_ip_info(const char *interface,
-                     char *ipaddr,
-                     char *gateway,
-                     uint32_t *prefixLength,
-                     char *dns[],
-                     char *server,
-                     uint32_t *lease,
-                     char *vendorInfo,
-                     char *domain,
-                     char *mtu)
-{
-    char prop_name[PROPERTY_KEY_MAX];
-    char prop_value[PROPERTY_VALUE_MAX];
-    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-    int x;
-
-    get_p2p_interface_replacement(interface, p2p_interface);
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    property_get(prop_name, ipaddr, NULL);
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    property_get(prop_name, gateway, NULL);
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    property_get(prop_name, server, NULL);
-
-    //TODO: Handle IPv6 when we change system property usage
-    if (gateway[0] == '\0' || strncmp(gateway, "0.0.0.0", 7) == 0) {
-        //DHCP server is our best bet as gateway
-        strncpy(gateway, server, PROPERTY_VALUE_MAX);
-    }
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    if (property_get(prop_name, prop_value, NULL)) {
-        int p;
-        // this conversion is v4 only, but this dhcp client is v4 only anyway
-        in_addr_t mask = ntohl(inet_addr(prop_value));
-        // Check netmask is a valid IP address.  ntohl gives NONE response (all 1's) for
-        // non 255.255.255.255 inputs.  if we get that value check if it is legit..
-        if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
-            snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
-            return -1;
-        }
-        for (p = 0; p < 32; p++) {
-            if (mask == 0) break;
-            // check for non-contiguous netmask, e.g., 255.254.255.0
-            if ((mask & 0x80000000) == 0) {
-                snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
-                return -1;
-            }
-            mask = mask << 1;
-        }
-        *prefixLength = p;
-    }
-
-    for (x=0; dns[x] != NULL; x++) {
-        snprintf(prop_name, sizeof(prop_name), "%s.%s.dns%d", DHCP_PROP_NAME_PREFIX, p2p_interface, x+1);
-        property_get(prop_name, dns[x], NULL);
-    }
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    if (property_get(prop_name, prop_value, NULL)) {
-        *lease = atol(prop_value);
-    }
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.vendorInfo", DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-    property_get(prop_name, vendorInfo, NULL);
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.domain", DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-    property_get(prop_name, domain, NULL);
-
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.mtu", DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-    property_get(prop_name, mtu, NULL);
-
-    return 0;
-}
-
-/*
- * Get any available DHCP results.
- */
-int dhcp_get_results(const char *interface,
-                     char *ipaddr,
-                     char *gateway,
-                     uint32_t *prefixLength,
-                     char *dns[],
-                     char *server,
-                     uint32_t *lease,
-                     char *vendorInfo,
-                     char *domain,
-                     char *mtu)
-{
-    char result_prop_name[PROPERTY_KEY_MAX];
-    char prop_value[PROPERTY_VALUE_MAX];
-
-    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-    get_p2p_interface_replacement(interface, p2p_interface);
-    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
-            DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-
-    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu) == -1) {
-            return -1;
-        }
-        return 0;
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
-        return -1;
-    }
-}
-
-/*
- * Start the dhcp client daemon, and wait for it to finish
- * configuring the interface.
- *
- * The device init.rc file needs a corresponding entry for this work.
- *
- * Example:
- * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
- */
-int dhcp_start(const char *interface)
-{
-    char result_prop_name[PROPERTY_KEY_MAX];
-    char daemon_prop_name[PROPERTY_KEY_MAX];
-    char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
-    char daemon_cmd[PROPERTY_VALUE_MAX * 2 + sizeof(DHCP_CONFIG_PATH)];
-    const char *ctrl_prop = "ctl.start";
-    const char *desired_status = "running";
-    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-
-    get_p2p_interface_replacement(interface, p2p_interface);
-
-    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
-            DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-
-    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
-            DAEMON_PROP_NAME,
-            p2p_interface);
-
-    /* Erase any previous setting of the dhcp result property */
-    property_set(result_prop_name, "");
-
-    /* Start the daemon and wait until it's ready */
-    if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
-                 p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
-    else
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
-                 p2p_interface, DHCP_CONFIG_PATH, interface);
-    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
-    property_set(ctrl_prop, daemon_cmd);
-    if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
-        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
-        return -1;
-    }
-
-    /* Wait for the daemon to return a result */
-    if (wait_for_property(result_prop_name, NULL, 30) < 0) {
-        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
- * Stop the DHCP client daemon.
- */
-int dhcp_stop(const char *interface)
-{
-    char result_prop_name[PROPERTY_KEY_MAX];
-    char daemon_prop_name[PROPERTY_KEY_MAX];
-    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
-    const char *ctrl_prop = "ctl.stop";
-    const char *desired_status = "stopped";
-
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-
-    get_p2p_interface_replacement(interface, p2p_interface);
-
-    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
-            DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-
-    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
-            DAEMON_PROP_NAME,
-            p2p_interface);
-
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
-
-    /* Stop the daemon and wait until it's reported to be stopped */
-    property_set(ctrl_prop, daemon_cmd);
-    if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
-        return -1;
-    }
-    property_set(result_prop_name, "failed");
-    return 0;
-}
-
-/**
- * Release the current DHCP client lease.
- */
-int dhcp_release_lease(const char *interface)
-{
-    char daemon_prop_name[PROPERTY_KEY_MAX];
-    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
-    const char *ctrl_prop = "ctl.stop";
-    const char *desired_status = "stopped";
-
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-
-    get_p2p_interface_replacement(interface, p2p_interface);
-
-    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
-            DAEMON_PROP_NAME,
-            p2p_interface);
-
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
-
-    /* Stop the daemon and wait until it's reported to be stopped */
-    property_set(ctrl_prop, daemon_cmd);
-    if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-char *dhcp_get_errmsg() {
-    return errmsg;
-}
-
-/**
- * The device init.rc file needs a corresponding entry.
- *
- * Example:
- * service iprenew_<interface> /system/bin/dhcpcd -n
- *
- */
-int dhcp_start_renew(const char *interface)
-{
-    char result_prop_name[PROPERTY_KEY_MAX];
-    char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
-    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
-    const char *ctrl_prop = "ctl.start";
-
-    char p2p_interface[MAX_INTERFACE_LENGTH];
-
-    get_p2p_interface_replacement(interface, p2p_interface);
-
-    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
-            DHCP_PROP_NAME_PREFIX,
-            p2p_interface);
-
-    /* Erase any previous setting of the dhcp result property */
-    property_set(result_prop_name, "");
-
-    /* Start the renew daemon and wait until it's ready */
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW,
-            p2p_interface, interface);
-    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
-    property_set(ctrl_prop, daemon_cmd);
-
-    /* Wait for the daemon to return a result */
-    if (wait_for_property(result_prop_name, NULL, 30) < 0) {
-        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
-        return -1;
-    }
-
-    return 0;
-}
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
index 352ac5e..a2d3869 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <err.h>
 #include <errno.h>
 #include <error.h>
 #include <stdbool.h>
@@ -29,12 +30,14 @@
 
   char* interface = argv[1];
   if (ifc_init()) {
-    error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+    err(errno, "dhcptool %s: ifc_init failed", interface);
+    ifc_close();
+    return EXIT_FAILURE;
   }
 
   int rc = do_dhcp(interface);
   if (rc) {
-    error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+    err(errno, "dhcptool %s: do_dhcp failed", interface);
   }
 
   ifc_close();
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index e0a9f7f..85ff070 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <pthread.h>
 
 #include <sys/socket.h>
 #include <sys/select.h>
@@ -57,6 +58,8 @@
 
 static int ifc_ctl_sock = -1;
 static int ifc_ctl_sock6 = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t ifc_sock6_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 void printerr(char *fmt, ...);
 
 #define DBG 0
@@ -122,6 +125,8 @@
 int ifc_init(void)
 {
     int ret;
+
+    pthread_mutex_lock(&ifc_sock_mutex);
     if (ifc_ctl_sock == -1) {
         ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock < 0) {
@@ -136,6 +141,7 @@
 
 int ifc_init6(void)
 {
+    pthread_mutex_lock(&ifc_sock6_mutex);
     if (ifc_ctl_sock6 == -1) {
         ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock6 < 0) {
@@ -152,6 +158,7 @@
         (void)close(ifc_ctl_sock);
         ifc_ctl_sock = -1;
     }
+    pthread_mutex_unlock(&ifc_sock_mutex);
 }
 
 void ifc_close6(void)
@@ -160,6 +167,7 @@
         (void)close(ifc_ctl_sock6);
         ifc_ctl_sock6 = -1;
     }
+    pthread_mutex_unlock(&ifc_sock6_mutex);
 }
 
 static void ifc_init_ifr(const char *name, struct ifreq *ifr)
@@ -541,6 +549,7 @@
     ifc_init();
 
     if (ifc_ctl_sock < 0) {
+        ifc_close();
         return -errno;
     }
 
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index ee6ba58..1885fa5 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -7,14 +7,4 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Wall -Werror
-LOCAL_REQUIRED_MODULE := processgroup_cleanup
 include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := cleanup.cpp
-LOCAL_MODULE := processgroup_cleanup
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_STATIC_LIBRARIES := libc libcutils
-include $(BUILD_EXECUTABLE)
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
deleted file mode 100644
index cca8dc4..0000000
--- a/libprocessgroup/cleanup.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  Copyright 2014 Google, Inc
- *
- *  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 <string.h>
-#include <unistd.h>
-#include <sys/syslimits.h>
-
-#include "processgroup_priv.h"
-
-int main(int argc, char **argv)
-{
-    char buf[PATH_MAX];
-    if (argc != 2)
-        return -1;
-
-    memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
-    strlcat(buf, argv[1], sizeof(buf));
-    return rmdir(buf);
-}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 00a0357..cfc9ae2 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <mutex>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -36,7 +37,30 @@
 #include <utils/SystemClock.h>
 
 #include <processgroup/processgroup.h>
-#include "processgroup_priv.h"
+
+// Uncomment line below use memory cgroups for keeping track of (forked) PIDs
+// #define USE_MEMCG 1
+
+#define MEM_CGROUP_PATH "/dev/memcg/apps"
+#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
+#define ACCT_CGROUP_PATH "/acct"
+
+#define PROCESSGROUP_UID_PREFIX "uid_"
+#define PROCESSGROUP_PID_PREFIX "pid_"
+#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+#define PROCESSGROUP_MAX_UID_LEN 11
+#define PROCESSGROUP_MAX_PID_LEN 11
+#define PROCESSGROUP_MAX_PATH_LEN \
+        ((sizeof(MEM_CGROUP_PATH) > sizeof(ACCT_CGROUP_PATH) ? \
+          sizeof(MEM_CGROUP_PATH) : sizeof(ACCT_CGROUP_PATH)) + \
+         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_UID_LEN + \
+         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_PID_LEN + \
+         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
+         1)
+
+std::once_flag init_path_flag;
 
 struct ctx {
     bool initialized;
@@ -46,10 +70,25 @@
     size_t buf_len;
 };
 
+static const char* getCgroupRootPath() {
+#ifdef USE_MEMCG
+    static const char* cgroup_root_path = NULL;
+    std::call_once(init_path_flag, [&]() {
+            // Check if mem cgroup is mounted, only then check for write-access to avoid
+            // SELinux denials
+            cgroup_root_path = access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ?
+                    ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
+            });
+    return cgroup_root_path;
+#else
+    return ACCT_CGROUP_PATH;
+#endif
+}
+
 static int convertUidToPath(char *path, size_t size, uid_t uid)
 {
     return snprintf(path, size, "%s/%s%d",
-            PROCESSGROUP_CGROUP_PATH,
+            getCgroupRootPath(),
             PROCESSGROUP_UID_PREFIX,
             uid);
 }
@@ -57,7 +96,7 @@
 static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
 {
     return snprintf(path, size, "%s/%s%d/%s%d",
-            PROCESSGROUP_CGROUP_PATH,
+            getCgroupRootPath(),
             PROCESSGROUP_UID_PREFIX,
             uid,
             PROCESSGROUP_PID_PREFIX,
@@ -188,9 +227,10 @@
 void removeAllProcessGroups()
 {
     SLOGV("removeAllProcessGroups()");
-    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(PROCESSGROUP_CGROUP_PATH), closedir);
+    const char *cgroup_root_path = getCgroupRootPath();
+    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
     if (root == NULL) {
-        SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
+        SLOGE("failed to open %s: %s", cgroup_root_path, strerror(errno));
     } else {
         struct dirent cur;
         struct dirent *dir;
@@ -204,7 +244,7 @@
                 continue;
             }
 
-            snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
+            snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
             removeUidProcessGroups(path);
             SLOGV("removing %s\n", path);
             rmdir(path);
diff --git a/libprocessgroup/processgroup_priv.h b/libprocessgroup/processgroup_priv.h
deleted file mode 100644
index 1895bf9..0000000
--- a/libprocessgroup/processgroup_priv.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  Copyright 2014 Google, Inc
- *
- *  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 _PROCESSGROUP_PRIV_H_
-#define _PROCESSGROUP_PRIV_H_
-
-#define PROCESSGROUP_CGROUP_PATH "/acct"
-#define PROCESSGROUP_UID_PREFIX "uid_"
-#define PROCESSGROUP_PID_PREFIX "pid_"
-#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
-#define PROCESSGROUP_MAX_UID_LEN 11
-#define PROCESSGROUP_MAX_PID_LEN 11
-#define PROCESSGROUP_MAX_PATH_LEN \
-        (sizeof(PROCESSGROUP_CGROUP_PATH) + \
-         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
-         PROCESSGROUP_MAX_UID_LEN + \
-         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
-         PROCESSGROUP_MAX_PID_LEN + \
-         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
-         1)
-
-#endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 23dcd62..739fad7 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -159,7 +159,7 @@
     struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
     struct ifa_cacheinfo *cacheinfo = NULL;
     char addrstr[INET6_ADDRSTRLEN] = "";
-    char ifname[IFNAMSIZ];
+    char ifname[IFNAMSIZ] = "";
 
     if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
         return false;
@@ -207,8 +207,7 @@
 
             // Find the interface name.
             if (!if_indextoname(ifaddr->ifa_index, ifname)) {
-                SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
-                return false;
+                SLOGD("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
             }
 
         } else if (rta->rta_type == IFA_CACHEINFO) {
@@ -235,8 +234,7 @@
     mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
                                       Action::kAddressRemoved;
     mSubsystem = strdup("net");
-    asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
-             ifaddr->ifa_prefixlen);
+    asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
     asprintf(&mParams[1], "INTERFACE=%s", ifname);
     asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
     asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index b8e3215..299fdc4 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -617,6 +617,11 @@
     return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
 }
 
+int usb_device_reset(struct usb_device *device)
+{
+    return ioctl(device->fd, USBDEVFS_RESET);
+}
+
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc)
 {
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 6f88a6d..84bac32 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -106,19 +106,16 @@
 LOCAL_SANITIZE := integer
 include $(BUILD_SHARED_LIBRARY)
 
-# Include subdirectory makefiles
-# ============================================================
-
 include $(CLEAR_VARS)
 LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_STATIC_LIBRARIES := libutils
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := SharedBufferTest.cpp
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_STATIC_LIBRARIES := libutils
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := SharedBufferTest.cpp
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index c7dd1ab..34d75ee 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
diff --git a/libutils/SharedBufferTest.cpp b/libutils/SharedBufferTest.cpp
index a0484ff..33a4e0c 100644
--- a/libutils/SharedBufferTest.cpp
+++ b/libutils/SharedBufferTest.cpp
@@ -31,10 +31,10 @@
   // Check that null is returned, as we are asking for the whole address space.
   android::SharedBuffer* buf =
       android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
-  ASSERT_TRUE(NULL == buf);
+  ASSERT_EQ(nullptr, buf);
 
   buf = android::SharedBuffer::alloc(0);
-  ASSERT_FALSE(NULL == buf);
+  ASSERT_NE(nullptr, buf);
   ASSERT_EQ(0U, buf->size());
   buf->release();
 }
@@ -49,7 +49,7 @@
   // Make sure we don't die here.
   // Check that null is returned, as we are asking for the whole address space.
   buf = buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
-  ASSERT_TRUE(NULL == buf);
+  ASSERT_EQ(nullptr, buf);
 
   buf = android::SharedBuffer::alloc(10);
   buf = buf->editResize(0);
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 6dda6b5..def739f 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -668,6 +668,8 @@
 
 status_t Thread::run(const char* name, int32_t priority, size_t stack)
 {
+    LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to Thread::run");
+
     Mutex::Autolock _l(mLock);
 
     if (mRunning) {
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index 00077e6..17319e0 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/tests/Looper_test.cpp
@@ -138,7 +138,7 @@
 
 TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
     sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
-    delayedWake->run();
+    delayedWake->run("LooperTest");
 
     StopWatch stopWatch("pollOnce");
     int result = mLooper->pollOnce(1000);
@@ -251,7 +251,7 @@
     sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
 
     handler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
-    delayedWriteSignal->run();
+    delayedWriteSignal->run("LooperTest");
 
     StopWatch stopWatch("pollOnce");
     int result = mLooper->pollOnce(1000);
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index c42c68d..01e64f6 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -72,4 +72,9 @@
     EXPECT_STREQ(src3, " Verify me.");
 }
 
+TEST_F(String8Test, SetToSizeMaxReturnsNoMemory) {
+    const char *in = "some string";
+    EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
+}
+
 }
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a2d6fcc..1f27500 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -495,14 +495,20 @@
 }
 
 // Attempts to read |len| bytes into |buf| at offset |off|.
-// Callers should not rely on the |fd| offset being incremented
-// as a side effect of this call.
+// On non-Windows platforms, callers are guaranteed that the |fd|
+// offset is unchanged and there is no side effect to this call.
+//
+// On Windows platforms this is not thread-safe.
 static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
+#if !defined(_WIN32)
+  return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
+#else
   if (lseek64(fd, off, SEEK_SET) != off) {
     ALOGW("Zip: failed seek to offset %" PRId64, off);
     return false;
   }
   return android::base::ReadFully(fd, buf, len);
+#endif
 }
 
 static int32_t FindEntry(const ZipArchive* archive, const int ent,
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index aa3db8a..afc81ed 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -39,7 +39,7 @@
 #endif
 
 #define MEMCG_SYSFS_PATH "/dev/memcg/"
-#define MEMPRESSURE_WATCH_LEVEL "medium"
+#define MEMPRESSURE_WATCH_LEVEL "low"
 #define ZONEINFO_PATH "/proc/zoneinfo"
 #define LINE_MAX 128
 
@@ -77,12 +77,7 @@
 static int epollfd;
 static int maxevents;
 
-#define OOM_DISABLE (-17)
-/* inclusive */
-#define OOM_ADJUST_MIN (-16)
-#define OOM_ADJUST_MAX 15
-
-/* kernel OOM score values */
+/* OOM score values used by both kernel and framework */
 #define OOM_SCORE_ADJ_MIN       (-1000)
 #define OOM_SCORE_ADJ_MAX       1000
 
@@ -114,8 +109,8 @@
 static struct proc *pidhash[PIDHASH_SZ];
 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
-static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
+#define ADJTOSLOT(adj) (adj + -OOM_SCORE_ADJ_MIN)
+static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
 
 /*
  * Wait 1-2 seconds for the death report of a killed process prior to
@@ -148,14 +143,6 @@
     return ret;
 }
 
-static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
-{
-    if (oom_adj == OOM_ADJUST_MAX)
-        return OOM_SCORE_ADJ_MAX;
-    else
-        return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
-}
-
 static struct proc *pid_lookup(int pid) {
     struct proc *procp;
 
@@ -254,13 +241,13 @@
     char path[80];
     char val[20];
 
-    if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
+    if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
         ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
         return;
     }
 
     snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
-    snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
+    snprintf(val, sizeof(val), "%d", oomadj);
     writefilestring(path, val);
 
     if (use_inkernel_interface)
@@ -608,7 +595,7 @@
 static int find_and_kill_process(int other_free, int other_file, bool first)
 {
     int i;
-    int min_score_adj = OOM_ADJUST_MAX + 1;
+    int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
     int minfree = 0;
     int killed_size = 0;
 
@@ -620,10 +607,10 @@
         }
     }
 
-    if (min_score_adj == OOM_ADJUST_MAX + 1)
+    if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
         return 0;
 
-    for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
+    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
         struct proc *procp;
 
 retry:
@@ -784,7 +771,7 @@
             ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
     }
 
-    for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
+    for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
         procadjslot_list[i].next = &procadjslot_list[i];
         procadjslot_list[i].prev = &procadjslot_list[i];
     }
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 8db2ba8..e6c94ff 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,5 +1,6 @@
 libandroid.so
 libc.so
+libcamera2ndk.so
 libdl.so
 libEGL.so
 libGLESv1_CM.so
@@ -15,5 +16,6 @@
 libOpenSLES.so
 libRS.so
 libstdc++.so
+libvulkan.so
 libwebviewchromium_plat_support.so
 libz.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 673e115..292730a 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,5 +1,6 @@
 libandroid.so
 libc.so
+libcamera2ndk.so
 libdl.so
 libEGL.so
 libGLESv1_CM.so
@@ -15,4 +16,5 @@
 libOpenSLES.so
 libRS.so
 libstdc++.so
+libvulkan.so
 libz.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index aa32343..abbb3f1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -46,35 +46,26 @@
     mount cgroup none /acct cpuacct
     mkdir /acct/uid
 
-    # Create cgroup mount point for memory
-    mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
-    mkdir /sys/fs/cgroup/memory 0750 root system
-    mount cgroup none /sys/fs/cgroup/memory memory
-    write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
-    chown root system /sys/fs/cgroup/memory/tasks
-    chmod 0660 /sys/fs/cgroup/memory/tasks
-    mkdir /sys/fs/cgroup/memory/sw 0750 root system
-    write /sys/fs/cgroup/memory/sw/memory.swappiness 100
-    write /sys/fs/cgroup/memory/sw/memory.move_charge_at_immigrate 1
-    chown root system /sys/fs/cgroup/memory/sw/tasks
-    chmod 0660 /sys/fs/cgroup/memory/sw/tasks
-
     # Create energy-aware scheduler tuning nodes
-    mkdir /sys/fs/cgroup/stune
-    mount cgroup none /sys/fs/cgroup/stune schedtune
-    mkdir /sys/fs/cgroup/stune/foreground
-    chown system system /sys/fs/cgroup/stune
-    chown system system /sys/fs/cgroup/stune/foreground
-    chown system system /sys/fs/cgroup/stune/tasks
-    chown system system /sys/fs/cgroup/stune/foreground/tasks
-    chmod 0664 /sys/fs/cgroup/stune/tasks
-    chmod 0664 /sys/fs/cgroup/stune/foreground/tasks
+    mkdir /dev/stune
+    mount cgroup none /dev/stune schedtune
+    mkdir /dev/stune/foreground
+    chown system system /dev/stune
+    chown system system /dev/stune/foreground
+    chown system system /dev/stune/tasks
+    chown system system /dev/stune/foreground/tasks
+    chmod 0664 /dev/stune/tasks
+    chmod 0664 /dev/stune/foreground/tasks
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
     mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
     restorecon_recursive /mnt
 
+    mount configfs none /config
+    chmod 0775 /config/sdcardfs
+    chown system package_info /config/sdcardfs
+
     mkdir /mnt/secure 0700 root root
     mkdir /mnt/secure/asec 0700 root root
     mkdir /mnt/asec 0755 root system
@@ -83,6 +74,7 @@
     mkdir /mnt/user 0755 root root
     mkdir /mnt/user/0 0755 root root
     mkdir /mnt/expand 0771 system system
+    mkdir /mnt/appfuse 0711 root root
 
     # Storage views to support runtime permissions
     mkdir /mnt/runtime 0700 root root
@@ -97,9 +89,11 @@
     symlink /storage/self/primary /sdcard
     symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
 
-    # memory control cgroup
+    # root memory control cgroup, used by lmkd
     mkdir /dev/memcg 0700 root system
     mount cgroup none /dev/memcg memory
+    # app mem cgroups, used by activity manager, lmkd and zygote
+    mkdir /dev/memcg/apps/ 0755 system system
 
     write /proc/sys/kernel/panic_on_oops 1
     write /proc/sys/kernel/hung_task_timeout_secs 0
@@ -175,21 +169,32 @@
     write /dev/cpuset/system-background/cpus 0
     write /dev/cpuset/system-background/mems 0
 
+    mkdir /dev/cpuset/top-app
+    write /dev/cpuset/top-app/cpus 0
+    write /dev/cpuset/top-app/mems 0
+
     # change permissions for all cpusets we'll touch at runtime
     chown system system /dev/cpuset
     chown system system /dev/cpuset/foreground
     chown system system /dev/cpuset/foreground/boost
     chown system system /dev/cpuset/background
     chown system system /dev/cpuset/system-background
+    chown system system /dev/cpuset/top-app
     chown system system /dev/cpuset/tasks
     chown system system /dev/cpuset/foreground/tasks
     chown system system /dev/cpuset/foreground/boost/tasks
     chown system system /dev/cpuset/background/tasks
     chown system system /dev/cpuset/system-background/tasks
+    chown system system /dev/cpuset/top-app/tasks
+
+    # set system-background to 0775 so SurfaceFlinger can touch it
+    chmod 0775 /dev/cpuset/system-background
+
     chmod 0664 /dev/cpuset/foreground/tasks
     chmod 0664 /dev/cpuset/foreground/boost/tasks
     chmod 0664 /dev/cpuset/background/tasks
     chmod 0664 /dev/cpuset/system-background/tasks
+    chmod 0664 /dev/cpuset/top-app/tasks
     chmod 0664 /dev/cpuset/tasks
 
 
@@ -285,6 +290,10 @@
     # permissions if created by the recovery system.
     mkdir /cache/recovery 0770 system cache
 
+    # Backup/restore mechanism uses the cache partition
+    mkdir /cache/backup_stage 0700 system system
+    mkdir /cache/backup 0700 system system
+
     #change permissions on vmallocinfo so we can grab it from bugreports
     chown root log /proc/vmallocinfo
     chmod 0440 /proc/vmallocinfo
@@ -321,8 +330,6 @@
     start vold
     installkey /data
 
-    # Emulated internal storage area
-    mkdir /data/media 0770 media_rw media_rw
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell
@@ -359,16 +366,23 @@
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
+    mkdir /data/misc/audioserver 0700 audioserver audioserver
+    mkdir /data/misc/cameraserver 0700 cameraserver cameraserver
     mkdir /data/misc/vold 0700 root root
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/trace 0700 root root
+    # profile file layout
+    mkdir /data/misc/profiles 0771 system system
+    mkdir /data/misc/profiles/cur 0771 system system
+    mkdir /data/misc/profiles/ref 0771 system system
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell
     mkdir /data/data 0771 system system
     mkdir /data/app-private 0771 system system
+    mkdir /data/app-ephemeral 0771 system system
     mkdir /data/app-asec 0700 root root
     mkdir /data/app-lib 0771 system system
     mkdir /data/app 0771 system system
@@ -377,6 +391,8 @@
 
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 root root
+    # create the A/B OTA directory, so as to enforce our permissions
+    mkdir /data/ota 0771 root root
 
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
@@ -397,18 +413,31 @@
     mkdir /data/anr 0775 system system
 
     # symlink to bugreport storage location
-    symlink /data/data/com.android.shell/files/bugreports /data/bugreports
+    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
-    mkdir /data/media 0770 media_rw media_rw
     mkdir /data/ss 0700 system system
+
     mkdir /data/system 0775 system system
     mkdir /data/system/heapdump 0700 system system
-    mkdir /data/user 0711 system system
 
-    setusercryptopolicies /data/user
+    mkdir /data/system_de 0770 system system
+    mkdir /data/system_ce 0770 system system
+
+    mkdir /data/misc_de 01771 system misc
+    mkdir /data/misc_ce 01771 system misc
+
+    mkdir /data/user 0711 system system
+    mkdir /data/user_de 0711 system system
+    symlink /data/data /data/user/0
+
+    mkdir /data/media 0770 media_rw media_rw
+    mkdir /data/media/obb 0770 media_rw media_rw
+
+    init_user0
 
     # Set SELinux security contexts on upgrade or policy update.
     restorecon_recursive /data
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 0ca38b9..22b9d6b 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -3,6 +3,8 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
+    onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1646c0f..555eda4 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -3,6 +3,8 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
+    onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
@@ -11,4 +13,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index b477c8e..297468c 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -3,6 +3,8 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
+    onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 633a981..46f9f02 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -3,6 +3,8 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
+    onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
@@ -11,4 +13,4 @@
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/run-as/package.c b/run-as/package.c
index aea89e5..86824c2 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -182,6 +182,10 @@
     if (ret < 0)
         return -1;
 
+    /* /data/user/0 is a known safe symlink */
+    if (strcmp("/data/user/0", path) == 0)
+        return 0;
+
     /* must be a real directory, not a symlink */
     if (!S_ISDIR(st.st_mode))
         goto BAD;
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index f862561..d8fda67 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1214,13 +1214,7 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
-
-#ifdef FUSE_STACKED_IO
-    out.lower_fd = h->fd;
-#else
     out.padding = 0;
-#endif
-
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1384,13 +1378,7 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
-
-#ifdef FUSE_STACKED_IO
-    out.lower_fd = -1;
-#else
     out.padding = 0;
-#endif
-
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1472,11 +1460,6 @@
     out.major = FUSE_KERNEL_VERSION;
     out.max_readahead = req->max_readahead;
     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-
-#ifdef FUSE_STACKED_IO
-    out.flags |= FUSE_STACKED_IO;
-#endif
-
     out.max_background = 32;
     out.congestion_threshold = 32;
     out.max_write = MAX_WRITE;
@@ -1911,6 +1894,105 @@
     exit(1);
 }
 
+static int sdcardfs_setup(const char *source_path, const char *dest_path, uid_t fsuid,
+                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
+    char opts[256];
+
+    snprintf(opts, sizeof(opts),
+            "fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
+            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
+
+    if (mount(source_path, dest_path, "sdcardfs",
+                        MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts) != 0) {
+        ERROR("failed to mount sdcardfs filesystem: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static void run_sdcardfs(const char* source_path, const char* label, uid_t uid,
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+    char dest_path_default[PATH_MAX];
+    char dest_path_read[PATH_MAX];
+    char dest_path_write[PATH_MAX];
+    char obb_path[PATH_MAX];
+    snprintf(dest_path_default, PATH_MAX, "/mnt/runtime/default/%s", label);
+    snprintf(dest_path_read, PATH_MAX, "/mnt/runtime/read/%s", label);
+    snprintf(dest_path_write, PATH_MAX, "/mnt/runtime/write/%s", label);
+
+    umask(0);
+    if (multi_user) {
+        /* Multi-user storage is fully isolated per user, so "other"
+         * 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,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
+    } else {
+        /* Physical storage is readable by all users on device, but
+         * the Android directories are masked off to a single user
+         * 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,
+                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
+                || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
+    }
+
+    /* Drop privs */
+    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
+        ERROR("cannot setgroups: %s\n", strerror(errno));
+        exit(1);
+    }
+    if (setgid(gid) < 0) {
+        ERROR("cannot setgid: %s\n", strerror(errno));
+        exit(1);
+    }
+    if (setuid(uid) < 0) {
+        ERROR("cannot setuid: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    if (multi_user) {
+        snprintf(obb_path, sizeof(obb_path), "%s/obb", source_path);
+        fs_prepare_dir(&obb_path[0], 0775, uid, gid);
+    }
+
+    exit(0);
+}
+
+static bool supports_sdcardfs(void) {
+    FILE *fp;
+    char *buf = NULL;
+    size_t buflen = 0;
+
+    fp = fopen("/proc/filesystems", "r");
+    if (!fp) {
+        ERROR("Could not read /proc/filesystems, error: %s\n", strerror(errno));
+        return false;
+    }
+    while ((getline(&buf, &buflen, fp)) > 0) {
+        if (strstr(buf, "sdcardfs\n")) {
+            free(buf);
+            fclose(fp);
+            return true;
+        }
+    }
+    free(buf);
+    fclose(fp);
+    return false;
+}
+
 int main(int argc, char **argv) {
     const char *source_path = NULL;
     const char *label = NULL;
@@ -1983,6 +2065,10 @@
         sleep(1);
     }
 
-    run(source_path, label, uid, gid, userid, multi_user, full_write);
+    if (supports_sdcardfs()) {
+        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
+    } else {
+        run(source_path, label, uid, gid, userid, multi_user, full_write);
+    }
     return 1;
 }
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
new file mode 100644
index 0000000..13e9a09
--- /dev/null
+++ b/trusty/gatekeeper/Android.mk
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK.  Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := gatekeeper.trusty
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+	module.cpp \
+	trusty_gatekeeper_ipc.c \
+	trusty_gatekeeper.cpp
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+	libgatekeeper \
+	liblog \
+	libcutils \
+	libtrusty
+
+LOCAL_MODULE_TAGS := optional
+
+# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
+LOCAL_POST_INSTALL_CMD = \
+    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/gatekeeper_ipc.h b/trusty/gatekeeper/gatekeeper_ipc.h
new file mode 100644
index 0000000..b05dcd8
--- /dev/null
+++ b/trusty/gatekeeper/gatekeeper_ipc.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
+#define GATEKEEPER_MAX_BUFFER_LENGTH 1024
+
+enum gatekeeper_command {
+	GK_REQ_SHIFT = 1,
+	GK_RESP_BIT  = 1,
+
+	GK_ENROLL       = (0 << GK_REQ_SHIFT),
+	GK_VERIFY       = (1 << GK_REQ_SHIFT),
+};
+
+/**
+ * gatekeeper_message - Serial header for communicating with GK server
+ * @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized
+ *       buffer of the corresponding request object.
+ * @payload: start of the serialized command specific payload
+ */
+struct gatekeeper_message {
+    uint32_t cmd;
+    uint8_t payload[0];
+};
+
diff --git a/trusty/gatekeeper/module.cpp b/trusty/gatekeeper/module.cpp
new file mode 100644
index 0000000..0ee3c2f
--- /dev/null
+++ b/trusty/gatekeeper/module.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 <hardware/hardware.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "trusty_gatekeeper.h"
+
+using gatekeeper::TrustyGateKeeperDevice;
+
+static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
+        hw_device_t **device) {
+
+    if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
+        return -EINVAL;
+    }
+
+    TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
+    if (gatekeeper == NULL) return -ENOMEM;
+    *device = gatekeeper->hw_device();
+
+    return 0;
+}
+
+static struct hw_module_methods_t gatekeeper_module_methods = {
+    .open = trusty_gatekeeper_open,
+};
+
+struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = GATEKEEPER_HARDWARE_MODULE_ID,
+        .name = "Trusty GateKeeper HAL",
+        .author = "The Android Open Source Project",
+        .methods = &gatekeeper_module_methods,
+        .dso = 0,
+        .reserved = {}
+    },
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
new file mode 100644
index 0000000..d24f44f
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <type_traits>
+
+#include "trusty_gatekeeper.h"
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+
+namespace gatekeeper {
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+    static_assert(std::is_standard_layout<TrustyGateKeeperDevice>::value,
+                  "TrustyGateKeeperDevice must be standard layout");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0,
+                  "device_ must be the first member of TrustyGateKeeperDevice");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0,
+                  "common must be the first member of gatekeeper_device");
+#else
+    assert(reinterpret_cast<gatekeeper_device_t *>(this) == &device_);
+    assert(reinterpret_cast<hw_device_t *>(this) == &(device_.common));
+#endif
+
+    memset(&device_, 0, sizeof(device_));
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = const_cast<hw_module_t *>(module);
+    device_.common.close = close_device;
+
+    device_.enroll = enroll;
+    device_.verify = verify;
+    device_.delete_user = nullptr;
+    device_.delete_all_users = nullptr;
+
+    int rc = trusty_gatekeeper_connect();
+    if (rc < 0) {
+        ALOGE("Error initializing trusty session: %d", rc);
+    }
+
+    error_ = rc;
+
+}
+
+hw_device_t* TrustyGateKeeperDevice::hw_device() {
+    return &device_.common;
+}
+
+int TrustyGateKeeperDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<TrustyGateKeeperDevice *>(dev);
+    return 0;
+}
+
+TrustyGateKeeperDevice::~TrustyGateKeeperDevice() {
+    trusty_gatekeeper_disconnect();
+}
+
+int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle,
+        uint32_t current_password_handle_length, const uint8_t *current_password,
+        uint32_t current_password_length, const uint8_t *desired_password,
+        uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+        uint32_t *enrolled_password_handle_length) {
+
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+
+
+    return 0;
+}
+
+int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge,
+        const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+        const uint8_t *provided_password, uint32_t provided_password_length,
+        uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    if (request_reenroll != NULL) {
+        *request_reenroll = response.request_reenroll;
+    }
+
+    return 0;
+}
+
+gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
+        GateKeeperMessage *response) {
+    uint32_t request_size = request.GetSerializedSize();
+    if (request_size > SEND_BUF_SIZE)
+        return ERROR_INVALID;
+    uint8_t send_buf[SEND_BUF_SIZE];
+    request.Serialize(send_buf, send_buf + request_size);
+
+    // Send it
+    uint8_t recv_buf[RECV_BUF_SIZE];
+    uint32_t response_size = RECV_BUF_SIZE;
+    int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size);
+    if (rc < 0) {
+        ALOGE("error (%d) calling gatekeeper TA", rc);
+        return ERROR_INVALID;
+    }
+
+    const gatekeeper_message *msg = reinterpret_cast<gatekeeper_message *>(recv_buf);
+    const uint8_t *payload = msg->payload;
+
+    return response->Deserialize(payload, payload + response_size);
+}
+
+static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) {
+    return reinterpret_cast<TrustyGateKeeperDevice *>(const_cast<gatekeeper_device *>(dev));
+}
+
+/* static */
+int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (dev == NULL ||
+            enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length,
+            current_password, current_password_length, desired_password, desired_password_length,
+            enrolled_password_handle, enrolled_password_handle_length);
+
+}
+
+/* static */
+int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+        bool *request_reenroll) {
+
+    if (dev == NULL || enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle,
+            enrolled_password_handle_length, provided_password, provided_password_length,
+            auth_token, auth_token_length, request_reenroll);
+}
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
new file mode 100644
index 0000000..82108dc
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef TRUSTY_GATEKEEPER_H
+#define TRUSTY_GATEKEEPER_H
+
+#include <hardware/gatekeeper.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+#include "gatekeeper_ipc.h"
+
+namespace gatekeeper {
+
+class TrustyGateKeeperDevice {
+    public:
+
+    TrustyGateKeeperDevice(const hw_module_t* module);
+    ~TrustyGateKeeperDevice();
+
+    hw_device_t* hw_device();
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password will not be allocated.
+     */
+    int Enroll(uint32_t uid, const uint8_t *current_password_handle,
+            uint32_t current_password_handle_length, const uint8_t *current_password,
+            uint32_t current_password_length, const uint8_t *desired_password,
+            uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+            uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches expected_password after enrolling
+     * with the authentication factor private key.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to verification_token,
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle,
+            uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+            uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+            bool *request_reenroll);
+
+    private:
+
+    gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
+                           GateKeeperMessage* response);
+
+    gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
+        return Send(GK_ENROLL, request, response);
+    }
+
+    gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
+        return Send(GK_VERIFY, request, response);
+    }
+
+    // Static methods interfacing the HAL API with the TrustyGateKeeper device
+
+    /**
+     * Enrolls desired_password, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * If there was already a password enrolled, it should be provided in
+     * current_password_handle, along with the current password in current_password
+     * that should validate against current_password_handle.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+
+    static int close_device(hw_device_t* dev);
+
+    gatekeeper_device device_;
+    int error_;
+
+};
+}
+
+#endif
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
new file mode 100644
index 0000000..a1c319e
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+#include <trusty/tipc.h>
+
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_gatekeeper_connect() {
+    int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
+    if (rc < 0) {
+        return rc;
+    }
+
+    handle_ = rc;
+    return 0;
+}
+
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size) {
+    if (handle_ == 0) {
+        ALOGE("not connected\n");
+        return -EINVAL;
+    }
+
+    size_t msg_size = in_size + sizeof(struct gatekeeper_message);
+    struct gatekeeper_message *msg = malloc(msg_size);
+    msg->cmd = cmd;
+    memcpy(msg->payload, in, in_size);
+
+    ssize_t rc = write(handle_, msg, msg_size);
+    free(msg);
+
+    if (rc < 0) {
+        ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+                GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    rc = read(handle_, out, *out_size);
+    if (rc < 0) {
+        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+                cmd, GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    if ((size_t) rc < sizeof(struct gatekeeper_message)) {
+        ALOGE("invalid response size (%d)\n", (int) rc);
+        return -EINVAL;
+    }
+
+    msg = (struct gatekeeper_message *) out;
+
+    if ((cmd | GK_RESP_BIT) != msg->cmd) {
+        ALOGE("invalid command (%d)\n", msg->cmd);
+        return -EINVAL;
+    }
+
+    *out_size = ((size_t) rc) - sizeof(struct gatekeeper_message);
+    return rc;
+}
+
+void trusty_gatekeeper_disconnect() {
+    if (handle_ != 0) {
+        tipc_close(handle_);
+    }
+}
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.h b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
new file mode 100644
index 0000000..f8de7f8
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+__BEGIN_DECLS
+
+int trusty_gatekeeper_connect();
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size);
+void trusty_gatekeeper_disconnect();
+
+__END_DECLS