Merge "Make RefBase more robust and debuggable"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 725aa91..be390d9 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -354,21 +354,13 @@
     case A_AUTH:
         if (p->msg.arg0 == ADB_AUTH_TOKEN) {
             t->connection_state = kCsUnauthorized;
-            t->key = adb_auth_nextkey(t->key);
-            if (t->key) {
-                send_auth_response(p->data, p->msg.data_length, t);
-            } else {
-                /* No more private keys to try, send the public key */
-                send_auth_publickey(t);
-            }
+            send_auth_response(p->data, p->msg.data_length, t);
         } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
-            if (adb_auth_verify(t->token, sizeof(t->token),
-                                p->data, p->msg.data_length)) {
+            if (adb_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
                 adb_auth_verified(t);
                 t->failed_auth_attempts = 0;
             } else {
-                if (t->failed_auth_attempts++ > 10)
-                    adb_sleep_ms(1000);
+                if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
                 send_auth_request(t);
             }
         } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index 215bbe6..0b07158 100644
--- a/adb/adb_auth.cpp
+++ b/adb/adb_auth.cpp
@@ -16,8 +16,9 @@
 
 #define TRACE_TAG ADB
 
-#include "sysdeps.h"
+#include "adb.h"
 #include "adb_auth.h"
+#include "transport.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -25,53 +26,28 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "adb.h"
-#include "transport.h"
-
 bool auth_required = true;
 
 void send_auth_request(atransport *t)
 {
-    D("Calling send_auth_request");
-    apacket *p;
-    int ret;
+    LOG(INFO) << "Calling send_auth_request...";
 
-    ret = adb_auth_generate_token(t->token, sizeof(t->token));
-    if (ret != sizeof(t->token)) {
-        D("Error generating token ret=%d", ret);
+    if (!adb_auth_generate_token(t->token, sizeof(t->token))) {
+        PLOG(ERROR) << "Error generating token";
         return;
     }
 
-    p = get_apacket();
-    memcpy(p->data, t->token, ret);
+    apacket* p = get_apacket();
+    memcpy(p->data, t->token, sizeof(t->token));
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_TOKEN;
-    p->msg.data_length = ret;
+    p->msg.data_length = sizeof(t->token);
     send_packet(p, t);
 }
 
-void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
-{
-    D("Calling send_auth_response");
-    apacket *p = get_apacket();
-    int ret;
+static void send_auth_publickey(atransport* t) {
+    LOG(INFO) << "Calling send_auth_publickey";
 
-    ret = adb_auth_sign(t->key, token, token_size, p->data);
-    if (!ret) {
-        D("Error signing the token");
-        put_apacket(p);
-        return;
-    }
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-void send_auth_publickey(atransport *t)
-{
-    D("Calling send_auth_publickey");
     std::string key = adb_auth_get_userkey();
     if (key.empty()) {
         D("Failed to get user public key");
@@ -88,7 +64,33 @@
 
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
-    p->msg.data_length = key.size();
+
+    // adbd expects a null-terminated string.
+    p->msg.data_length = key.size() + 1;
+    send_packet(p, t);
+}
+
+void send_auth_response(uint8_t* token, size_t token_size, atransport* t) {
+    std::shared_ptr<RSA> key = t->NextKey();
+    if (key == nullptr) {
+        // No more private keys to try, send the public key.
+        send_auth_publickey(t);
+        return;
+    }
+
+    LOG(INFO) << "Calling send_auth_response";
+    apacket* p = get_apacket();
+
+    int ret = adb_auth_sign(key.get(), token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_SIGNATURE;
+    p->msg.data_length = ret;
     send_packet(p, t);
 }
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 6363bb4..59b80d8 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,6 +19,11 @@
 
 #include "adb.h"
 
+#include <deque>
+#include <memory>
+
+#include <openssl/rsa.h>
+
 extern bool auth_required;
 
 int adb_auth_keygen(const char* filename);
@@ -26,7 +31,6 @@
 
 void send_auth_request(atransport *t);
 void send_auth_response(uint8_t *token, size_t token_size, atransport *t);
-void send_auth_publickey(atransport *t);
 
 /* AUTH packets first argument */
 /* Request */
@@ -37,36 +41,25 @@
 
 #if ADB_HOST
 
-void adb_auth_init(void);
-int adb_auth_sign(void *key, const unsigned char* token, size_t token_size,
-                  unsigned char* sig);
-void *adb_auth_nextkey(void *current);
+void adb_auth_init();
+int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig);
 std::string adb_auth_get_userkey();
+std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
 
-static inline int adb_auth_generate_token(void *token, size_t token_size) {
-    return 0;
-}
-static inline int adb_auth_verify(void *token, size_t token_size,
-                                  void *sig, int siglen) {
-    return 0;
-}
-static inline void adb_auth_confirm_key(unsigned char *data, size_t len,
-                                        atransport *t) {}
+static inline bool adb_auth_generate_token(void*, size_t) { abort(); }
+static inline bool adb_auth_verify(void*, size_t, void*, int) { abort(); }
+static inline void adb_auth_confirm_key(unsigned char*, size_t, atransport*) { abort(); }
 
 #else // !ADB_HOST
 
-static inline int adb_auth_sign(void* key, const unsigned char* token,
-                                size_t token_size, unsigned char* sig) {
-    return 0;
-}
-static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline std::string adb_auth_get_userkey() { return ""; }
+static inline int adb_auth_sign(void*, const unsigned char*, size_t, unsigned char*) { abort(); }
+static inline std::string adb_auth_get_userkey() { abort(); }
+static inline std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { abort(); }
 
 void adbd_auth_init(void);
 void adbd_cloexec_auth_socket();
-int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(uint8_t* token, size_t token_size,
-                    uint8_t* sig, int siglen);
+bool adb_auth_generate_token(void* token, size_t token_size);
+bool adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int sig_len);
 void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
 
 #endif // ADB_HOST
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 415ab8e..9d8dfc0 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -16,37 +16,25 @@
 
 #define TRACE_TAG AUTH
 
-#include "sysdeps.h"
+#include "adb.h"
 #include "adb_auth.h"
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
 
 #include <resolv.h>
 #include <stdio.h>
 #include <string.h>
 
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <openssl/obj_mac.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-#include <crypto_utils/android_pubkey.h>
-
-#include "cutils/list.h"
-#include "cutils/sockets.h"
-
-#include "adb.h"
-#include "fdevent.h"
-#include "transport.h"
-
-struct adb_public_key {
-    struct listnode node;
-    RSA* key;
-};
-
-static const char *key_paths[] = {
-    "/adb_keys",
-    "/data/misc/adb/adb_keys",
-    NULL
-};
-
 static fdevent listener_fde;
 static fdevent framework_fde;
 static int framework_fd = -1;
@@ -56,135 +44,71 @@
 static atransport* usb_transport;
 static bool needs_retry = false;
 
-static void read_keys(const char *file, struct listnode *list)
-{
-    FILE *f;
-    char buf[MAX_PAYLOAD_V1];
-    char *sep;
-    int ret;
+bool adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int sig_len) {
+    static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
 
-    f = fopen(file, "re");
-    if (!f) {
-        D("Can't open '%s'", file);
-        return;
-    }
+    for (const auto& path : key_paths) {
+        if (access(path, R_OK) == 0) {
+            LOG(INFO) << "Loading keys from " << path;
 
-    while (fgets(buf, sizeof(buf), f)) {
-        auto key = reinterpret_cast<adb_public_key*>(
-            calloc(1, sizeof(adb_public_key)));
-        if (key == nullptr) {
-            D("Can't malloc key");
-            break;
-        }
+            std::string content;
+            if (!android::base::ReadFileToString(path, &content)) {
+                PLOG(ERROR) << "Couldn't read " << path;
+                continue;
+            }
 
-        sep = strpbrk(buf, " \t");
-        if (sep)
-            *sep = '\0';
+            for (const auto& line : android::base::Split(content, "\n")) {
+                // TODO: do we really have to support both ' ' and '\t'?
+                char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
+                if (sep) *sep = '\0';
 
-        // b64_pton requires one additional byte in the target buffer for
-        // decoding to succeed. See http://b/28035006 for details.
-        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
-        ret = __b64_pton(buf, keybuf, sizeof(keybuf));
-        if (ret != ANDROID_PUBKEY_ENCODED_SIZE) {
-            D("%s: Invalid base64 data ret=%d", file, ret);
-            free(key);
-            continue;
-        }
+                // b64_pton requires one additional byte in the target buffer for
+                // decoding to succeed. See http://b/28035006 for details.
+                uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+                if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+                    LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
+                    continue;
+                }
 
-        if (!android_pubkey_decode(keybuf, ret, &key->key)) {
-            D("%s: Failed to parse key", file);
-            free(key);
-            continue;
-        }
+                RSA* key = nullptr;
+                if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+                    LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path;
+                    continue;
+                }
 
-        list_add_tail(list, &key->node);
-    }
-
-    fclose(f);
-}
-
-static void free_keys(struct listnode *list)
-{
-    struct listnode *item;
-
-    while (!list_empty(list)) {
-        item = list_head(list);
-        list_remove(item);
-        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
-        RSA_free(key->key);
-        free(key);
-    }
-}
-
-static void load_keys(struct listnode *list)
-{
-    const char* path;
-    const char** paths = key_paths;
-    struct stat buf;
-
-    list_init(list);
-
-    while ((path = *paths++)) {
-        if (!stat(path, &buf)) {
-            D("Loading keys from '%s'", path);
-            read_keys(path, list);
+                bool verified = (RSA_verify(NID_sha1, token, token_size, sig, sig_len, key) == 1);
+                RSA_free(key);
+                if (verified) return true;
+            }
         }
     }
+    return false;
 }
 
-int adb_auth_generate_token(void *token, size_t token_size)
-{
-    FILE *f;
-    int ret;
-
-    f = fopen("/dev/urandom", "re");
-    if (!f)
-        return 0;
-
-    ret = fread(token, token_size, 1, f);
-
-    fclose(f);
-    return ret * token_size;
-}
-
-int adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int siglen)
-{
-    struct listnode *item;
-    struct listnode key_list;
-    int ret = 0;
-
-    load_keys(&key_list);
-
-    list_for_each(item, &key_list) {
-        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
-        ret = RSA_verify(NID_sha1, token, token_size, sig, siglen, key->key);
-        if (ret)
-            break;
-    }
-
-    free_keys(&key_list);
-
-    return ret;
+bool adb_auth_generate_token(void* token, size_t token_size) {
+    FILE* fp = fopen("/dev/urandom", "re");
+    if (!fp) return false;
+    bool okay = (fread(token, token_size, 1, fp) == 1);
+    fclose(fp);
+    return okay;
 }
 
 static void usb_disconnected(void* unused, atransport* t) {
-    D("USB disconnect");
+    LOG(INFO) << "USB disconnect";
     usb_transport = NULL;
     needs_retry = false;
 }
 
 static void framework_disconnected() {
-    D("Framework disconnect");
+    LOG(INFO) << "Framework disconnect";
     fdevent_remove(&framework_fde);
     framework_fd = -1;
 }
 
 static void adb_auth_event(int fd, unsigned events, void*) {
-    char response[2];
-    int ret;
-
     if (events & FDE_READ) {
-        ret = unix_read(fd, response, sizeof(response));
+        char response[2];
+        int ret = unix_read(fd, response, sizeof(response));
         if (ret <= 0) {
             framework_disconnected();
         } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
@@ -195,51 +119,43 @@
     }
 }
 
-void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
-{
-    char msg[MAX_PAYLOAD_V1];
-    int ret;
-
+void adb_auth_confirm_key(unsigned char* key, size_t len, atransport* t) {
     if (!usb_transport) {
         usb_transport = t;
         t->AddDisconnect(&usb_disconnect);
     }
 
     if (framework_fd < 0) {
-        D("Client not connected");
+        LOG(ERROR) << "Client not connected";
         needs_retry = true;
         return;
     }
 
     if (key[len - 1] != '\0') {
-        D("Key must be a null-terminated string");
+        LOG(ERROR) << "Key must be a null-terminated string";
         return;
     }
 
-    ret = snprintf(msg, sizeof(msg), "PK%s", key);
-    if (ret >= (signed)sizeof(msg)) {
-        D("Key too long. ret=%d", ret);
+    char msg[MAX_PAYLOAD_V1];
+    int msg_len = snprintf(msg, sizeof(msg), "PK%s", key);
+    if (msg_len >= static_cast<int>(sizeof(msg))) {
+        LOG(ERROR) << "Key too long (" << msg_len << ")";
         return;
     }
-    D("Sending '%s'", msg);
+    LOG(DEBUG) << "Sending '" << msg << "'";
 
-    ret = unix_write(framework_fd, msg, ret);
-    if (ret < 0) {
-        D("Failed to write PK, errno=%d", errno);
+    if (unix_write(framework_fd, msg, msg_len) == -1) {
+        PLOG(ERROR) << "Failed to write PK";
         return;
     }
 }
 
 static void adb_auth_listener(int fd, unsigned events, void* data) {
     sockaddr_storage addr;
-    socklen_t alen;
-    int s;
-
-    alen = sizeof(addr);
-
-    s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
+    socklen_t alen = sizeof(addr);
+    int s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
     if (s < 0) {
-        D("Failed to accept: errno=%d", errno);
+        PLOG(ERROR) << "Failed to accept";
         return;
     }
 
@@ -261,7 +177,7 @@
 void adbd_cloexec_auth_socket() {
     int fd = android_get_control_socket("adbd");
     if (fd == -1) {
-        D("Failed to get adbd socket");
+        PLOG(ERROR) << "Failed to get adbd socket";
         return;
     }
     fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -270,12 +186,12 @@
 void adbd_auth_init(void) {
     int fd = android_get_control_socket("adbd");
     if (fd == -1) {
-        D("Failed to get adbd socket");
+        PLOG(ERROR) << "Failed to get adbd socket";
         return;
     }
 
     if (listen(fd, 4) == -1) {
-        D("Failed to listen on '%d'", fd);
+        PLOG(ERROR) << "Failed to listen on '" << fd << "'";
         return;
     }
 
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index dff874f..4f4f382 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -16,23 +16,24 @@
 
 #define TRACE_TAG AUTH
 
-#include "sysdeps.h"
-#include "adb_auth.h"
-#include "adb_utils.h"
-
+#include <dirent.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#if defined(__linux__)
+#include <sys/inotify.h>
+#endif
 
-#include "adb.h"
+#include <map>
+#include <mutex>
+#include <set>
+#include <string>
 
 #include <android-base/errors.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
-#include <cutils/list.h>
-
 #include <openssl/base64.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
@@ -40,18 +41,20 @@
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-#define ANDROID_PATH   ".android"
-#define ADB_KEY_FILE   "adbkey"
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+#include "sysdeps/mutex.h"
 
-struct adb_private_key {
-    struct listnode node;
-    RSA *rsa;
-};
-
-static struct listnode key_list;
-
+static std::mutex& g_keys_mutex = *new std::mutex;
+static std::map<std::string, std::shared_ptr<RSA>>& g_keys =
+    *new std::map<std::string, std::shared_ptr<RSA>>;
+static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
 
 static std::string get_user_info() {
+    LOG(INFO) << "get_user_info...";
+
     std::string hostname;
     if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
 #if !defined(_WIN32)
@@ -71,6 +74,8 @@
 }
 
 static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
+    LOG(INFO) << "write_public_keyfile...";
+
     uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
     if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
         LOG(ERROR) << "Failed to convert to public key";
@@ -99,19 +104,18 @@
     return true;
 }
 
-static int generate_key(const char *file)
-{
-    EVP_PKEY* pkey = EVP_PKEY_new();
-    BIGNUM* exponent = BN_new();
-    RSA* rsa = RSA_new();
+static int generate_key(const std::string& file) {
+    LOG(INFO) << "generate_key(" << file << ")...";
+
     mode_t old_mask;
     FILE *f = NULL;
     int ret = 0;
 
-    D("generate_key '%s'", file);
-
+    EVP_PKEY* pkey = EVP_PKEY_new();
+    BIGNUM* exponent = BN_new();
+    RSA* rsa = RSA_new();
     if (!pkey || !exponent || !rsa) {
-        D("Failed to allocate key");
+        LOG(ERROR) << "Failed to allocate key";
         goto out;
     }
 
@@ -121,9 +125,9 @@
 
     old_mask = umask(077);
 
-    f = fopen(file, "w");
+    f = fopen(file.c_str(), "w");
     if (!f) {
-        D("Failed to open '%s'", file);
+        PLOG(ERROR) << "Failed to open " << file;
         umask(old_mask);
         goto out;
     }
@@ -143,110 +147,179 @@
     ret = 1;
 
 out:
-    if (f)
-        fclose(f);
+    if (f) fclose(f);
     EVP_PKEY_free(pkey);
     RSA_free(rsa);
     BN_free(exponent);
     return ret;
 }
 
-static int read_key(const char *file, struct listnode *list)
-{
-    D("read_key '%s'", file);
+static std::string hash_key(RSA* key) {
+    unsigned char* pubkey = nullptr;
+    int len = i2d_RSA_PUBKEY(key, &pubkey);
+    if (len < 0) {
+        LOG(ERROR) << "failed to encode RSA public key";
+        return std::string();
+    }
 
-    FILE* fp = fopen(file, "r");
+    std::string result;
+    result.resize(SHA256_DIGEST_LENGTH);
+    SHA256(pubkey, len, reinterpret_cast<unsigned char*>(&result[0]));
+    OPENSSL_free(pubkey);
+    return result;
+}
+
+static bool read_key_file(const std::string& file) {
+    LOG(INFO) << "read_key_file '" << file << "'...";
+
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
     if (!fp) {
-        D("Failed to open '%s': %s", file, strerror(errno));
-        return 0;
+        PLOG(ERROR) << "Failed to open '" << file << "'";
+        return false;
     }
 
-    adb_private_key* key = new adb_private_key;
-    key->rsa = RSA_new();
-
-    if (!PEM_read_RSAPrivateKey(fp, &key->rsa, NULL, NULL)) {
-        D("Failed to read key");
-        fclose(fp);
-        RSA_free(key->rsa);
-        delete key;
-        return 0;
+    RSA* key = RSA_new();
+    if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
+        LOG(ERROR) << "Failed to read key";
+        RSA_free(key);
+        return false;
     }
 
-    fclose(fp);
-    list_add_tail(list, &key->node);
-    return 1;
+    std::lock_guard<std::mutex> lock(g_keys_mutex);
+    std::string fingerprint = hash_key(key);
+    if (g_keys.find(fingerprint) != g_keys.end()) {
+        LOG(INFO) << "ignoring already-loaded key: " << file;
+        RSA_free(key);
+    } else {
+        g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+    }
+
+    return true;
 }
 
-static int get_user_keyfilepath(char *filename, size_t len)
-{
+static bool read_keys(const std::string& path, bool allow_dir = true) {
+    LOG(INFO) << "read_keys '" << path << "'...";
+
+    struct stat st;
+    if (stat(path.c_str(), &st) != 0) {
+        PLOG(ERROR) << "failed to stat '" << path << "'";
+        return false;
+    }
+
+    if (S_ISREG(st.st_mode)) {
+        if (!android::base::EndsWith(path, ".adb_key")) {
+            LOG(INFO) << "skipping non-adb_key '" << path << "'";
+            return false;
+        }
+
+        return read_key_file(path);
+    } else if (S_ISDIR(st.st_mode)) {
+        if (!allow_dir) {
+            // inotify isn't recursive. It would break expectations to load keys in nested
+            // directories but not monitor them for new keys.
+            LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
+            return false;
+        }
+
+        std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
+        if (!dir) {
+            PLOG(ERROR) << "failed to open directory '" << path << "'";
+            return false;
+        }
+
+        bool result = false;
+        while (struct dirent* dent = readdir(dir.get())) {
+            std::string name = dent->d_name;
+
+            // We can't use dent->d_type here because it's not available on Windows.
+            if (name == "." || name == "..") {
+                continue;
+            }
+
+            result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false);
+        }
+        return result;
+    }
+
+    LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
+    return false;
+}
+
+static std::string get_user_key_path() {
     const std::string home = adb_get_homedir_path(true);
-    D("home '%s'", home.c_str());
+    LOG(DEBUG) << "adb_get_homedir_path returned '" << home << "'";
 
-    const std::string android_dir =
-            android::base::StringPrintf("%s%c%s", home.c_str(),
-                                        OS_PATH_SEPARATOR, ANDROID_PATH);
+    const std::string android_dir = android::base::StringPrintf("%s%c.android", home.c_str(),
+                                                                OS_PATH_SEPARATOR);
 
     struct stat buf;
-    if (stat(android_dir.c_str(), &buf)) {
-        if (adb_mkdir(android_dir.c_str(), 0750) < 0) {
-            D("Cannot mkdir '%s'", android_dir.c_str());
-            return -1;
+    if (stat(android_dir.c_str(), &buf) == -1) {
+        if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
+            PLOG(ERROR) << "Cannot mkdir '" << android_dir << "'";
+            return "";
         }
     }
 
-    return snprintf(filename, len, "%s%c%s",
-                    android_dir.c_str(), OS_PATH_SEPARATOR, ADB_KEY_FILE);
+    return android_dir + OS_PATH_SEPARATOR + "adbkey";
 }
 
-static int get_user_key(struct listnode *list)
-{
-    struct stat buf;
-    char path[PATH_MAX];
-    int ret;
-
-    ret = get_user_keyfilepath(path, sizeof(path));
-    if (ret < 0 || ret >= (signed)sizeof(path)) {
-        D("Error getting user key filename");
-        return 0;
+static bool get_user_key() {
+    std::string path = get_user_key_path();
+    if (path.empty()) {
+        PLOG(ERROR) << "Error getting user key filename";
+        return false;
     }
 
-    D("user key '%s'", path);
-
-    if (stat(path, &buf) == -1) {
+    struct stat buf;
+    if (stat(path.c_str(), &buf) == -1) {
+        LOG(INFO) << "User key '" << path << "' does not exist...";
         if (!generate_key(path)) {
-            D("Failed to generate new key");
-            return 0;
+            LOG(ERROR) << "Failed to generate new key";
+            return false;
         }
     }
 
-    return read_key(path, list);
+    return read_key_file(path);
 }
 
-static void get_vendor_keys(struct listnode* key_list) {
+static std::set<std::string> get_vendor_keys() {
     const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
     if (adb_keys_path == nullptr) {
-        return;
+        return std::set<std::string>();
     }
 
+    std::set<std::string> result;
     for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
-        if (!read_key(path.c_str(), key_list)) {
-            D("Failed to read '%s'", path.c_str());
-        }
+        result.emplace(path);
     }
+    return result;
 }
 
-int adb_auth_sign(void *node, const unsigned char* token, size_t token_size,
-                  unsigned char* sig)
-{
-    unsigned int len;
-    struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
+std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() {
+    std::deque<std::shared_ptr<RSA>> result;
 
+    // Copy all the currently known keys.
+    std::lock_guard<std::mutex> lock(g_keys_mutex);
+    for (const auto& it : g_keys) {
+        result.push_back(it.second);
+    }
+
+    // Add a sentinel to the list. Our caller uses this to mean "out of private keys,
+    // but try using the public key" (the empty deque could otherwise mean this _or_
+    // that this function hasn't been called yet to request the keys).
+    result.push_back(nullptr);
+
+    return result;
+}
+
+int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig) {
     if (token_size != TOKEN_SIZE) {
         D("Unexpected token size %zd", token_size);
         return 0;
     }
 
-    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
+    unsigned int len;
+    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key)) {
         return 0;
     }
 
@@ -254,40 +327,17 @@
     return (int)len;
 }
 
-void *adb_auth_nextkey(void *current)
-{
-    struct listnode *item;
-
-    if (list_empty(&key_list))
-        return NULL;
-
-    if (!current)
-        return list_head(&key_list);
-
-    list_for_each(item, &key_list) {
-        if (item == current) {
-            /* current is the last item, we tried all the keys */
-            if (item->next == &key_list)
-                return NULL;
-            return item->next;
-        }
-    }
-
-    return NULL;
-}
-
 std::string adb_auth_get_userkey() {
-    char path[PATH_MAX];
-    int ret = get_user_keyfilepath(path, sizeof(path) - 4);
-    if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
-        D("Error getting user key filename");
+    std::string path = get_user_key_path();
+    if (path.empty()) {
+        PLOG(ERROR) << "Error getting user key filename";
         return "";
     }
-    strcat(path, ".pub");
+    path += ".pub";
 
     std::string content;
     if (!android::base::ReadFileToString(path, &content)) {
-        D("Can't load '%s'", path);
+        PLOG(ERROR) << "Can't load '" << path << "'";
         return "";
     }
     return content;
@@ -297,19 +347,92 @@
     return (generate_key(filename) == 0);
 }
 
-void adb_auth_init(void)
-{
-    int ret;
-
-    D("adb_auth_init");
-
-    list_init(&key_list);
-
-    ret = get_user_key(&key_list);
-    if (!ret) {
-        D("Failed to get user key");
+#if defined(__linux__)
+static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
+    LOG(INFO) << "adb_auth_inotify_update called";
+    if (!(fd_event & FDE_READ)) {
         return;
     }
 
-    get_vendor_keys(&key_list);
+    char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
+    while (true) {
+        ssize_t rc = TEMP_FAILURE_RETRY(unix_read(fd, buf, sizeof(buf)));
+        if (rc == -1) {
+            if (errno == EAGAIN) {
+                LOG(INFO) << "done reading inotify fd";
+                break;
+            }
+            PLOG(FATAL) << "read of inotify event failed";
+        }
+
+        // The read potentially returned multiple events.
+        char* start = buf;
+        char* end = buf + rc;
+
+        while (start < end) {
+            inotify_event* event = reinterpret_cast<inotify_event*>(start);
+            auto root_it = g_monitored_paths.find(event->wd);
+            if (root_it == g_monitored_paths.end()) {
+                LOG(FATAL) << "observed inotify event for unmonitored path, wd = " << event->wd;
+            }
+
+            std::string path = root_it->second;
+            if (event->len > 0) {
+                path += '/';
+                path += event->name;
+            }
+
+            if (event->mask & (IN_CREATE | IN_MOVED_TO)) {
+                if (event->mask & IN_ISDIR) {
+                    LOG(INFO) << "ignoring new directory at '" << path << "'";
+                } else {
+                    LOG(INFO) << "observed new file at '" << path << "'";
+                    read_keys(path, false);
+                }
+            } else {
+                LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
+                             << event->mask;
+            }
+
+            start += sizeof(struct inotify_event) + event->len;
+        }
+    }
+}
+
+static void adb_auth_inotify_init(const std::set<std::string>& paths) {
+    LOG(INFO) << "adb_auth_inotify_init...";
+    int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
+    for (const std::string& path : paths) {
+        int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO);
+        if (wd < 0) {
+            PLOG(ERROR) << "failed to inotify_add_watch on path '" << path;
+            continue;
+        }
+
+        g_monitored_paths[wd] = path;
+        LOG(INFO) << "watch descriptor " << wd << " registered for " << path;
+    }
+
+    fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr);
+    fdevent_add(event, FDE_READ);
+}
+#endif
+
+void adb_auth_init() {
+    LOG(INFO) << "adb_auth_init...";
+
+    if (!get_user_key()) {
+        LOG(ERROR) << "Failed to get user key";
+        return;
+    }
+
+    const auto& key_paths = get_vendor_keys();
+
+#if defined(__linux__)
+    adb_auth_inotify_init(key_paths);
+#endif
+
+    for (const std::string& path : key_paths) {
+        read_keys(path.c_str());
+    }
 }
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index d2ca44e..e160169 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -110,7 +110,6 @@
 
     usb_init();
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    adb_auth_init();
 
     std::string error;
     std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
@@ -118,11 +117,14 @@
         fatal("could not install *smartsocket* listener: %s", error.c_str());
     }
 
-    // Inform our parent that we are up and running.
     if (is_daemon) {
         close_stdin();
         setup_daemon_logging();
+    }
 
+    adb_auth_init();
+
+    if (is_daemon) {
 #if !defined(_WIN32)
         // Start a new session for the daemon. Do this here instead of after the fork so
         // that a ctrl-c between the "starting server" and "done starting server" messages
@@ -132,6 +134,8 @@
         }
 #endif
 
+        // Inform our parent that we are up and running.
+
         // Any error output written to stderr now goes to adb.log. We could
         // keep around a copy of the stderr fd and use that to write any errors
         // encountered by the following code, but that is probably overkill.
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 193b929..8aab389 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -66,6 +66,9 @@
 static auto& gProductOutPath = *new std::string();
 extern int gListenAll;
 
+static constexpr char BUGZ_OK_PREFIX[] = "OK:";
+static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
+
 static std::string product_file(const char *extra) {
     if (gProductOutPath.empty()) {
         fprintf(stderr, "adb: Product directory not specified; "
@@ -158,7 +161,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"
@@ -166,12 +169,12 @@
         "                                 (-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"
         "                                 ('-k' means keep the data and cache directories)\n"
-        "  adb bugreport                - return all information from the device\n"
+        "  adb bugreport [<zip_file>]   - return all information from the device\n"
         "                                 that should be included in a bug report.\n"
         "\n"
         "  adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
@@ -289,11 +292,17 @@
 // this expects that incoming data will use the shell protocol, in which case
 // stdout/stderr are routed independently and the remote exit code will be
 // returned.
-static int read_and_dump(int fd, bool use_shell_protocol=false) {
+// if |output| is non-null, stdout will be appended to it instead.
+// if |err| is non-null, stderr will be appended to it instead.
+static int read_and_dump(int fd, bool use_shell_protocol=false, std::string* output=nullptr,
+                         std::string* err=nullptr) {
     int exit_code = 0;
+    if (fd < 0) return exit_code;
+
     std::unique_ptr<ShellProtocol> protocol;
     int length = 0;
     FILE* outfile = stdout;
+    std::string* outstring = output;
 
     char raw_buffer[BUFSIZ];
     char* buffer_ptr = raw_buffer;
@@ -306,7 +315,7 @@
         buffer_ptr = protocol->data();
     }
 
-    while (fd >= 0) {
+    while (true) {
         if (use_shell_protocol) {
             if (!protocol->Read()) {
                 break;
@@ -314,9 +323,11 @@
             switch (protocol->id()) {
                 case ShellProtocol::kIdStdout:
                     outfile = stdout;
+                    outstring = output;
                     break;
                 case ShellProtocol::kIdStderr:
                     outfile = stderr;
+                    outstring = err;
                     break;
                 case ShellProtocol::kIdExit:
                     exit_code = protocol->data()[0];
@@ -334,8 +345,12 @@
             }
         }
 
-        fwrite(buffer_ptr, 1, length, outfile);
-        fflush(outfile);
+        if (outstring == nullptr) {
+            fwrite(buffer_ptr, 1, length, outfile);
+            fflush(outfile);
+        } else {
+            outstring->append(buffer_ptr, length);
+        }
     }
 
     return exit_code;
@@ -1102,7 +1117,9 @@
 // resulting output.
 static int send_shell_command(TransportType transport_type, const char* serial,
                               const std::string& command,
-                              bool disable_shell_protocol) {
+                              bool disable_shell_protocol,
+                              std::string* output=nullptr,
+                              std::string* err=nullptr) {
     int fd;
     bool use_shell_protocol = false;
 
@@ -1137,7 +1154,7 @@
         }
     }
 
-    int exit_code = read_and_dump(fd, use_shell_protocol);
+    int exit_code = read_and_dump(fd, use_shell_protocol, output, err);
 
     if (adb_close(fd) < 0) {
         PLOG(ERROR) << "failure closing FD " << fd;
@@ -1146,6 +1163,45 @@
     return exit_code;
 }
 
+static int bugreport(TransportType transport_type, const char* serial, int argc,
+                     const char** argv) {
+    if (argc == 1) return send_shell_command(transport_type, serial, "bugreport", false);
+    if (argc != 2) return usage();
+
+    // Zipped bugreport option - will call 'bugreportz', which prints the location of the generated
+    // file, then pull it to the destination file provided by the user.
+    std::string dest_file = argv[1];
+    if (!android::base::EndsWith(argv[1], ".zip")) {
+        // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+        dest_file += ".zip";
+    }
+    std::string output;
+
+    fprintf(stderr, "Bugreport is in progress and it could take minutes to complete.\n"
+            "Please be patient and do not cancel or disconnect your device until it completes.\n");
+    int status = send_shell_command(transport_type, serial, "bugreportz", false, &output, nullptr);
+    if (status != 0 || output.empty()) return status;
+    output = android::base::Trim(output);
+
+    if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) {
+        const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)];
+        std::vector<const char*> srcs{zip_file};
+        status = do_sync_pull(srcs, dest_file.c_str(), true, dest_file.c_str()) ? 0 : 1;
+        if (status != 0) {
+            fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file.c_str());
+        }
+        return status;
+    }
+    if (android::base::StartsWith(output, BUGZ_FAIL_PREFIX)) {
+        const char* error_message = &output[strlen(BUGZ_FAIL_PREFIX)];
+        fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message);
+        return -1;
+    }
+    fprintf(stderr, "Unexpected string (%s) returned by bugreportz, "
+            "device probably does not support -z option\n", output.c_str());
+    return -1;
+}
+
 static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
     char* log_tags = getenv("ANDROID_LOG_TAGS");
     std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
@@ -1681,12 +1737,8 @@
     } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
         return adb_root(argv[0]) ? 0 : 1;
     } else if (!strcmp(argv[0], "bugreport")) {
-        if (argc != 1) return usage();
-        // No need for shell protocol with bugreport, always disable for
-        // simplicity.
-        return send_shell_command(transport_type, serial, "bugreport", true);
-    }
-    else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
+        return bugreport(transport_type, serial, argc, argv);
+    } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
         bool reverse = !strcmp(argv[0], "reverse");
         ++argv;
         --argc;
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 3368b7f..56ff68c 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -622,7 +622,8 @@
     return sc.CopyDone(lpath, rpath);
 }
 
-static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
+static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
+                      const char* name=nullptr) {
     unsigned size = 0;
     if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
 
@@ -675,8 +676,9 @@
         }
 
         bytes_copied += msg.data.size;
+
         sc.RecordBytesTransferred(msg.data.size);
-        sc.ReportProgress(rpath, bytes_copied, size);
+        sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size);
     }
 
     sc.RecordFilesTransferred(1);
@@ -1031,7 +1033,7 @@
 }
 
 bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
-                  bool copy_attrs) {
+                  bool copy_attrs, const char* name) {
     SyncConnection sc;
     if (!sc.IsValid()) return false;
 
@@ -1127,7 +1129,7 @@
 
         sc.NewTransfer();
         sc.SetExpectedTotalBytes(src_size);
-        if (!sync_recv(sc, src_path, dst_path)) {
+        if (!sync_recv(sc, src_path, dst_path, name)) {
             success = false;
             continue;
         }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 460e9dc..0e25974 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -67,7 +67,7 @@
 bool do_sync_ls(const char* path);
 bool do_sync_push(const std::vector<const char*>& srcs, const char* dst);
 bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
-                  bool copy_attrs);
+                  bool copy_attrs, const char* name=nullptr);
 
 bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
 
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index d2ce2d8..2bb01a3 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -254,10 +254,7 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(ClientThreadFunc), nullptr,
                                   &client_thread));
 
-    struct sockaddr addr;
-    socklen_t alen;
-    alen = sizeof(addr);
-    int accept_fd = adb_socket_accept(listen_fd, &addr, &alen);
+    int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
     ASSERT_GE(accept_fd, 0);
     CloseRdHupSocketArg arg;
     arg.socket_fd = accept_fd;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 04df16f..333b861 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -828,4 +828,9 @@
 // configured to drop after 10 missed keepalives. Returns true on success.
 bool set_tcp_keepalive(int fd, int interval_sec);
 
+#if defined(_WIN32)
+// Win32 defines ERROR, which we don't need, but which conflicts with google3 logging.
+#undef ERROR
+#endif
+
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 65b05b8..3eaeb06 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -35,6 +35,7 @@
 #include <android-base/strings.h>
 
 #include "adb.h"
+#include "adb_auth.h"
 #include "adb_utils.h"
 #include "diagnose_usb.h"
 
@@ -784,9 +785,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).
@@ -1074,3 +1073,11 @@
         return 0;
     }
 }
+
+std::shared_ptr<RSA> atransport::NextKey() {
+    if (keys_.empty()) keys_ = adb_auth_get_private_keys();
+
+    std::shared_ptr<RSA> result = keys_[0];
+    keys_.pop_front();
+    return result;
+}
diff --git a/adb/transport.h b/adb/transport.h
index 46d472b..959681f 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -19,12 +19,16 @@
 
 #include <sys/types.h>
 
+#include <deque>
 #include <list>
+#include <memory>
 #include <string>
 #include <unordered_set>
 
 #include "adb.h"
 
+#include <openssl/rsa.h>
+
 typedef std::unordered_set<std::string> FeatureSet;
 
 const FeatureSet& supported_features();
@@ -104,7 +108,8 @@
         return type == kTransportLocal && local_port_for_emulator_ == -1;
     }
 
-    void* key = nullptr;
+    std::shared_ptr<RSA> NextKey();
+
     unsigned char token[TOKEN_SIZE] = {};
     size_t failed_auth_attempts = 0;
 
@@ -156,6 +161,8 @@
     // A list of adisconnect callbacks called when the transport is kicked.
     std::list<adisconnect*> disconnects_;
 
+    std::deque<std::shared_ptr<RSA>> keys_;
+
     DISALLOW_COPY_AND_ASSIGN(atransport);
 };
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d918cc7..cc19785 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -41,14 +41,19 @@
 #include "adb_utils.h"
 
 #if ADB_HOST
+
+// Android Wear has been using port 5601 in all of its documentation/tooling,
+// but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX].
+// Avoid stomping on their port by limiting the number of emulators that can be
+// connected.
+#define ADB_LOCAL_TRANSPORT_MAX 16
+
+ADB_MUTEX_DEFINE(local_transports_lock);
+
 /* we keep a list of opened transports. The atransport struct knows to which
  * local transport it is connected. The list is used to detect when we're
  * trying to connect twice to a given local transport.
  */
-#define  ADB_LOCAL_TRANSPORT_MAX  64
-
-ADB_MUTEX_DEFINE( local_transports_lock );
-
 static atransport*  local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
 #endif /* ADB_HOST */
 
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c10b48c..0ba6b4b 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -400,33 +400,35 @@
     v2_descriptor.os_header = os_desc_header;
     v2_descriptor.os_desc = os_desc_compat;
 
-    D("OPENING %s", USB_FFS_ADB_EP0);
-    h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
-    if (h->control < 0) {
-        D("[ %s: cannot open control endpoint: errno=%d]", USB_FFS_ADB_EP0, errno);
-        goto err;
-    }
-
-    ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
-    if (ret < 0) {
-        v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
-        v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
-        v1_descriptor.header.fs_count = 3;
-        v1_descriptor.header.hs_count = 3;
-        v1_descriptor.fs_descs = fs_descriptors;
-        v1_descriptor.hs_descs = hs_descriptors;
-        D("[ %s: Switching to V1_descriptor format errno=%d ]", USB_FFS_ADB_EP0, errno);
-        ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
-        if (ret < 0) {
-            D("[ %s: write descriptors failed: errno=%d ]", USB_FFS_ADB_EP0, errno);
+    if (h->control < 0) { // might have already done this before
+        D("OPENING %s", USB_FFS_ADB_EP0);
+        h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+        if (h->control < 0) {
+            D("[ %s: cannot open control endpoint: errno=%d]", USB_FFS_ADB_EP0, errno);
             goto err;
         }
-    }
 
-    ret = adb_write(h->control, &strings, sizeof(strings));
-    if (ret < 0) {
-        D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
-        goto err;
+        ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
+        if (ret < 0) {
+            v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+            v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+            v1_descriptor.header.fs_count = 3;
+            v1_descriptor.header.hs_count = 3;
+            v1_descriptor.fs_descs = fs_descriptors;
+            v1_descriptor.hs_descs = hs_descriptors;
+            D("[ %s: Switching to V1_descriptor format errno=%d ]", USB_FFS_ADB_EP0, errno);
+            ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
+            if (ret < 0) {
+                D("[ %s: write descriptors failed: errno=%d ]", USB_FFS_ADB_EP0, errno);
+                goto err;
+            }
+        }
+
+        ret = adb_write(h->control, &strings, sizeof(strings));
+        if (ret < 0) {
+            D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
+            goto err;
+        }
     }
 
     h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
@@ -554,7 +556,6 @@
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
-    adb_close(h->control);
     // Notify usb_adb_open_thread to open a new connection.
     adb_mutex_lock(&h->lock);
     h->open_new_connection = true;
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 44e92fe..bbc724a 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -185,7 +185,7 @@
   return result;
 }
 
-static void send_debuggerd_packet(siginfo_t* info) {
+static void send_debuggerd_packet() {
   // Mutex to prevent multiple crashing threads from trying to talk
   // to debuggerd at the same time.
   static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -222,7 +222,6 @@
     msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_callbacks.get_abort_message());
   }
 
-  msg.original_si_code = (info != nullptr) ? info->si_code : 0;
   ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
   if (ret == sizeof(msg)) {
     char debuggerd_ack;
@@ -254,7 +253,7 @@
 
   log_signal_summary(signal_number, info);
 
-  send_debuggerd_packet(info);
+  send_debuggerd_packet();
 
   // We need to return from the signal handler so that debuggerd can dump the
   // thread that crashed, but returning here does not guarantee that the signal
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index a82fd07..8834209 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -51,6 +51,8 @@
 
 #include <private/android_filesystem_config.h>
 
+#include <debuggerd/client.h>
+
 #include "backtrace.h"
 #include "getevent.h"
 #include "signal_sender.h"
@@ -70,7 +72,6 @@
   pid_t pid, tid;
   uid_t uid, gid;
   uintptr_t abort_msg_address;
-  int32_t original_si_code;
 };
 
 static void wait_for_user_action(const debugger_request_t& request) {
@@ -192,8 +193,6 @@
   }
 
   ALOGV("reading tid");
-  fcntl(fd, F_SETFL, O_NONBLOCK);
-
   pollfd pollfds[1];
   pollfds[0].fd = fd;
   pollfds[0].events = POLLIN;
@@ -222,7 +221,6 @@
   out_request->uid = cr.uid;
   out_request->gid = cr.gid;
   out_request->abort_msg_address = msg.abort_msg_address;
-  out_request->original_si_code = msg.original_si_code;
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
@@ -459,9 +457,10 @@
     return false;
   }
 
-  int total_sleep_time_usec = 0;
   while (true) {
-    int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
+    // wait_for_signal waits for forever, but the watchdog process will kill us
+    // if it takes too long.
+    int signal = wait_for_signal(request.tid);
     switch (signal) {
       case -1:
         ALOGE("debuggerd: timed out waiting for signal");
@@ -470,8 +469,8 @@
       case SIGSTOP:
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("debuggerd: stopped -- dumping to tombstone");
-          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                            request.original_si_code, request.abort_msg_address, amfd_data);
+          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+                            request.abort_msg_address, amfd_data);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
           dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
@@ -493,11 +492,12 @@
 #ifdef SIGSTKFLT
       case SIGSTKFLT:
 #endif
+      case SIGSYS:
       case SIGTRAP:
         ALOGV("stopped -- fatal signal\n");
         *crash_signal = signal;
-        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                          request.original_si_code, request.abort_msg_address, amfd_data);
+        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+                          request.abort_msg_address, amfd_data);
         break;
 
       default:
@@ -822,12 +822,8 @@
   ALOGI("debuggerd: starting\n");
 
   for (;;) {
-    sockaddr_storage ss;
-    sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-    socklen_t alen = sizeof(ss);
-
     ALOGV("waiting for connection\n");
-    int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);
+    int fd = accept4(s, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
     if (fd == -1) {
       ALOGE("accept failed: %s\n", strerror(errno));
       continue;
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
index 41b7b3a..8225c73 100644
--- a/debuggerd/include/debuggerd/client.h
+++ b/debuggerd/include/debuggerd/client.h
@@ -44,7 +44,6 @@
   int32_t action;
   pid_t tid;
   uint64_t abort_msg_address;
-  int32_t original_si_code;
 } debugger_msg_t;
 
 // These callbacks are called in a signal handler, and thus must be async signal safe.
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index 58d640e..5ee07cd 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -595,7 +595,7 @@
   si.si_signo = 0;
   ptrace_set_fake_getsiginfo(si);
 
-  dump_signal_info(&log_, 123, SIGSEGV, 10);
+  dump_signal_info(&log_, 123);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index dfdf29c..3ddd2b0 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -56,8 +56,13 @@
 #define TOMBSTONE_DIR   "/data/tombstones"
 #define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
-static bool signal_has_si_addr(int sig) {
-  switch (sig) {
+static bool signal_has_si_addr(int si_signo, int si_code) {
+  // Manually sent signals won't have si_addr.
+  if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+    return false;
+  }
+
+  switch (si_signo) {
     case SIGBUS:
     case SIGFPE:
     case SIGILL:
@@ -176,7 +181,7 @@
   _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
-static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
+static void dump_signal_info(log_t* log, pid_t tid) {
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
@@ -184,18 +189,15 @@
     return;
   }
 
-  // bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
-  si.si_code = si_code;
-
   char addr_desc[32]; // ", fault addr 0x1234"
-  if (signal_has_si_addr(signal)) {
+  if (signal_has_si_addr(si.si_signo, si.si_code)) {
     snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
   } else {
     snprintf(addr_desc, sizeof(addr_desc), "--------");
   }
 
-  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
-       signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
+  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si.si_signo,
+       get_signame(si.si_signo), si.si_code, get_sigcode(si.si_signo, si.si_code), addr_desc);
 }
 
 static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
@@ -362,7 +364,7 @@
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) {
-    print_fault_address_marker = signal_has_si_addr(si.si_signo);
+    print_fault_address_marker = signal_has_si_addr(si.si_signo, si.si_code);
     addr = reinterpret_cast<uintptr_t>(si.si_addr);
   } else {
     ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
@@ -445,17 +447,14 @@
   }
 }
 
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map, int signal,
-                        int si_code, uintptr_t abort_msg_address, bool primary_thread) {
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map,
+                        uintptr_t abort_msg_address, bool primary_thread) {
   log->current_tid = tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
   }
   dump_thread_info(log, pid, tid);
-
-  if (signal) {
-    dump_signal_info(log, tid, signal, si_code);
-  }
+  dump_signal_info(log, tid);
 
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
   if (primary_thread) {
@@ -545,6 +544,10 @@
     if (!hdr_size) {
       hdr_size = sizeof(log_entry.entry_v1);
     }
+    if ((hdr_size < sizeof(log_entry.entry_v1)) ||
+        (hdr_size > sizeof(log_entry.entry))) {
+      continue;
+    }
     char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
 
     char timeBuf[32];
@@ -606,8 +609,7 @@
 
 // Dumps all information about the specified pid to the tombstone.
 static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int si_code,
-                       uintptr_t abort_msg_address) {
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
   char value[PROPERTY_VALUE_MAX];
   property_get("ro.debuggable", value, "0");
@@ -616,14 +618,14 @@
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(log);
-  dump_thread(log, pid, tid, map, signal, si_code, abort_msg_address, true);
+  dump_thread(log, pid, tid, map, abort_msg_address, true);
   if (want_logs) {
     dump_logs(log, pid, 5);
   }
 
   if (!siblings.empty()) {
     for (pid_t sibling : siblings) {
-      dump_thread(log, pid, sibling, map, 0, 0, 0, false);
+      dump_thread(log, pid, sibling, map, 0, false);
     }
   }
 
@@ -686,8 +688,8 @@
 }
 
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address, std::string* amfd_data) {
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+                       std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
@@ -699,5 +701,5 @@
 
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
+  dump_crash(&log, map, pid, tid, siblings, abort_msg_address);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 487d950..e1c39c5 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -33,7 +33,7 @@
 
 /* Creates a tombstone file and writes the crash dump to it. */
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address, std::string* amfd_data);
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+                       std::string* amfd_data);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index bd06095..7fabf69 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -31,9 +31,6 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-constexpr int SLEEP_TIME_USEC = 50000;          // 0.05 seconds
-constexpr int MAX_TOTAL_SLEEP_USEC = 10000000;  // 10 seconds
-
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == HEADER)
@@ -74,10 +71,10 @@
   }
 }
 
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+int wait_for_signal(pid_t tid) {
   while (true) {
     int status;
-    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL));
     if (n == -1) {
       ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
       return -1;
@@ -91,14 +88,6 @@
         return -1;
       }
     }
-
-    if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
-      ALOGE("timed out waiting for stop signal: tid=%d", tid);
-      return -1;
-    }
-
-    usleep(SLEEP_TIME_USEC);
-    *total_sleep_time_usec += SLEEP_TIME_USEC;
   }
 }
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index cd01188..d820f0f 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -77,7 +77,7 @@
 void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
+int wait_for_signal(pid_t tid);
 
 void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index dde21d5..df0f651 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,
@@ -97,19 +99,40 @@
 };
 
 static struct {
-    char img_name[13];
-    char sig_name[13];
+    char img_name[17];
+    char sig_name[17];
     char part_name[9];
     bool is_optional;
+    bool is_secondary;
 } images[] = {
-    {"boot.img", "boot.sig", "boot", false},
-    {"recovery.img", "recovery.sig", "recovery", true},
-    {"system.img", "system.sig", "system", false},
-    {"vendor.img", "vendor.sig", "vendor", true},
+    {"boot.img", "boot.sig", "boot", false, false},
+    {"boot_other.img", "boot.sig", "boot", true, true},
+    {"recovery.img", "recovery.sig", "recovery", true, false},
+    {"system.img", "system.sig", "system", false, false},
+    {"system_other.img", "system.sig", "system", true, true},
+    {"vendor.img", "vendor.sig", "vendor", true, false},
+    {"vendor_other.img", "vendor.sig", "vendor", true, true},
 };
 
-static std::string find_item(const char* item, const char* product) {
+static std::string find_item_given_name(const char* img_name, const char* product) {
+    if(product) {
+        std::string path = get_my_path();
+        path.erase(path.find_last_of('/'));
+        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+                                           path.c_str(), product, img_name);
+    }
+
+    char *dir = getenv("ANDROID_PRODUCT_OUT");
+    if (dir == nullptr || dir[0] == '\0') {
+        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+    }
+
+    return android::base::StringPrintf("%s/%s", dir, img_name);
+}
+
+std::string find_item(const char* item, const char* product) {
     const char *fn;
+
     if (!strcmp(item,"boot")) {
         fn = "boot.img";
     } else if(!strcmp(item,"recovery")) {
@@ -129,19 +152,7 @@
         return "";
     }
 
-    if (product) {
-        std::string path = get_my_path();
-        path.erase(path.find_last_of('/'));
-        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
-                                           path.c_str(), product, fn);
-    }
-
-    char* dir = getenv("ANDROID_PRODUCT_OUT");
-    if (dir == nullptr || dir[0] == '\0') {
-        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
-    }
-
-    return android::base::StringPrintf("%s/%s", dir, fn);
+    return find_item_given_name(fn, product);
 }
 
 static int64_t get_file_size(int fd) {
@@ -307,8 +318,13 @@
             "\n"
             "commands:\n"
             "  update <filename>                        Reflash device from update.zip.\n"
+            "                                           Sets the flashed slot as active.\n"
             "  flashall                                 Flash boot, system, vendor, and --\n"
-            "                                           if found -- recovery.\n"
+            "                                           if found -- recovery. If the device\n"
+            "                                           supports slots, the slot that has\n"
+            "                                           been flashed to is set as active.\n"
+            "                                           Secondary images may be flashed to\n"
+            "                                           an inactive slot.\n"
             "  flash <partition> [ <filename> ]         Write a file to a flash partition.\n"
             "  flashing lock                            Locks the device. Prevents flashing.\n"
             "  flashing unlock                          Unlocks the device. Allows flashing\n"
@@ -331,7 +347,7 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
-            "  set_active <suffix>                      Sets the active slot. If slots are\n"
+            "  set_active <slot>                        Sets the active slot. If slots are\n"
             "                                           not supported, this does nothing.\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
@@ -368,24 +384,34 @@
             "                                           (default: 2048).\n"
             "  -S <size>[K|M|G]                         Automatically sparse files greater\n"
             "                                           than 'size'. 0 to disable.\n"
-            "  --slot <suffix>                          Specify slot suffix to be used if the\n"
-            "                                           device supports slots. This will be\n"
-            "                                           added to all partition names that use\n"
-            "                                           slots. 'all' can be given to refer\n"
-            "                                           to all slots. 'other' can be given to\n"
-            "                                           refer to a non-current slot. If this\n"
-            "                                           flag is not used, slotted partitions\n"
-            "                                           will default to the current active slot.\n"
-            "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
+            "  --slot <slot>                            Specify slot name to be used if the\n"
+            "                                           device supports slots. All operations\n"
+            "                                           on partitions that support slots will\n"
+            "                                           be done on the slot specified.\n"
+            "                                           'all' can be given to refer to all slots.\n"
+            "                                           'other' can be given to refer to a\n"
+            "                                           non-current slot. If this flag is not\n"
+            "                                           used, slotted partitions will default\n"
+            "                                           to the current active slot.\n"
+            "  -a, --set-active[=<slot>]                Sets the active slot. If no slot is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
             "                                           supported, this does nothing. This will\n"
             "                                           run after all non-reboot commands.\n"
+            "  --skip-secondary                         Will not flash secondary slots when\n"
+            "                                           performing a flashall or update. This\n"
+            "                                           will preserve data on other slots.\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) {
@@ -505,8 +531,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) {
@@ -519,6 +597,7 @@
     ZipEntry zip_entry;
     if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name);
+        fclose(fp);
         return -1;
     }
 
@@ -526,10 +605,12 @@
     int error = ExtractEntryToFile(zip, &zip_entry, fd);
     if (error != 0) {
         fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
+        fclose(fp);
         return -1;
     }
 
     lseek(fd, 0, SEEK_SET);
+    // TODO: We're leaking 'fp' here.
     return fd;
 }
 
@@ -779,83 +860,138 @@
     }
 }
 
-static std::vector<std::string> get_suffixes(Transport* transport) {
+static std::string get_current_slot(Transport* transport)
+{
+    std::string current_slot;
+    if (fb_getvar(transport, "current-slot", &current_slot)) {
+        if (current_slot == "_a") return "a"; // Legacy support
+        if (current_slot == "_b") return "b"; // Legacy support
+        return current_slot;
+    }
+    return "";
+}
+
+// Legacy support
+static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
     std::vector<std::string> suffixes;
     std::string suffix_list;
     if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
-        die("Could not get suffixes.\n");
+        return suffixes;
     }
-    return android::base::Split(suffix_list, ",");
+    suffixes = android::base::Split(suffix_list, ",");
+    // Unfortunately some devices will return an error message in the
+    // guise of a valid value. If we only see only one suffix, it's probably
+    // not real.
+    if (suffixes.size() == 1) {
+        suffixes.clear();
+    }
+    return suffixes;
 }
 
-static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
-    if (strcmp(slot, "all") == 0) {
+// Legacy support
+static bool supports_AB_obsolete(Transport* transport) {
+  return !get_suffixes_obsolete(transport).empty();
+}
+
+static int get_slot_count(Transport* transport) {
+    std::string var;
+    int count;
+    if (!fb_getvar(transport, "slot-count", &var)) {
+        if (supports_AB_obsolete(transport)) return 2; // Legacy support
+    }
+    if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+    return count;
+}
+
+static bool supports_AB(Transport* transport) {
+  return get_slot_count(transport) >= 2;
+}
+
+// Given a current slot, this returns what the 'other' slot is.
+static std::string get_other_slot(const std::string& current_slot, int count) {
+    if (count == 0) return "";
+
+    char next = (current_slot[0] - 'a' + 1)%count + 'a';
+    return std::string(1, next);
+}
+
+static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
+    return get_other_slot(current_slot, get_slot_count(transport));
+}
+
+static std::string get_other_slot(Transport* transport, int count) {
+    return get_other_slot(get_current_slot(transport), count);
+}
+
+static std::string get_other_slot(Transport* transport) {
+    return get_other_slot(get_current_slot(transport), get_slot_count(transport));
+}
+
+static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+    std::string slot = slot_name;
+    if (slot == "_a") slot = "a"; // Legacy support
+    if (slot == "_b") slot = "b"; // Legacy support
+    if (slot == "all") {
         if (allow_all) {
             return "all";
         } else {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            if (!suffixes.empty()) {
-                return suffixes[0];
+            int count = get_slot_count(transport);
+            if (count > 0) {
+                return "a";
             } else {
                 die("No known slots.");
             }
         }
     }
 
-    std::vector<std::string> suffixes = get_suffixes(transport);
+    int count = get_slot_count(transport);
+    if (count == 0) die("Device does not support slots.\n");
 
-    if (strcmp(slot, "other") == 0) {
-        std::string current_slot;
-        if (!fb_getvar(transport, "current-slot", &current_slot)) {
-            die("Failed to identify current slot.");
+    if (slot == "other") {
+        std::string other = get_other_slot(transport, count);
+        if (other == "") {
+           die("No known slots.");
         }
-        if (!suffixes.empty()) {
-            for (size_t i = 0; i < suffixes.size(); i++) {
-                if (current_slot == suffixes[i])
-                    return suffixes[(i+1)%suffixes.size()];
-            }
-        } else {
-            die("No known slots.");
-        }
+        return other;
     }
 
-    for (const std::string &suffix : suffixes) {
-        if (suffix == slot)
-            return slot;
+    if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot;
+
+    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str());
+    for (int i=0; i<count; i++) {
+        fprintf(stderr, "%c\n", (char)(i + 'a'));
     }
-    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
-    for (const std::string &suffix : suffixes) {
-        fprintf(stderr, "%s\n", suffix.c_str());
-    }
+
     exit(1);
 }
 
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const std::string& slot) {
    return verify_slot(transport, slot, true);
 }
 
-static void do_for_partition(Transport* transport, const char *part, const char *slot,
+static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
                              const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
     std::string current_slot;
 
-    if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) {
+    if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
         /* If has-slot is not supported, the answer is no. */
         has_slot = "no";
     }
     if (has_slot == "yes") {
-        if (!slot || slot[0] == 0) {
-            if (!fb_getvar(transport, "current-slot", &current_slot)) {
+        if (slot == "") {
+            current_slot = get_current_slot(transport);
+            if (current_slot == "") {
                 die("Failed to identify current slot.\n");
             }
-            func(std::string(part) + current_slot);
+            func(part + "_" + current_slot);
         } else {
-            func(std::string(part) + slot);
+            func(part + '_' + slot);
         }
     } else {
-        if (force_slot && slot && slot[0]) {
+        if (force_slot && slot != "") {
              fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n",
-                     part, slot);
+                     part.c_str(), slot.c_str());
         }
         func(part);
     }
@@ -866,18 +1002,17 @@
  * partition names. If force_slot is true, it will fail if a slot is specified, and the given
  * partition does not support slots.
  */
-static void do_for_partitions(Transport* transport, const char *part, const char *slot,
+static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
                               const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
 
-    if (slot && strcmp(slot, "all") == 0) {
-        if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) {
-            die("Could not check if partition %s has slot.", part);
+    if (slot == "all") {
+        if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+            die("Could not check if partition %s has slot.", part.c_str());
         }
         if (has_slot == "yes") {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            for (std::string &suffix : suffixes) {
-                do_for_partition(transport, part, suffix.c_str(), func, force_slot);
+            for (int i=0; i < get_slot_count(transport); i++) {
+                do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
             }
         } else {
             do_for_partition(transport, part, "", func, force_slot);
@@ -904,7 +1039,28 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) {
+// Sets slot_override as the active slot. If slot_override is blank,
+// set current slot as active instead. This clears slot-unbootable.
+static void set_active(Transport* transport, const std::string& slot_override) {
+    std::string separator = "";
+    if (!supports_AB(transport)) {
+        if (supports_AB_obsolete(transport)) {
+            separator = "_"; // Legacy support
+        } else {
+            return;
+        }
+    }
+    if (slot_override != "") {
+        fb_set_active((separator + slot_override).c_str());
+    } else {
+        std::string current_slot = get_current_slot(transport);
+        if (current_slot != "") {
+            fb_set_active((separator + current_slot).c_str());
+        }
+    }
+}
+
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -925,7 +1081,30 @@
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
 
+    std::string secondary;
+    if (!skip_secondary) {
+        if (slot_override != "") {
+            secondary = get_other_slot(transport, slot_override);
+        } else {
+            secondary = get_other_slot(transport);
+        }
+        if (secondary == "") {
+            if (supports_AB(transport)) {
+                fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+            }
+            skip_secondary = true;
+        }
+    }
     for (size_t i = 0; i < arraysize(images); ++i) {
+        const char* slot = slot_override.c_str();
+        if (images[i].is_secondary) {
+            if (!skip_secondary) {
+                slot = secondary.c_str();
+            } else {
+                continue;
+            }
+        }
+
         int fd = unzip_to_file(zip, images[i].img_name);
         if (fd == -1) {
             if (images[i].is_optional) {
@@ -950,49 +1129,74 @@
              * program exits.
              */
         };
-        do_for_partitions(transport, images[i].part_name, slot_override, update, false);
+        do_for_partitions(transport, images[i].part_name, slot, update, false);
     }
 
     CloseArchive(zip);
+    if (slot_override == "all") {
+        set_active(transport, "a");
+    } else {
+        set_active(transport, slot_override);
+    }
 }
 
-static void do_send_signature(const char* filename) {
-    if (android::base::EndsWith(filename, ".img") == false) {
-        return;
-    }
+static void do_send_signature(const std::string& fn) {
+    std::size_t extension_loc = fn.find(".img");
+    if (extension_loc == std::string::npos) return;
 
-    std::string sig_path = filename;
-    sig_path.erase(sig_path.size() - 4);
-    sig_path += ".sig";
+    std::string fs_sig = fn.substr(0, extension_loc) + ".sig";
 
     int64_t sz;
-    void* data = load_file(sig_path, &sz);
+    void* data = load_file(fs_sig.c_str(), &sz);
     if (data == nullptr) return;
 
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_flashall(Transport* transport, const char* slot_override, int erase_first) {
+static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) {
+    std::string fname;
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    std::string fname = find_item("info", product);
+    fname = find_item("info", product);
     if (fname.empty()) die("cannot find android-info.txt");
 
     int64_t sz;
-    void* data = load_file(fname, &sz);
+    void* data = load_file(fname.c_str(), &sz);
     if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
 
+    std::string secondary;
+    if (!skip_secondary) {
+        if (slot_override != "") {
+            secondary = get_other_slot(transport, slot_override);
+        } else {
+            secondary = get_other_slot(transport);
+        }
+        if (secondary == "") {
+            if (supports_AB(transport)) {
+                fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+            }
+            skip_secondary = true;
+        }
+    }
+
     for (size_t i = 0; i < arraysize(images); i++) {
-        fname = find_item(images[i].part_name, product);
+        const char* slot = NULL;
+        if (images[i].is_secondary) {
+            if (!skip_secondary) slot = secondary.c_str();
+        } else {
+            slot = slot_override.c_str();
+        }
+        if (!slot) continue;
+        fname = find_item_given_name(images[i].img_name, product);
         fastboot_buffer buf;
         if (!load_buf(transport, fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
-            die("could not load '%s': %s", images[i].img_name, strerror(errno));
+            die("could not load '%s': %s\n", images[i].img_name, strerror(errno));
         }
 
         auto flashall = [&](const std::string &partition) {
@@ -1002,7 +1206,13 @@
             }
             flash_buf(partition.c_str(), &buf);
         };
-        do_for_partitions(transport, images[i].part_name, slot_override, flashall, false);
+        do_for_partitions(transport, images[i].part_name, slot, flashall, false);
+    }
+
+    if (slot_override == "all") {
+        set_active(transport, "a");
+    } else {
+        set_active(transport, slot_override);
     }
 }
 
@@ -1089,7 +1299,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;
@@ -1153,7 +1364,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;
@@ -1181,7 +1392,9 @@
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
     bool wants_set_active = false;
+    bool skip_secondary = false;
     bool erase_first = true;
+    bool set_fbe_marker = false;
     void *data;
     int64_t sz;
     int longindex;
@@ -1204,6 +1417,10 @@
         {"slot", required_argument, 0, 0},
         {"set_active", optional_argument, 0, 'a'},
         {"set-active", optional_argument, 0, 'a'},
+        {"skip-secondary", no_argument, 0, 0},
+#if !defined(_WIN32)
+        {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
         {0, 0, 0, 0}
     };
 
@@ -1285,6 +1502,17 @@
                 return 0;
             } else if (strcmp("slot", longopts[longindex].name) == 0) {
                 slot_override = std::string(optarg);
+            } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
+                skip_secondary = true;
+#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:
@@ -1316,17 +1544,23 @@
         return 1;
     }
 
-    if (slot_override != "")
-        slot_override = verify_slot(transport, slot_override.c_str());
-    if (next_active != "")
-        next_active = verify_slot(transport, next_active.c_str(), false);
+    if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
+        fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
+    }
+    if (slot_override != "") slot_override = verify_slot(transport, slot_override);
+    if (next_active != "") next_active = verify_slot(transport, next_active, false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
-                wants_set_active = false;
+                std::string current_slot;
+                if (fb_getvar(transport, "current-slot", &current_slot)) {
+                    next_active = verify_slot(transport, current_slot, false);
+                } else {
+                    wants_set_active = false;
+                }
             } else {
-                next_active = verify_slot(transport, slot_override.c_str(), false);
+                next_active = verify_slot(transport, slot_override, false);
             }
         }
     }
@@ -1349,7 +1583,7 @@
 
                 fb_queue_erase(partition.c_str());
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true);
+            do_for_partitions(transport, argv[1], slot_override, erase, true);
             skip(2);
         } else if(!strncmp(*argv, "format", strlen("format"))) {
             char *overrides;
@@ -1382,9 +1616,10 @@
                 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);
+            do_for_partitions(transport, argv[1], slot_override, format, true);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1451,7 +1686,7 @@
                 }
                 do_flash(transport, partition.c_str(), fname.c_str());
             };
-            do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
+            do_for_partitions(transport, pname, slot_override, flash, true);
         } else if(!strcmp(*argv, "flash:raw")) {
             char *kname = argv[2];
             char *rname = 0;
@@ -1471,23 +1706,32 @@
             auto flashraw = [&](const std::string &partition) {
                 fb_queue_flash(partition.c_str(), data, sz);
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
+            do_for_partitions(transport, argv[1], slot_override, flashraw, true);
         } else if(!strcmp(*argv, "flashall")) {
             skip(1);
-            do_flashall(transport, slot_override.c_str(), erase_first);
+            if (slot_override == "all") {
+                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+                do_flashall(transport, slot_override, erase_first, true);
+            } else {
+                do_flashall(transport, slot_override, erase_first, skip_secondary);
+            }
             wants_reboot = true;
         } else if(!strcmp(*argv, "update")) {
+            bool slot_all = (slot_override == "all");
+            if (slot_all) {
+                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+            }
             if (argc > 1) {
-                do_update(transport, argv[1], slot_override.c_str(), erase_first);
+                do_update(transport, argv[1], slot_override, erase_first, skip_secondary || slot_all);
                 skip(2);
             } else {
-                do_update(transport, "update.zip", slot_override.c_str(), erase_first);
+                do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all);
                 skip(1);
             }
             wants_reboot = 1;
         } else if(!strcmp(*argv, "set_active")) {
             require(2);
-            std::string slot = verify_slot(transport, argv[1], false);
+            std::string slot = verify_slot(transport, std::string(argv[1]), false);
             fb_set_active(slot.c_str());
             skip(2);
         } else if(!strcmp(*argv, "oem")) {
@@ -1517,13 +1761,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 dfd2abc..1d75aa7 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 1b3893f..46d147a 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -98,6 +98,7 @@
     char tmpmnt_opts[64] = "errors=remount-ro";
     char *e2fsck_argv[] = {
         E2FSCK_BIN,
+        "-f",
         "-y",
         blk_device
     };
@@ -436,12 +437,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 {
@@ -449,48 +470,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
@@ -501,7 +489,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;
@@ -565,15 +553,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");
                 }
@@ -615,6 +603,10 @@
                 /* Let's replay the mount actions. */
                 i = top_idx - 1;
                 continue;
+            } else {
+                ERROR("%s(): Format failed. Suggest recovery...\n", __func__);
+                encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+                continue;
             }
         }
         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
@@ -889,7 +881,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;
         }
 
@@ -905,3 +898,22 @@
 
     return 0;
 }
+
+int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
+{
+    if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        int rc = fs_mgr_setup_verity(fstab_rec);
+        if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            INFO("Verity disabled");
+            return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
+        } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
+            return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
+        } else {
+            return FS_MGR_EARLY_SETUP_VERITY_FAIL;
+        }
+    } else if (device_is_secure()) {
+        ERROR("Verity must be enabled for early mounted partitions on secured devices.\n");
+        return FS_MGR_EARLY_SETUP_VERITY_FAIL;
+    }
+    return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
+}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index 5011b08..7ee5832 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -69,7 +69,7 @@
     }
 
     /* 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, sehandle, 0, 0, NULL);
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 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 5b92db7..791ddd2 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 },
@@ -141,6 +142,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.
@@ -210,9 +216,8 @@
     return f;
 }
 
-struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
 {
-    FILE *fstab_file;
     int cnt, entries;
     ssize_t len;
     size_t alloc_len = 0;
@@ -224,12 +229,6 @@
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
-    fstab_file = fopen(fstab_path, "r");
-    if (!fstab_file) {
-        ERROR("Cannot open file %s\n", fstab_path);
-        return 0;
-    }
-
     entries = 0;
     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
@@ -255,7 +254,6 @@
     /* Allocate and init the fstab structure */
     fstab = calloc(1, sizeof(struct fstab));
     fstab->num_entries = entries;
-    fstab->fstab_filename = strdup(fstab_path);
     fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
 
     fseek(fstab_file, 0, SEEK_SET);
@@ -338,18 +336,34 @@
         ERROR("Error updating for slotselect\n");
         goto err;
     }
-    fclose(fstab_file);
     free(line);
     return fstab;
 
 err:
-    fclose(fstab_file);
     free(line);
     if (fstab)
         fs_mgr_free_fstab(fstab);
     return NULL;
 }
 
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+{
+    FILE *fstab_file;
+    struct fstab *fstab;
+
+    fstab_file = fopen(fstab_path, "r");
+    if (!fstab_file) {
+        ERROR("Cannot open file %s\n", fstab_path);
+        return NULL;
+    }
+    fstab = fs_mgr_read_fstab_file(fstab_file);
+    if (fstab) {
+        fstab->fstab_filename = strdup(fstab_path);
+    }
+    fclose(fstab_file);
+    return fstab;
+}
+
 void fs_mgr_free_fstab(struct fstab *fstab)
 {
     int i;
@@ -465,7 +479,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)
@@ -473,6 +487,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 775f36d..46975f1 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 MF_NOFAIL       0x40000
 
 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 67104cc..767b3b3 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -341,17 +341,6 @@
     return 0;
 }
 
-static int test_access(char *device) {
-    int tries = 25;
-    while (tries--) {
-        if (!access(device, F_OK) || errno != ENOENT) {
-            return 0;
-        }
-        usleep(40 * 1000);
-    }
-    return -1;
-}
-
 static int check_verity_restart(const char *fname)
 {
     char buffer[VERITY_KMSG_BUFSIZE + 1];
@@ -1031,11 +1020,6 @@
     fstab->blk_device = verity_blk_name;
     verity_blk_name = 0;
 
-    // make sure we've set everything up properly
-    if (test_access(fstab->blk_device) < 0) {
-        goto out;
-    }
-
     retval = FS_MGR_SETUP_VERITY_SUCCESS;
 
 out:
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3c27ede..36918fa 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -17,6 +17,7 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
+#include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <linux/dm-ioctl.h>
@@ -72,15 +73,16 @@
 typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
         const char *mount_point, int mode, int status);
 
+struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
 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);
 
@@ -103,6 +105,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);
@@ -111,6 +114,11 @@
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
 
+#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
+#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
+#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
+int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index 3f1b92d..8b126d5 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,3 +1,4 @@
 service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
     class late_start
     user system
+    writepid /dev/cpuset/system-background/tasks
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 d1c547d..f81e7d9 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -42,6 +42,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 {
 
@@ -64,6 +66,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;
@@ -73,6 +76,7 @@
     props->batteryCurrent = 0;
     props->batteryCycleCount = 0;
     props->batteryFullCharge = 0;
+    props->batteryChargeCounter = 0;
     props->batteryTechnology.clear();
 }
 
@@ -207,6 +211,9 @@
     if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
         props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
 
+    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
+        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
+
     props.batteryTemperature = mBatteryFixedTemperature ?
         mBatteryFixedTemperature :
         getIntField(mHealthdConfig->batteryTemperaturePath);
@@ -232,12 +239,12 @@
         props.batteryTechnology = String8(buf.c_str());
 
     unsigned int i;
+    double MaxPower = 0;
 
     for (i = 0; i < mChargerNames.size(); i++) {
         String8 path;
         path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
                           mChargerNames[i].string());
-
         if (getIntField(path)) {
             path.clear();
             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
@@ -259,11 +266,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;
             }
         }
     }
@@ -390,9 +409,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);
@@ -611,7 +631,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/android/log.h b/include/android/log.h
index 2956e6e..a4973b2 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -89,6 +89,11 @@
 } android_LogPriority;
 
 /*
+ * Release any logger resources (a new log write will immediately re-acquire)
+ */
+void __android_log_close();
+
+/*
  * Send a simple string to the log.
  */
 int __android_log_write(int prio, const char *tag, const char *text);
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index acedf73..d80caa6 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -20,6 +20,7 @@
 extern "C" {
 #endif
 
+int ashmem_valid(int fd);
 int ashmem_create_region(const char *name, size_t size);
 int ashmem_set_prot_region(int fd, int prot);
 int ashmem_pin_region(int fd, size_t offset, size_t len);
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index 70f0b92..a34ce86 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -40,11 +40,25 @@
 #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);
+
+/*
+ * Ensure that file exists with given mode and owners.  If it exists
+ * with different owners, they are not fixed and -1 is returned.
+ */
+extern int fs_prepare_file_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/process_name.h b/include/cutils/process_name.h
deleted file mode 100644
index 1e72e5c..0000000
--- a/include/cutils/process_name.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-/**
- * Gives the current process a name.
- */
-
-#ifndef __PROCESS_NAME_H
-#define __PROCESS_NAME_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Sets the current process name.
- *
- * Warning: This leaks a string every time you call it. Use judiciously!
- */
-void set_process_name(const char* process_name);
-
-/** Gets the current process name. */
-const char* get_process_name(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PROCESS_NAME_H */ 
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/log/logger.h b/include/log/logger.h
index 60d47a2..256fdd1 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -143,7 +143,14 @@
     }
     char *msg()
     {
-        return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
+        unsigned short hdr_size = entry.hdr_size;
+        if (!hdr_size) {
+            hdr_size = sizeof(entry_v1);
+        }
+        if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
+            return NULL;
+        }
+        return (char *) buf + hdr_size;
     }
     unsigned int len()
     {
diff --git a/include/system/graphics.h b/include/system/graphics.h
index cf2d7de..a9e451f 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.
@@ -756,6 +1038,48 @@
 
 } android_dataspace_t;
 
+/*
+ * Color transforms that may be applied by hardware composer to the whole
+ * display.
+ */
+typedef enum android_color_transform {
+    /* Applies no transform to the output color */
+    HAL_COLOR_TRANSFORM_IDENTITY = 0,
+
+    /* Applies an arbitrary transform defined by a 4x4 affine matrix */
+    HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+
+    /* Applies a transform that inverts the value or luminance of the color, but
+     * does not modify hue or saturation */
+    HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+
+    /* Applies a transform that maps all colors to shades of gray */
+    HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+
+    /* Applies a transform which corrects for protanopic color blindness */
+    HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+
+    /* Applies a transform which corrects for deuteranopic color blindness */
+    HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+
+    /* Applies a transform which corrects for tritanopic color blindness */
+    HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
+} android_color_transform_t;
+
+/*
+ * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
+ */
+typedef enum android_hdr {
+    /* Device supports Dolby Vision HDR */
+    HAL_HDR_DOLBY_VISION = 1,
+
+    /* Device supports HDR10 */
+    HAL_HDR_HDR10 = 2,
+
+    /* Device supports hybrid log-gamma HDR */
+    HAL_HDR_HLG = 3
+} android_hdr_t;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/system/radio.h b/include/system/radio.h
index 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..b8f33ff 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_SHARED_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_shared_buffer_mode(..., bool sharedBufferMode)
+ * Enable/disable shared buffer mode
+ */
+static inline int native_window_set_shared_buffer_mode(
+        struct ANativeWindow* window,
+        bool sharedBufferMode)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE,
+            sharedBufferMode);
+}
+
+/*
+ * native_window_set_auto_refresh(..., autoRefresh)
+ * Enable/disable auto refresh when in shared 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/Mutex.h b/include/utils/Mutex.h
index 8b720b9..8c4683c 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -35,6 +35,10 @@
 class Condition;
 
 /*
+ * NOTE: This class is for code that builds on Win32.  Its usage is
+ * deprecated for code which doesn't build for Win32.  New code which
+ * doesn't build for Win32 should use std::mutex and std::lock_guard instead.
+ *
  * Simple mutex class.  The implementation is system-dependent.
  *
  * The mutex must be unlocked by the thread that locked it.  They are not
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 4a5874a..07c4de7 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -94,6 +94,8 @@
             bool                startsWith(const String16& prefix) const;
             bool                startsWith(const char16_t* prefix) const;
 
+            bool                contains(const char16_t* chrs) const;
+
             status_t            makeLower();
 
             status_t            replaceAll(char16_t replaceThis,
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 0f7ac9f..a261fc8 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/utils/Unicode.h b/include/utils/Unicode.h
index b76a5e2..a006082 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -29,6 +29,7 @@
 size_t strnlen16(const char16_t *, size_t);
 char16_t *strcpy16(char16_t *, const char16_t *);
 char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+char16_t *strstr16(const char16_t*, const char16_t*);
 
 // Version of comparison that supports embedded nulls.
 // This is different than strncmp() because we don't stop
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 5888456..4a8df32 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -83,14 +83,15 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libinit \
+    libbootloader_message_writer \
     libfs_mgr \
     libfec \
     libfec_rs \
     libsquashfs_utils \
     liblogwrap \
     libcutils \
-    libbase \
     libext4_utils_static \
+    libbase \
     libc \
     libselinux \
     liblog \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3d220c5..48b1ad7 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -37,6 +37,7 @@
 #include <unistd.h>
 #include <linux/loop.h>
 #include <linux/module.h>
+#include <ext4_crypt.h>
 #include <ext4_crypt_init_extensions.h>
 
 #include <selinux/selinux.h>
@@ -47,6 +48,7 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <bootloader_message_writer.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
 #include <logwrap/logwrap.h>
@@ -135,6 +137,17 @@
     }
 }
 
+static int wipe_data_via_recovery(const std::string& reason) {
+    const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
+    std::string err;
+    if (!write_bootloader_message(options, &err)) {
+        LOG(ERROR) << "failed to set bootloader message: " << err;
+        return -1;
+    }
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (1) { pause(); }  // never reached
+}
+
 static void unmount_and_fsck(const struct mntent *entry) {
     if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
         return;
@@ -324,7 +337,13 @@
         }
     }
 
-    return e4crypt_set_directory_policy(args[1].c_str());
+    if (e4crypt_is_native()) {
+        if (e4crypt_set_directory_policy(args[1].c_str())) {
+            wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static struct {
@@ -437,21 +456,6 @@
 
 }
 
-static int wipe_data_via_recovery() {
-    mkdir("/cache/recovery", 0700);
-    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
-    if (fd >= 0) {
-        write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
-        write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
-        close(fd);
-    } else {
-        PLOG(ERROR) << "could not open /cache/recovery/command";
-        return -1;
-    }
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (1) { pause(); }  // never reached
-}
-
 /* Imports .rc files from the specified paths. Default ones are applied if none is given.
  *
  * start_index: index of the first path in the args list
@@ -529,23 +533,23 @@
     import_late(args, 2);
 
     if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
-        property_set("vold.decrypt", "trigger_encryption");
+        ActionManager::GetInstance().QueueEventTrigger("encrypt");
     } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "block");
-        property_set("vold.decrypt", "trigger_default_encryption");
+        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
     } 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 */
         PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
-        ret = wipe_data_via_recovery();
+        ret = wipe_data_via_recovery("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;
         }
@@ -555,13 +559,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) {
         PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << ret;
     }
@@ -930,11 +927,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 {
@@ -953,6 +947,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}},
@@ -969,7 +964,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/devices.cpp b/init/devices.cpp
index 373177e..830b74c 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -44,6 +44,7 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <cutils/list.h>
 #include <cutils/uevent.h>
 
@@ -601,14 +602,17 @@
     return name;
 }
 
+#define DEVPATH_LEN 96
+#define MAX_DEV_NAME 64
+
 static void handle_block_device_event(struct uevent *uevent)
 {
     const char *base = "/dev/block/";
     const char *name;
-    char devpath[96];
+    char devpath[DEVPATH_LEN];
     char **links = NULL;
 
-    name = parse_device_name(uevent, 64);
+    name = parse_device_name(uevent, MAX_DEV_NAME);
     if (!name)
         return;
 
@@ -622,8 +626,6 @@
             uevent->major, uevent->minor, links);
 }
 
-#define DEVPATH_LEN 96
-
 static bool assemble_devpath(char *devpath, const char *dirname,
         const char *devname)
 {
@@ -657,7 +659,7 @@
     char devpath[DEVPATH_LEN] = {0};
     char **links = NULL;
 
-    name = parse_device_name(uevent, 64);
+    name = parse_device_name(uevent, MAX_DEV_NAME);
     if (!name)
         return;
 
@@ -900,7 +902,8 @@
 }
 
 #define UEVENT_MSG_LEN  2048
-void handle_device_fd()
+
+static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
 {
     char msg[UEVENT_MSG_LEN+2];
     int n;
@@ -913,21 +916,28 @@
 
         struct uevent uevent;
         parse_event(msg, &uevent);
-
-        if (selinux_status_updated() > 0) {
-            struct selabel_handle *sehandle2;
-            sehandle2 = selinux_android_file_context_handle();
-            if (sehandle2) {
-                selabel_close(sehandle);
-                sehandle = sehandle2;
-            }
-        }
-
-        handle_device_event(&uevent);
-        handle_firmware_event(&uevent);
+        handle_uevent(&uevent);
     }
 }
 
+void handle_device_fd()
+{
+    handle_device_fd_with(
+        [](struct uevent *uevent) {
+            if (selinux_status_updated() > 0) {
+                struct selabel_handle *sehandle2;
+                sehandle2 = selinux_android_file_context_handle();
+                if (sehandle2) {
+                    selabel_close(sehandle);
+                    sehandle = sehandle2;
+                }
+            }
+
+            handle_device_event(uevent);
+            handle_firmware_event(uevent);
+        });
+}
+
 /* Coldboot walks parts of the /sys tree and pokes the uevent files
 ** to cause the kernel to regenerate device add events that happened
 ** before init's device manager was started
@@ -979,6 +989,65 @@
     }
 }
 
+static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
+{
+    const char *name;
+    char devpath[DEVPATH_LEN];
+
+    if (is_block && strncmp(uevent->subsystem, "block", 5))
+        return;
+
+    name = parse_device_name(uevent, MAX_DEV_NAME);
+    if (!name) {
+        LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
+                   << " " << uevent->partition_name << " " << uevent->partition_num
+                   << " " << uevent->major << ":" << uevent->minor;
+        return;
+    }
+
+    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+    make_dir(base, 0755);
+
+    dev_t dev = makedev(uevent->major, uevent->minor);
+    mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
+    mknod(devpath, mode, dev);
+}
+
+void early_create_dev(const std::string& syspath, early_device_type dev_type)
+{
+    android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
+    if (dfd < 0) {
+        LOG(ERROR) << "Failed to open " << syspath;
+        return;
+    }
+
+    android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
+    if (fd < 0) {
+        LOG(ERROR) << "Failed to open " << syspath << "/uevent";
+        return;
+    }
+
+    fcntl(device_fd, F_SETFL, O_NONBLOCK);
+
+    write(fd, "add\n", 4);
+    handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
+        [](struct uevent *uevent) {
+            early_uevent_handler(uevent, "/dev/block/", true);
+        } :
+        [](struct uevent *uevent) {
+            early_uevent_handler(uevent, "/dev/", false);
+        });
+}
+
+int early_device_socket_open() {
+    device_fd = uevent_open_socket(256*1024, true);
+    return device_fd < 0;
+}
+
+void early_device_socket_close() {
+    close(device_fd);
+}
+
 void device_init() {
     sehandle = selinux_android_file_context_handle();
     selinux_status_open(true);
diff --git a/init/devices.h b/init/devices.h
index 6cb0a77..8e9ab7d 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -21,6 +21,13 @@
 
 extern void handle_device_fd();
 extern void device_init(void);
+
+enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+
+extern int early_device_socket_open();
+extern void early_device_socket_close();
+extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+
 extern int add_dev_perms(const char *name, const char *attr,
                          mode_t perm, unsigned int uid,
                          unsigned int gid, unsigned short prefix,
diff --git a/init/init.cpp b/init/init.cpp
index 78d71a8..957527b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -54,6 +54,7 @@
 #include "action.h"
 #include "bootchart.h"
 #include "devices.h"
+#include "fs_mgr.h"
 #include "import_parser.h"
 #include "init.h"
 #include "init_parser.h"
@@ -342,9 +343,6 @@
 }
 
 static void process_kernel_cmdline() {
-    // Don't expose the raw commandline to unprivileged processes.
-    chmod("/proc/cmdline", 0440);
-
     // The first pass does the common stuff, and finds if we are in qemu.
     // The second pass is only necessary for qemu to export all kernel params
     // as properties.
@@ -461,6 +459,104 @@
     }
 }
 
+/* Returns a new path consisting of base_path and the file name in reference_path. */
+static std::string get_path(const std::string& base_path, const std::string& reference_path) {
+    std::string::size_type pos = reference_path.rfind('/');
+    if (pos == std::string::npos) {
+        return base_path + '/' + reference_path;
+    } else {
+        return base_path + reference_path.substr(pos);
+    }
+}
+
+/* Imports the fstab info from cmdline. */
+static std::string import_cmdline_fstab() {
+    std::string prefix, fstab, fstab_full;
+
+    import_kernel_cmdline(false,
+        [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
+            if (key == "android.early.prefix") {
+                prefix = value;
+            } else if (key == "android.early.fstab") {
+                fstab = value;
+            }
+        });
+    if (!fstab.empty()) {
+        // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
+        std::replace(fstab.begin(), fstab.end(), '+', ' ');
+        for (const auto& entry : android::base::Split(fstab, "\n")) {
+            fstab_full += prefix + entry + '\n';
+        }
+    }
+    return fstab_full;
+}
+
+/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
+static void early_mount() {
+    std::string fstab_string = import_cmdline_fstab();
+    if (fstab_string.empty()) {
+        LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
+        return;
+    }
+    FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
+    if (!fstab_file) {
+        PLOG(ERROR) << "Failed to open fstab string as FILE";
+        return;
+    }
+    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
+    fclose(fstab_file);
+    if (!fstab) {
+        LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
+        return;
+    }
+    LOG(INFO) << "Loaded vendor fstab from cmdline";
+
+    if (early_device_socket_open()) {
+        LOG(ERROR) << "Failed to open device uevent socket";
+        return;
+    }
+
+    /* Create /dev/device-mapper for dm-verity */
+    early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
+
+    for (int i = 0; i < fstab->num_entries; ++i) {
+        struct fstab_rec *rec = &fstab->recs[i];
+        std::string mount_point = rec->mount_point;
+        std::string syspath = rec->blk_device;
+
+        if (mount_point != "/vendor" && mount_point != "/odm")
+            continue;
+
+        /* Create mount target under /dev/block/ from sysfs via uevent */
+        LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
+        char *devpath = strdup(get_path("/dev/block", syspath).c_str());
+        if (!devpath) {
+            PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
+            continue;
+        }
+        rec->blk_device = devpath;
+        early_create_dev(syspath, EARLY_BLOCK_DEV);
+
+        int rc = fs_mgr_early_setup_verity(rec);
+        if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
+            /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
+            early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
+        } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
+            LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
+            continue;
+        } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
+            LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+        }
+
+        mkdir(mount_point.c_str(), 0755);
+        rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
+        if (rc) {
+            PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+        }
+    }
+    early_device_socket_close();
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -477,6 +573,9 @@
 
     bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
 
+    // Don't expose the raw commandline to unprivileged processes.
+    chmod("/proc/cmdline", 0440);
+
     // Get the basic filesystem setup we need put together in the initramdisk
     // on / and then we'll let the rc file figure out the rest.
     if (is_first_stage) {
@@ -489,6 +588,7 @@
         mount("sysfs", "/sys", "sysfs", 0, NULL);
         mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
         mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+        early_mount();
     }
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
@@ -541,6 +641,8 @@
     restorecon("/dev/__properties__");
     restorecon("/property_contexts");
     restorecon_recursive("/sys");
+    restorecon_recursive("/dev/block");
+    restorecon("/dev/device-mapper");
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     if (epoll_fd == -1) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e2e1b16..9e13733 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -227,32 +227,29 @@
 static void handle_property_set_fd()
 {
     prop_msg msg;
-    int s;
     int r;
-    struct ucred cr;
-    struct sockaddr_un addr;
-    socklen_t addr_size = sizeof(addr);
-    socklen_t cr_size = sizeof(cr);
     char * source_ctx = NULL;
-    struct pollfd ufds[1];
-    const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
-    int nr;
 
-    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
+    int s = accept(property_set_fd, nullptr, nullptr);
+    if (s == -1) {
         return;
     }
 
     /* Check socket options here */
+    struct ucred cr;
+    socklen_t cr_size = sizeof(cr);
     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
         close(s);
         PLOG(ERROR) << "Unable to receive socket options";
         return;
     }
 
+    static constexpr int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
+    struct pollfd ufds[1];
     ufds[0].fd = s;
     ufds[0].events = POLLIN;
     ufds[0].revents = 0;
-    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+    int nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
     if (nr == 0) {
         LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
         close(s);
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 995abc0..0d2e11b 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -52,24 +52,8 @@
   }
 }
 
-extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
-                                int* status);
-
 std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
   std::string func_name = GetFunctionNameRaw(pc, offset);
-  if (!func_name.empty()) {
-#if defined(__APPLE__)
-    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
-    if (func_name[0] != '_') {
-      return func_name;
-    }
-#endif
-    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
-    if (name) {
-      func_name = name;
-      free(name);
-    }
-  }
   return func_name;
 }
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 4f26034..8624d13 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -42,7 +42,6 @@
         "load_file.c",
         "native_handle.c",
         "open_memstream.c",
-        "process_name.c",
         "record_stream.c",
         "sched_policy.c",
         "sockets.cpp",
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 4a07d66..09fa09a 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -85,7 +85,7 @@
 }
 
 /* Make sure file descriptor references ashmem, negative number means false */
-static int __ashmem_is_ashmem(int fd)
+static int __ashmem_is_ashmem(int fd, int fatal)
 {
     dev_t rdev;
     struct stat st;
@@ -117,22 +117,29 @@
         }
     }
 
-    if (rdev) {
-        LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o %d:%d",
-          fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
-          S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP,
-          major(rdev), minor(rdev));
-    } else {
-        LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o",
-          fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
-          S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP);
+    if (fatal) {
+        if (rdev) {
+            LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o %d:%d",
+              fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
+              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP,
+              major(rdev), minor(rdev));
+        } else {
+            LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o",
+              fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
+              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP);
+        }
+        /* NOTREACHED */
     }
-    /* NOTREACHED */
 
     errno = ENOTTY;
     return -1;
 }
 
+int ashmem_valid(int fd)
+{
+    return __ashmem_is_ashmem(fd, 0) >= 0;
+}
+
 /*
  * ashmem_create_region - creates a new ashmem region and returns the file
  * descriptor, or <0 on error
@@ -175,7 +182,7 @@
 
 int ashmem_set_prot_region(int fd, int prot)
 {
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -187,7 +194,7 @@
 {
     struct ashmem_pin pin = { offset, len };
 
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -199,7 +206,7 @@
 {
     struct ashmem_pin pin = { offset, len };
 
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -209,7 +216,7 @@
 
 int ashmem_get_size_region(int fd)
 {
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 45c7add..3f14de7 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -37,9 +37,11 @@
 #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_path_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
+        int allow_fixup, int prepare_as_dir) {
     // Check if path needs to be created
     struct stat sb;
+    int create_result = -1;
     if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
         if (errno == ENOENT) {
             goto create;
@@ -50,24 +52,46 @@
     }
 
     // Exists, verify status
-    if (!S_ISDIR(sb.st_mode)) {
-        ALOGE("Not a directory: %s", path);
+    int type_ok = prepare_as_dir ? S_ISDIR(sb.st_mode) : S_ISREG(sb.st_mode);
+    if (!type_ok) {
+        ALOGE("Not a %s: %s", (prepare_as_dir ? "directory" : "regular file"), path);
         return -1;
     }
-    if (((sb.st_mode & ALL_PERMS) == mode) && (sb.st_uid == uid) && (sb.st_gid == gid)) {
-        return 0;
-    } else {
-        goto fixup;
-    }
 
-create:
-    if (TEMP_FAILURE_RETRY(mkdir(path, mode)) == -1) {
-        if (errno != EEXIST) {
-            ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
+    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 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:
+    create_result = prepare_as_dir
+        ? TEMP_FAILURE_RETRY(mkdir(path, mode))
+        : TEMP_FAILURE_RETRY(open(path, O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_RDONLY));
+    if (create_result == -1) {
+        if (errno != EEXIST) {
+            ALOGE("Failed to %s(%s): %s",
+                    (prepare_as_dir ? "mkdir" : "open"), path, strerror(errno));
+            return -1;
+        }
+    } else if (!prepare_as_dir) {
+        // For regular files we need to make sure we close the descriptor
+        if (close(create_result) == -1) {
+            ALOGW("Failed to close file after create %s: %s", path, strerror(errno));
+        }
+    }
 fixup:
     if (TEMP_FAILURE_RETRY(chmod(path, mode)) == -1) {
         ALOGE("Failed to chmod(%s, %d): %s", path, mode, strerror(errno));
@@ -81,6 +105,18 @@
     return 0;
 }
 
+int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 1, /*prepare_as_dir*/ 1);
+}
+
+int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 1);
+}
+
+int fs_prepare_file_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 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..840ac86 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" },
@@ -148,7 +149,9 @@
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
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/process_name.c b/libcutils/process_name.c
deleted file mode 100644
index 5d28b6f..0000000
--- a/libcutils/process_name.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(__linux__)
-#include <sys/prctl.h>
-#endif
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/process_name.h>
-#if defined(__ANDROID__)
-#include <cutils/properties.h>
-#endif
-
-#define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
-
-static const char* process_name = "unknown";
-#if defined(__ANDROID__)
-static int running_in_emulator = -1;
-#endif
-
-void set_process_name(const char* new_name) {
-#if defined(__ANDROID__)
-    char  propBuf[PROPERTY_VALUE_MAX];
-#endif
-
-    if (new_name == NULL) {
-        return;
-    }
-
-    // We never free the old name. Someone else could be using it.
-    int len = strlen(new_name);
-    char* copy = (char*) malloc(len + 1);
-    strcpy(copy, new_name);
-    process_name = (const char*) copy;
-
-#if defined(__linux__)
-    if (len < 16) {
-        prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
-    } else {
-        prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0);
-    }
-#endif
-
-#if defined(__ANDROID__)
-    // If we know we are not running in the emulator, then return.
-    if (running_in_emulator == 0) {
-        return;
-    }
-
-    // If the "running_in_emulator" variable has not been initialized,
-    // then do it now.
-    if (running_in_emulator == -1) {
-        property_get("ro.kernel.qemu", propBuf, "");
-        if (propBuf[0] == '1') {
-            running_in_emulator = 1;
-        } else {
-            running_in_emulator = 0;
-            return;
-        }
-    }
-
-    // If the emulator was started with the "-trace file" command line option
-    // then we want to record the process name in the trace even if we are
-    // not currently tracing instructions (so that we will know the process
-    // name when we do start tracing instructions).  We do not need to execute
-    // this code if we are just running in the emulator without the "-trace"
-    // command line option, but we don't know that here and this function
-    // isn't called frequently enough to bother optimizing that case.
-    int fd = open(PROCESS_NAME_DEVICE, O_RDWR);
-    if (fd < 0)
-        return;
-    write(fd, process_name, strlen(process_name) + 1);
-    close(fd);
-#endif
-}
-
-const char* get_process_name(void) {
-    return process_name;
-}
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 14a58ca..dcd16ef 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -72,7 +72,8 @@
         savedErrno = 0;
     }
     if (res < 0) {
-        ALOGI("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno);
+        // ALOGV is enough because all the callers also log failures
+        ALOGV("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno);
     }
     close(fd);
     return -savedErrno;
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 5c68add..32e6c25 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -59,8 +59,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
@@ -127,19 +129,23 @@
         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
-
 }
 
 /*
- * Try to get the scheduler group.
+ * Returns the path under the requested cgroup subsystem (if it exists)
  *
  * The data from /proc/<pid>/cgroup looks (something) like:
  *  2:cpu:/bg_non_interactive
@@ -149,7 +155,7 @@
  * the default cgroup.  If the string is longer than "bufLen", the string
  * will be truncated.
  */
-static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
+static int getCGroupSubsys(int tid, const char* subsys, char* buf, size_t bufLen)
 {
 #if defined(__ANDROID__)
     char pathBuf[32];
@@ -163,7 +169,7 @@
 
     while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
         char *next = lineBuf;
-        char *subsys;
+        char *found_subsys;
         char *grp;
         size_t len;
 
@@ -172,11 +178,11 @@
             goto out_bad_data;
         }
 
-        if (!(subsys = strsep(&next, ":"))) {
+        if (!(found_subsys = strsep(&next, ":"))) {
             goto out_bad_data;
         }
 
-        if (strcmp(subsys, "cpu")) {
+        if (strcmp(found_subsys, subsys)) {
             /* Not the subsys we're looking for */
             continue;
         }
@@ -197,7 +203,7 @@
         return 0;
     }
 
-    SLOGE("Failed to find cpu subsys");
+    SLOGE("Failed to find subsys %s", subsys);
     fclose(fp);
     return -1;
  out_bad_data:
@@ -219,7 +225,23 @@
 
     if (__sys_supports_schedgroups) {
         char grpBuf[32];
-        if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
+#ifdef USE_CPUSETS
+        if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
+            return -1;
+        if (grpBuf[0] == '\0') {
+            *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "foreground")) {
+            *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "background")) {
+            *policy = SP_BACKGROUND;
+        } else if (!strcmp(grpBuf, "top-app")) {
+            *policy = SP_TOP_APP;
+        } else {
+            errno = ERANGE;
+            return -1;
+        }
+#else
+        if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
             return -1;
         if (grpBuf[0] == '\0') {
             *policy = SP_FOREGROUND;
@@ -229,6 +251,7 @@
             errno = ERANGE;
             return -1;
         }
+#endif
     } else {
         int rc = sched_getscheduler(tid);
         if (rc < 0)
@@ -257,8 +280,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;
@@ -270,6 +293,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;
@@ -342,6 +373,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:
@@ -362,6 +394,7 @@
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
+        case SP_TOP_APP:
             fd = fg_cgroup_fd;
             break;
         default:
@@ -416,6 +449,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/libcutils/trace-dev.c b/libcutils/trace-dev.c
index 5df1c5a..778e4f0 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -66,24 +66,17 @@
 // values listed in the app_cmdlines property.
 static bool atrace_is_cmdline_match(const char* cmdline)
 {
+    int count = property_get_int32("debug.atrace.app_number", 0);
+
+    char buf[PROPERTY_KEY_MAX];
     char value[PROPERTY_VALUE_MAX];
-    char* start = value;
 
-    property_get("debug.atrace.app_cmdlines", value, "");
-
-    while (start != NULL) {
-        char* end = strchr(start, ',');
-
-        if (end != NULL) {
-            *end = '\0';
-            end++;
-        }
-
-        if (strcmp(cmdline, start) == 0) {
+    for (int i = 0; i < count; i++) {
+        snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
+        property_get(buf, value, "");
+        if (strcmp(value, cmdline) == 0) {
             return true;
         }
-
-        start = end;
     }
 
     return false;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 81a510e..e32f73c 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -77,6 +77,7 @@
 
     cflags: [
         "-Werror",
+        "-fvisibility=hidden",
         // This is what we want to do:
         //  liblog_cflags := $(shell \
         //   sed -n \
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 059f170..ed82902 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -67,12 +67,9 @@
     int i, ret = 0;
 
     if (logdLoggerWrite.context.sock < 0) {
-        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 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));
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 00157b7..0d55453 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -367,6 +367,10 @@
     if (log_msg->entry_v2.hdr_size == 0) {
         log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
     }
+    if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
+            (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
+        return -EINVAL;
+    }
 
     /* len validation */
     if (ret <= log_msg->entry_v2.hdr_size) {
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index b802ed7..c7b5a84 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -132,6 +132,41 @@
     }
     return kLogNotAvailable;
 }
+/*
+ * Release any logger resources. A new log write will immediately re-acquire.
+ */
+LIBLOG_ABI_PUBLIC void __android_log_close()
+{
+    struct android_log_transport_write *transport;
+
+    __android_log_lock();
+
+    write_to_log = __write_to_log_init;
+
+    /*
+     * Threads that are actively writing at this point are not held back
+     * by a lock and are at risk of dropping the messages with a return code
+     * -EBADF. Prefer to return error code than add the overhead of a lock to
+     * each log writing call to guarantee delivery. In addition, anyone
+     * calling this is doing so to release the logging resources and shut down,
+     * for them to do so with outstanding log requests in other threads is a
+     * disengenuous use of this function.
+     */
+
+    write_transport_for_each(transport, &__android_log_persist_write) {
+        if (transport->close) {
+            (*transport->close)();
+        }
+    }
+
+    write_transport_for_each(transport, &__android_log_transport_write) {
+        if (transport->close) {
+            (*transport->close)();
+        }
+    }
+
+    __android_log_unlock();
+}
 
 /* log_init_lock assumed */
 static int __write_to_log_initialize()
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 59bd479..e21a9c4 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -496,6 +496,11 @@
     char *msg = buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
+        if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
+                (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
+            fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+            return -1;
+        }
         msg = ((char *)buf2) + buf2->hdr_size;
         if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
             entry->uid = ((struct logger_entry_v4 *)buf)->uid;
@@ -775,6 +780,11 @@
     eventData = (const unsigned char*) buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
+        if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
+                (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
+            fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+            return -1;
+        }
         eventData = ((unsigned char *)buf2) + buf2->hdr_size;
         if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
                 (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index a4eec65..679c159 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -343,6 +343,10 @@
         char *msg = (char *)&transp.logMsg + hdr_size;
         char *split = NULL;
 
+        if ((hdr_size < sizeof(transp.logMsg.entry_v1)) ||
+                (hdr_size > sizeof(transp.logMsg.entry))) {
+            continue;
+        }
         /* Check for invalid sequence number */
         if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
                 ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 1b66a56..f4e3089 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -542,7 +542,7 @@
 
             char* eventData = log_msg.msg();
 
-            if (eventData[4] != EVENT_TYPE_LONG) {
+            if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
                 continue;
             }
             log_time tx(eventData + 4 + 1);
@@ -622,7 +622,7 @@
 
             char* eventData = log_msg.msg();
 
-            if (eventData[4] != EVENT_TYPE_LONG) {
+            if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
                 continue;
             }
             log_time tx(eventData + 4 + 1);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index df2c766..b3b44e3 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -132,12 +132,17 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
+    // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
-
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    __android_log_close();
+
+    log_time ts1(CLOCK_MONOTONIC);
+    ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
     usleep(1000000);
 
     int count = 0;
+    int second_count = 0;
 
     for (;;) {
         log_msg log_msg;
@@ -154,17 +159,20 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
         log_time tx(eventData + 4 + 1);
         if (ts == tx) {
             ++count;
+        } else if (ts1 == tx) {
+            ++second_count;
         }
     }
 
     EXPECT_EQ(1, count);
+    EXPECT_EQ(1, second_count);
 
     android_logger_list_close(logger_list);
 }
@@ -227,7 +235,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_STRING) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_STRING)) {
             continue;
         }
 
@@ -506,7 +514,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -637,7 +645,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -788,7 +796,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -990,9 +998,9 @@
             continue;
         }
 
-        char *data = log_msg.msg() + 1;
+        char *data = log_msg.msg();
 
-        if (strcmp(data, tag)) {
+        if (!data || strcmp(++data, tag)) {
             continue;
         }
 
@@ -1107,9 +1115,9 @@
             continue;
         }
 
-        char *data = log_msg.msg() + 1;
+        char *data = log_msg.msg();
 
-        if (strcmp(data, tag)) {
+        if (!data || strcmp(++data, tag)) {
             continue;
         }
 
@@ -1606,6 +1614,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1687,6 +1698,10 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
+
         char *original = eventData;
 
         // Tag
@@ -1774,6 +1789,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1817,6 +1835,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1904,6 +1925,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1961,6 +1985,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -2449,16 +2476,19 @@
         android_log_format_free(logformat);
 
         // test buffer reading API
-        snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
-        print_barrier();
-        fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
-        memset(msgBuf, 0, sizeof(msgBuf));
-        int buffer_to_string = android_log_buffer_to_string(
-            eventData + sizeof(uint32_t),
-            log_msg.entry.len - sizeof(uint32_t),
-            msgBuf, sizeof(msgBuf));
-        fprintf(stderr, "%s\n", msgBuf);
-        print_barrier();
+        int buffer_to_string = -1;
+        if (eventData) {
+            snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
+            print_barrier();
+            fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
+            memset(msgBuf, 0, sizeof(msgBuf));
+            buffer_to_string = android_log_buffer_to_string(
+                eventData + sizeof(uint32_t),
+                log_msg.entry.len - sizeof(uint32_t),
+                msgBuf, sizeof(msgBuf));
+            fprintf(stderr, "%s\n", msgBuf);
+            print_barrier();
+        }
         EXPECT_EQ(0, buffer_to_string);
         EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
         EXPECT_EQ(0, strcmp(expected_string, msgBuf));
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index d0e07dd..e89c50f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -21,6 +21,7 @@
 #ifdef __ANDROID__
 #include "dlext_namespaces.h"
 #include "cutils/properties.h"
+#define LOG_TAG "libnativeloader"
 #include "log/log.h"
 #endif
 
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 56e1d59..0000000
--- a/libnetutils/dhcp_utils.c
+++ /dev/null
@@ -1,370 +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 */
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
-            p2p_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", DAEMON_NAME_RENEW,
-            p2p_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 a2d3869..d23afd3 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -20,9 +20,10 @@
 #include <stdbool.h>
 #include <stdlib.h>
 
-#include <netutils/dhcp.h>
 #include <netutils/ifc.h>
 
+extern int do_dhcp(char*);
+
 int main(int argc, char* argv[]) {
   if (argc != 2) {
     error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
diff --git a/libnetutils/include/netutils/dhcp.h b/libnetutils/include/netutils/dhcp.h
deleted file mode 100644
index 008dbd8..0000000
--- a/libnetutils/include/netutils/dhcp.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2010, 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 _NETUTILS_DHCP_H_
-#define _NETUTILS_DHCP_H_
-
-#include <sys/cdefs.h>
-#include <arpa/inet.h>
-
-__BEGIN_DECLS
-
-extern int do_dhcp(char *iname);
-extern int dhcp_start(const char *ifname);
-extern int dhcp_start_renew(const char *ifname);
-extern int dhcp_get_results(const char *ifname,
-                            char *ipaddr,
-                            char *gateway,
-                            uint32_t *prefixLength,
-                            char *dns[],
-                            char *server,
-                            uint32_t *lease,
-                            char *vendorInfo,
-                            char *domain,
-                            char *mtu);
-extern int dhcp_stop(const char *ifname);
-extern int dhcp_release_lease(const char *ifname);
-extern char *dhcp_get_errmsg();
-
-__END_DECLS
-
-#endif /* _NETUTILS_DHCP_H_ */
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 4b498c1..ae38519 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -23,7 +23,6 @@
 #include <sys/mman.h>
 
 #include <cutils/ashmem.h>
-#include <cutils/atomic.h>
 #define LOG_TAG "CodeCache"
 #include <cutils/log.h>
 
@@ -101,7 +100,7 @@
 }
 
 Assembly::Assembly(size_t size)
-    : mCount(1), mSize(0)
+    : mCount(0), mSize(0)
 {
     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
     LOG_ALWAYS_FATAL_IF(mBase == NULL,
@@ -117,12 +116,12 @@
 
 void Assembly::incStrong(const void*) const
 {
-    android_atomic_inc(&mCount);
+    mCount.fetch_add(1, std::memory_order_relaxed);
 }
 
 void Assembly::decStrong(const void*) const
 {
-    if (android_atomic_dec(&mCount) == 1) {
+    if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
         delete this;
     }
 }
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index c0e0684..9326453 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -19,6 +19,7 @@
 #ifndef ANDROID_CODECACHE_H
 #define ANDROID_CODECACHE_H
 
+#include <atomic>
 #include <stdint.h>
 #include <pthread.h>
 #include <sys/types.h>
@@ -69,7 +70,7 @@
     typedef void    weakref_type;
 
 private:
-    mutable int32_t     mCount;
+    mutable std::atomic<int32_t>     mCount;
             uint32_t*   mBase;
             size_t      mSize;
 };
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index 5f58797..63642c4 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -34,7 +34,6 @@
 
 #include <sys/mman.h>
 #include <cutils/ashmem.h>
-#include <cutils/atomic.h>
 
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
index b680b60..e8c4626 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
@@ -34,7 +34,6 @@
 
 #include <sys/mman.h>
 #include <cutils/ashmem.h>
-#include <cutils/atomic.h>
 #include <cutils/log.h>
 
 #define __STDC_FORMAT_MACROS
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index 14c76c5..0bfc391 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -16,14 +16,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 c2d2d27..0000000
--- a/libprocessgroup/cleanup.cpp
+++ /dev/null
@@ -1,30 +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 "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 1961e76..65bbc1e 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -30,12 +30,36 @@
 
 #include <chrono>
 #include <memory>
+#include <mutex>
 
 #include <android-base/logging.h>
 #include <private/android_filesystem_config.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;
@@ -45,10 +69,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);
 }
@@ -56,7 +95,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,
@@ -187,9 +226,10 @@
 void removeAllProcessGroups()
 {
     LOG(VERBOSE) << "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) {
-        PLOG(ERROR) << "failed to open " << PROCESSGROUP_CGROUP_PATH;
+        PLOG(ERROR) << "failed to open " << cgroup_root_path;
     } else {
         struct dirent cur;
         struct dirent *dir;
@@ -203,7 +243,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);
             LOG(VERBOSE) << "removing " << path;
             if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << 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/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 4d602a6..608abae 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -199,16 +199,7 @@
             continue;
         }
         if (mListen && FD_ISSET(mSock, &read_fds)) {
-            sockaddr_storage ss;
-            sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-            socklen_t alen;
-            int c;
-
-            do {
-                alen = sizeof(ss);
-                c = accept4(mSock, addrp, &alen, SOCK_CLOEXEC);
-                SLOGV("%s got %d from accept", mSocketName, c);
-            } while (c < 0 && errno == EINTR);
+            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
             if (c < 0) {
                 SLOGE("accept failed (%s)", strerror(errno));
                 sleep(1);
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.bp b/libutils/Android.bp
index 1038db4..25c779e 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -108,10 +108,7 @@
 cc_test {
     name: "SharedBufferTest",
     host_supported: true,
-    static_libs: [
-        "libutils",
-        "libcutils",
-    ],
+    static_libs: ["libutils"],
     shared_libs: ["liblog"],
     srcs: ["SharedBufferTest.cpp"],
 }
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index dc96aef..6c8c7d3 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/String16.cpp b/libutils/String16.cpp
index 87eda1b..ac12d8a 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -344,6 +344,11 @@
     return strncmp16(mString, prefix, ps) == 0;
 }
 
+bool String16::contains(const char16_t* chrs) const
+{
+    return strstr16(mString, chrs) != nullptr;
+}
+
 status_t String16::makeLower()
 {
     const size_t N = size();
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/Unicode.cpp b/libutils/Unicode.cpp
index 6f4b721..f1f8bc9 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -222,12 +222,17 @@
   char16_t ch;
   int d = 0;
 
-  while ( n-- ) {
-    d = (int)(ch = *s1++) - (int)*s2++;
-    if ( d || !ch )
-      break;
+  if (n == 0) {
+    return 0;
   }
 
+  do {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch ) {
+      break;
+    }
+  } while (--n);
+
   return d;
 }
 
@@ -284,6 +289,25 @@
   return ss-s;
 }
 
+char16_t* strstr16(const char16_t* src, const char16_t* target)
+{
+    const char16_t needle = *target++;
+    const size_t target_len = strlen16(target);
+    if (needle != '\0') {
+      do {
+        do {
+          if (*src == '\0') {
+            return nullptr;
+          }
+        } while (*src++ != needle);
+      } while (strncmp16(src, target, target_len) != 0);
+      src--;
+    }
+
+    return (char16_t*)src;
+}
+
+
 int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
 {
     const char16_t* e1 = s1+n1;
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index bdb1bb7..8ebcfaf 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/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
index 18c130c..c263f75 100644
--- a/libutils/tests/Unicode_test.cpp
+++ b/libutils/tests/Unicode_test.cpp
@@ -29,6 +29,8 @@
 
     virtual void TearDown() {
     }
+
+    char16_t const * const kSearchString = u"I am a leaf on the wind.";
 };
 
 TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
@@ -112,4 +114,37 @@
             << "should be NULL terminated";
 }
 
+TEST_F(UnicodeTest, strstr16EmptyTarget) {
+    EXPECT_EQ(strstr16(kSearchString, u""), kSearchString)
+            << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16SameString) {
+    const char16_t* result = strstr16(kSearchString, kSearchString);
+    EXPECT_EQ(kSearchString, result)
+            << "should return the original pointer";
+}
+
+TEST_F(UnicodeTest, strstr16TargetStartOfString) {
+    const char16_t* result = strstr16(kSearchString, u"I am");
+    EXPECT_EQ(kSearchString, result)
+            << "should return the original pointer";
+}
+
+
+TEST_F(UnicodeTest, strstr16TargetEndOfString) {
+    const char16_t* result = strstr16(kSearchString, u"wind.");
+    EXPECT_EQ(kSearchString+19, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetWithinString) {
+    const char16_t* result = strstr16(kSearchString, u"leaf");
+    EXPECT_EQ(kSearchString+7, result);
+}
+
+TEST_F(UnicodeTest, strstr16TargetNotPresent) {
+    const char16_t* result = strstr16(kSearchString, u"soar");
+    EXPECT_EQ(nullptr, result);
+}
+
 }
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a2d6fcc..350be31 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,
@@ -819,8 +825,9 @@
       // disk does not have enough space.
       result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
       if (result == -1 && errno == ENOSPC) {
-        ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
-              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        ALOGW("Zip: unable to allocate  %" PRId64 " bytes at offset %" PRId64 " : %s",
+              static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
+              strerror(errno));
         return std::unique_ptr<FileWriter>(nullptr);
       }
     }
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 37fbdb8..df1b9af 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)
@@ -410,9 +397,6 @@
 }
 
 static void ctrl_connect_handler(uint32_t events __unused) {
-    struct sockaddr_storage ss;
-    struct sockaddr *addrp = (struct sockaddr *)&ss;
-    socklen_t alen;
     struct epoll_event epev;
 
     if (ctrl_dfd >= 0) {
@@ -420,8 +404,7 @@
         ctrl_dfd_reopened = 1;
     }
 
-    alen = sizeof(ss);
-    ctrl_dfd = accept(ctrl_lfd, addrp, &alen);
+    ctrl_dfd = accept(ctrl_lfd, NULL, NULL);
 
     if (ctrl_dfd < 0) {
         ALOGE("lmkd control socket accept failed; errno=%d", errno);
@@ -608,7 +591,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 +603,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 +767,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/logd/Android.mk b/logd/Android.mk
index 3348890..81637d2 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -43,10 +43,6 @@
 
 LOCAL_CFLAGS := -Werror $(event_flag)
 
-ifeq ($(TARGET_BUILD_VARIANT),user)
-LOCAL_CFLAGS += -DAUDITD_ENFORCE_INTEGRITY=true
-endif
-
 include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 8859d55..cc140b0 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,9 +25,6 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
-#include <string>
-
-#include <cutils/properties.h>
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
@@ -38,10 +35,6 @@
 #include "LogKlog.h"
 #include "LogReader.h"
 
-#ifndef AUDITD_ENFORCE_INTEGRITY
-#define AUDITD_ENFORCE_INTEGRITY false
-#endif
-
 #define KMSG_PRIORITY(PRI)                          \
     '<',                                            \
     '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
@@ -53,10 +46,11 @@
         logbuf(buf),
         reader(reader),
         fdDmesg(fdDmesg),
-        policyLoaded(false),
-        rebootToSafeMode(false),
         initialized(false) {
-    logToDmesg("start");
+    static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
+        'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
+        ' ', 's', 't', 'a', 'r', 't', '\n' };
+    write(fdDmesg, auditd_message, sizeof(auditd_message));
 }
 
 bool LogAudit::onDataAvailable(SocketClient *cli) {
@@ -82,55 +76,6 @@
     return true;
 }
 
-void LogAudit::logToDmesg(const std::string& str)
-{
-    static const char prefix[] = { KMSG_PRIORITY(LOG_INFO),
-        'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
-        ' ', '\0' };
-    std::string message = prefix + str + "\n";
-    write(fdDmesg, message.c_str(), message.length());
-}
-
-std::string LogAudit::getProperty(const std::string& name)
-{
-    char value[PROP_VALUE_MAX] = {0};
-    property_get(name.c_str(), value, "");
-    return value;
-}
-
-void LogAudit::enforceIntegrity() {
-    static bool loggedOnce;
-    bool once = loggedOnce;
-
-    loggedOnce = true;
-
-    if (!AUDITD_ENFORCE_INTEGRITY) {
-        if (!once) {
-            logToDmesg("integrity enforcement suppressed; not rebooting");
-        }
-    } else if (rebootToSafeMode) {
-        if (getProperty("persist.sys.safemode") == "1") {
-            if (!once) {
-                logToDmesg("integrity enforcement suppressed; in safe mode");
-            }
-            return;
-        }
-
-        logToDmesg("enforcing integrity; rebooting to safe mode");
-        property_set("persist.sys.safemode", "1");
-
-        std::string buildDate = getProperty("ro.build.date.utc");
-        if (!buildDate.empty()) {
-            property_set("persist.sys.audit_safemode", buildDate.c_str());
-        }
-
-        property_set("sys.powerctl", "reboot");
-    } else {
-        logToDmesg("enforcing integrity: rebooting to recovery");
-        property_set("sys.powerctl", "reboot,recovery");
-    }
-}
-
 int LogAudit::logPrint(const char *fmt, ...) {
     if (fmt == NULL) {
         return -EINVAL;
@@ -152,31 +97,7 @@
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
 
-    bool loaded = strstr(str, " policy loaded ");
-
-    if (loaded) {
-        if (policyLoaded) {
-            // SELinux policy changes are not allowed
-            enforceIntegrity();
-        } else {
-            logToDmesg("policy loaded");
-            policyLoaded = true;
-        }
-    }
-
-    // Note: The audit log can include untrusted strings, but those containing
-    // "a control character, unprintable character, double quote mark, or a
-    // space" are hex encoded. The space character before the search term is
-    // therefore needed to prevent denial of service. Do not remove the space.
-    bool permissive = strstr(str, " enforcing=0") ||
-                      strstr(str, " permissive=1");
-
-    if (permissive) {
-        // SELinux in permissive mode is not allowed
-        enforceIntegrity();
-    }
-
-    bool info = loaded || permissive;
+    bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
     if ((fdDmesg >= 0) && initialized) {
         struct iovec iov[3];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 3a84541..ab30e28 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -27,15 +27,12 @@
     LogBuffer *logbuf;
     LogReader *reader;
     int fdDmesg;
-    bool policyLoaded;
-    bool rebootToSafeMode;
     bool initialized;
 
 public:
     LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
     int log(char *buf, size_t len);
     bool isMonotonic() { return logbuf->isMonotonic(); }
-    void allowSafeMode(bool allow = true) { rebootToSafeMode = allow; }
 
 protected:
     virtual bool onDataAvailable(SocketClient *cli);
@@ -44,9 +41,6 @@
     static int getLogSocket();
     int logPrint(const char *fmt, ...)
         __attribute__ ((__format__ (__printf__, 2, 3)));
-    void logToDmesg(const std::string& str);
-    std::string getProperty(const std::string& name);
-    void enforceIntegrity();
 };
 
 #endif
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 0495463..ef6c1ae 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -26,6 +26,7 @@
 #include <syslog.h>
 
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
 
 #include "LogBuffer.h"
 #include "LogKlog.h"
@@ -589,7 +590,12 @@
     // Parse pid, tid and uid
     const pid_t pid = sniffPid(p, len - (p - buf));
     const pid_t tid = pid;
-    const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
+    uid_t uid = AID_ROOT;
+    if (pid) {
+        logbuf->lock();
+        uid = logbuf->pidToUid(pid);
+        logbuf->unlock();
+    }
 
     // Parse (rules at top) to pull out a tag from the incoming kernel message.
     // Some may view the following as an ugly heuristic, the desire is to
diff --git a/logd/README.property b/logd/README.property
index 10694d8..791b1d5 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -1,6 +1,7 @@
 The properties that logd and friends react to are:
 
 name                       type default  description
+ro.logd.auditd             bool   true   Enable selinux audit daemon
 ro.logd.auditd.dmesg       bool   true   selinux audit messages duplicated and
                                          sent on to dmesg log
 persist.logd.security      bool   false  Enable security buffer.
diff --git a/logd/main.cpp b/logd/main.cpp
index b69927d..77a6973 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -218,7 +218,6 @@
 static sem_t reinit;
 static bool reinit_running = false;
 static LogBuffer *logBuf = NULL;
-static LogAudit *logAudit = NULL;
 
 static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) {
 
@@ -269,10 +268,6 @@
             logBuf->init();
             logBuf->initPrune(NULL);
         }
-
-        if (logAudit) {
-            logAudit->allowSafeMode();
-        }
     }
 
     return NULL;
@@ -493,19 +488,25 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
-    logAudit = new LogAudit(logBuf, reader,
-                            property_get_bool("logd.auditd.dmesg",
-                                              BOOL_DEFAULT_TRUE |
-                                              BOOL_DEFAULT_FLAG_PERSIST)
-                                ? fdDmesg
-                                : -1);
+    bool auditd = property_get_bool("logd.auditd",
+                                    BOOL_DEFAULT_TRUE |
+                                    BOOL_DEFAULT_FLAG_PERSIST);
+    LogAudit *al = NULL;
+    if (auditd) {
+        al = new LogAudit(logBuf, reader,
+                          property_get_bool("logd.auditd.dmesg",
+                                            BOOL_DEFAULT_TRUE |
+                                            BOOL_DEFAULT_FLAG_PERSIST)
+                              ? fdDmesg
+                              : -1);
+    }
 
     LogKlog *kl = NULL;
     if (klogd) {
-        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, logAudit != NULL);
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
     }
 
-    readDmesg(logAudit, kl);
+    readDmesg(al, kl);
 
     // failure is an option ... messages are in dmesg (required by standard)
 
@@ -513,9 +514,8 @@
         delete kl;
     }
 
-    if (logAudit && logAudit->startListener()) {
-        delete logAudit;
-        logAudit = NULL;
+    if (al && al->startListener()) {
+        delete al;
     }
 
     TEMP_FAILURE_RETRY(pause());
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 2014374..301ede9 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -213,9 +213,15 @@
         version = 1;
         break;
 
-    case sizeof(msg->entry_v2):
+    case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
         if (version == 0) {
-            version = 2;
+            version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
+        }
+        break;
+
+    case sizeof(msg->entry_v4):
+        if (version == 0) {
+            version = 4;
         }
         break;
     }
@@ -269,6 +275,11 @@
     unsigned int len = msg->entry.len;
     fprintf(stderr, "msg[%u]={", len);
     unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
+    if (!cp) {
+        static const unsigned char garbage[] = "<INVALID>";
+        cp = const_cast<unsigned char *>(garbage);
+        len = strlen(reinterpret_cast<const char *>(garbage));
+    }
     while(len) {
         unsigned char *p = cp;
         while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
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 b96ff4c..a68cb78 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
@@ -95,11 +87,14 @@
 
     # Symlink to keep legacy apps working in multi-user world
     symlink /storage/self/primary /sdcard
+    symlink /storage/self/primary /mnt/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
@@ -173,21 +168,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
 
 
@@ -283,6 +289,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
@@ -319,8 +329,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
@@ -357,16 +365,24 @@
     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
+    mkdir /data/misc/profman 0770 system shell
 
     # 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
@@ -375,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
@@ -395,18 +413,32 @@
     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
+    mkdir /data/system/users 0775 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
@@ -518,13 +550,6 @@
     class_start main
     class_start late_start
 
-on property:vold.decrypt=trigger_default_encryption
-    start defaultcrypto
-
-on property:vold.decrypt=trigger_encryption
-    start surfaceflinger
-    start encrypt
-
 on property:sys.init_log_level=*
     loglevel ${sys.init_log_level}
 
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 4b76383..807f9bc 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -4,6 +4,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 2efd8e2..10fa915 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -4,6 +4,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
@@ -13,4 +15,4 @@
     priority -20
     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 342a561..13ffd7e 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -4,6 +4,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 b3ac7b0..1164ac5 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -4,6 +4,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
@@ -13,4 +15,4 @@
     priority -20
     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/sdcard/fuse.cpp b/sdcard/fuse.cpp
index 47e4257..6a972ea 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -20,6 +20,12 @@
 
 #include <android-base/logging.h>
 
+/* FUSE_CANONICAL_PATH is not currently upstreamed */
+#define FUSE_CANONICAL_PATH 2016
+
+#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
+#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
+
 #define FUSE_UNKNOWN_INO 0xffffffff
 
 /* Pseudo-error constant used to indicate that no fuse status is needed
@@ -117,7 +123,7 @@
 
     ssize_t pathlen = 0;
     if (node->parent && node->graft_path == NULL) {
-        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
+        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
         if (pathlen < 0) {
             return -1;
         }
@@ -1008,13 +1014,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;
 }
@@ -1178,13 +1178,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;
 }
@@ -1267,11 +1261,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;
@@ -1279,6 +1268,35 @@
     return NO_STATUS;
 }
 
+static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    int len;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] CANONICAL_PATH @ " << std::hex << hdr->nodeid
+               << std::dec << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+        return -EACCES;
+    }
+    len = strlen(path);
+    if (len + 1 > PATH_MAX)
+        len = PATH_MAX - 1;
+    path[PATH_MAX - 1] = 0;
+    fuse_reply(fuse, hdr->unique, path, len + 1);
+    return NO_STATUS;
+}
+
+
 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const void *data, size_t data_len)
 {
@@ -1394,6 +1412,10 @@
         return handle_init(fuse, handler, hdr, req);
     }
 
+    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
+        return handle_canonical_path(fuse, handler, hdr);
+    }
+
     default: {
         DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
                    << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;