Merge "init: usb: disable usb function switch until adbd is ready"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b3661e4..3cad427 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -56,3 +56,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.$(TARGET_DEVICE).so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so)
diff --git a/adb/Android.mk b/adb/Android.mk
index f1d3bee..71d5aaf 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -58,6 +58,7 @@
 
 LIBADB_TEST_SRCS := \
     adb_io_test.cpp \
+    adb_listeners_test.cpp \
     adb_utils_test.cpp \
     fdevent_test.cpp \
     socket_test.cpp \
@@ -108,7 +109,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -131,7 +132,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
 
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
 LOCAL_MULTILIB := first
@@ -151,7 +152,7 @@
     shell_service_test.cpp \
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils_static libcrypto_static
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
@@ -191,6 +192,7 @@
 LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_STATIC_LIBRARIES := \
     libadb \
+    libcrypto_utils_static \
     libcrypto_static \
     libcutils \
     libdiagnose_usb \
@@ -219,7 +221,7 @@
 LOCAL_SRC_FILES := test_track_devices.cpp
 LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
+LOCAL_STATIC_LIBRARIES := libadb libcrypto_utils_static libcrypto_static libcutils
 LOCAL_LDLIBS += -lrt -ldl -lpthread
 include $(BUILD_HOST_EXECUTABLE)
 endif
@@ -271,6 +273,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libadb \
     libbase \
+    libcrypto_utils_static \
     libcrypto_static \
     libdiagnose_usb \
     liblog \
@@ -342,11 +345,11 @@
     libfec_rs \
     libselinux \
     liblog \
-    libmincrypt \
     libext4_utils_static \
     libsquashfs_utils \
     libcutils \
     libbase \
+    libcrypto_utils_static \
     libcrypto_static \
     libminijail
 
diff --git a/adb/adb.cpp b/adb/adb.cpp
index cb54d04..11e9c68 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -353,7 +353,8 @@
                 send_auth_publickey(t);
             }
         } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
-            if (adb_auth_verify(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 {
@@ -954,18 +955,25 @@
 
         std::string error;
         InstallStatus r;
+        int resolved_tcp_port = 0;
         if (kill_forward) {
             r = remove_listener(pieces[0].c_str(), transport);
         } else {
-            r = install_listener(pieces[0], pieces[1].c_str(), transport,
-                                 no_rebind, &error);
+            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
+                                 &resolved_tcp_port, &error);
         }
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
-            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            // On the host: 1st OKAY is connect, 2nd OKAY is status.
             SendOkay(reply_fd);
 #endif
             SendOkay(reply_fd);
+
+            // If a TCP port was resolved, send the actual port number back.
+            if (resolved_tcp_port != 0) {
+                SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
+            }
+
             return 1;
         }
 
@@ -1134,6 +1142,13 @@
         /* we don't even need to send a reply */
         return 0;
     }
+
+    if (!strcmp(service, "reconnect")) {
+        if (s->transport != nullptr) {
+            kick_transport(s->transport);
+        }
+        return SendOkay(reply_fd, "done");
+    }
 #endif // ADB_HOST
 
     int ret = handle_forward_request(service, type, serial, reply_fd);
diff --git a/adb/adb.h b/adb/adb.h
index 59644d4..cb38e61 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 35
+#define ADB_SERVER_VERSION 37
 
 class atransport;
 struct usb_handle;
@@ -116,29 +116,6 @@
     kCsUnauthorized,
 };
 
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
-    alistener *next;
-    alistener *prev;
-
-    fdevent fde;
-    int fd;
-
-    char *local_name;
-    char *connect_to;
-    atransport *transport;
-    adisconnect  disconnect;
-};
-
 
 void print_packet(const char *label, apacket *p);
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index a13604a..1ab5e1a 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -43,9 +43,15 @@
 void *adb_auth_nextkey(void *current);
 int adb_auth_get_userkey(unsigned char *data, size_t len);
 
-static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
-static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
-static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+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) {}
 
 #else // !ADB_HOST
 
@@ -54,12 +60,15 @@
     return 0;
 }
 static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) {
+    return 0;
+}
 
 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, uint8_t* sig, int siglen);
+int adb_auth_verify(uint8_t* token, size_t token_size,
+                    uint8_t* sig, int siglen);
 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 128c3df..415ab8e 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -23,10 +23,14 @@
 #include <stdio.h>
 #include <string.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 "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
 
 #include "adb.h"
 #include "fdevent.h"
@@ -34,7 +38,7 @@
 
 struct adb_public_key {
     struct listnode node;
-    RSAPublicKey key;
+    RSA* key;
 };
 
 static const char *key_paths[] = {
@@ -66,9 +70,8 @@
     }
 
     while (fgets(buf, sizeof(buf), f)) {
-        /* Allocate 4 extra bytes to decode the base64 data in-place */
         auto key = reinterpret_cast<adb_public_key*>(
-            calloc(1, sizeof(adb_public_key) + 4));
+            calloc(1, sizeof(adb_public_key)));
         if (key == nullptr) {
             D("Can't malloc key");
             break;
@@ -78,15 +81,18 @@
         if (sep)
             *sep = '\0';
 
-        ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
-        if (ret != sizeof(key->key)) {
+        // 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;
         }
 
-        if (key->key.len != RSANUMWORDS) {
-            D("%s: Invalid key len %d", file, key->key.len);
+        if (!android_pubkey_decode(keybuf, ret, &key->key)) {
+            D("%s: Failed to parse key", file);
             free(key);
             continue;
         }
@@ -104,7 +110,9 @@
     while (!list_empty(list)) {
         item = list_head(list);
         list_remove(item);
-        free(node_to_item(item, struct adb_public_key, node));
+        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
+        RSA_free(key->key);
+        free(key);
     }
 }
 
@@ -139,20 +147,17 @@
     return ret * token_size;
 }
 
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
+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;
 
-    if (siglen != RSANUMBYTES)
-        return 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(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
+        ret = RSA_verify(NID_sha1, token, token_size, sig, siglen, key->key);
         if (ret)
             break;
     }
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 8f154fd..ab641eb 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -37,14 +37,9 @@
 
 #include "adb.h"
 
-/* HACK: we need the RSAPublicKey struct
- * but RSA_verify conflits with openssl */
-#define RSA_verify RSA_verify_mincrypt
-#include "mincrypt/rsa.h"
-#undef RSA_verify
-
 #include <android-base/errors.h>
 #include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <cutils/list.h>
 
 #include <openssl/evp.h>
@@ -68,54 +63,6 @@
 static struct listnode key_list;
 
 
-/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
-static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
-{
-    int ret = 1;
-    unsigned int i;
-
-    BN_CTX* ctx = BN_CTX_new();
-    BIGNUM* r32 = BN_new();
-    BIGNUM* rr = BN_new();
-    BIGNUM* r = BN_new();
-    BIGNUM* rem = BN_new();
-    BIGNUM* n = BN_new();
-    BIGNUM* n0inv = BN_new();
-
-    if (RSA_size(rsa) != RSANUMBYTES) {
-        ret = 0;
-        goto out;
-    }
-
-    BN_set_bit(r32, 32);
-    BN_copy(n, rsa->n);
-    BN_set_bit(r, RSANUMWORDS * 32);
-    BN_mod_sqr(rr, r, n, ctx);
-    BN_div(NULL, rem, n, r32, ctx);
-    BN_mod_inverse(n0inv, rem, r32, ctx);
-
-    pkey->len = RSANUMWORDS;
-    pkey->n0inv = 0 - BN_get_word(n0inv);
-    for (i = 0; i < RSANUMWORDS; i++) {
-        BN_div(rr, rem, rr, r32, ctx);
-        pkey->rr[i] = BN_get_word(rem);
-        BN_div(n, rem, n, r32, ctx);
-        pkey->n[i] = BN_get_word(rem);
-    }
-    pkey->exponent = BN_get_word(rsa->e);
-
-out:
-    BN_free(n0inv);
-    BN_free(n);
-    BN_free(rem);
-    BN_free(r);
-    BN_free(rr);
-    BN_free(r32);
-    BN_CTX_free(ctx);
-
-    return ret;
-}
-
 static void get_user_info(char *buf, size_t len)
 {
     char hostname[1024], username[1024];
@@ -156,53 +103,55 @@
 
 static int write_public_keyfile(RSA *private_key, const char *private_key_path)
 {
-    RSAPublicKey pkey;
+    uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+    uint8_t* base64_key_data = nullptr;
+    size_t base64_key_length = 0;
     FILE *outfile = NULL;
     char path[PATH_MAX], info[MAX_PAYLOAD_V1];
-    uint8_t* encoded = nullptr;
-    size_t encoded_length;
     int ret = 0;
 
-    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
-        (int)sizeof(path)) {
-        D("Path too long while writing public key");
-        return 0;
-    }
-
-    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
+    if (!android_pubkey_encode(private_key, binary_key_data,
+                               sizeof(binary_key_data))) {
         D("Failed to convert to publickey");
-        return 0;
-    }
-
-    outfile = fopen(path, "w");
-    if (!outfile) {
-        D("Failed to open '%s'", path);
-        return 0;
+        goto out;
     }
 
     D("Writing public key to '%s'", path);
 
 #if defined(OPENSSL_IS_BORINGSSL)
-    if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
+    if (!EVP_EncodedLength(&base64_key_length, sizeof(binary_key_data))) {
         D("Public key too large to base64 encode");
         goto out;
     }
 #else
     /* While we switch from OpenSSL to BoringSSL we have to implement
      * |EVP_EncodedLength| here. */
-    encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
+    base64_key_length = 1 + ((sizeof(binary_key_data) + 2) / 3 * 4);
 #endif
 
-    encoded = new uint8_t[encoded_length];
-    if (encoded == nullptr) {
+    base64_key_data = new uint8_t[base64_key_length];
+    if (base64_key_data == nullptr) {
         D("Allocation failure");
         goto out;
     }
 
-    encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
+    base64_key_length = EVP_EncodeBlock(base64_key_data, binary_key_data,
+                                        sizeof(binary_key_data));
     get_user_info(info, sizeof(info));
 
-    if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
+    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
+        (int)sizeof(path)) {
+        D("Path too long while writing public key");
+        goto out;
+    }
+
+    outfile = fopen(path, "w");
+    if (!outfile) {
+        D("Failed to open '%s'", path);
+        goto out;
+    }
+
+    if (fwrite(base64_key_data, base64_key_length, 1, outfile) != 1 ||
         fwrite(info, strlen(info), 1, outfile) != 1) {
         D("Write error while writing public key");
         goto out;
@@ -214,7 +163,7 @@
     if (outfile != NULL) {
         fclose(outfile);
     }
-    delete[] encoded;
+    delete[] base64_key_data;
     return ret;
 }
 
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index d29c08e..a27dd47 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -158,7 +158,8 @@
         }
     }
 
-    if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) {
+    if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") &&
+        switch_socket_transport(fd, error)) {
         return -1;
     }
 
@@ -168,9 +169,11 @@
         return -1;
     }
 
-    if (!adb_status(fd, error)) {
-        adb_close(fd);
-        return -1;
+    if (service != "reconnect") {
+        if (!adb_status(fd, error)) {
+            adb_close(fd);
+            return -1;
+        }
     }
 
     D("_adb_connect: return fd %d", fd);
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 21a82e8..611b239 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -37,7 +37,13 @@
 // fds far from the range that open() returns. But all of that might defeat the
 // purpose of the tests.
 
-TEST(io, ReadFdExactly_whole) {
+#if defined(_WIN32)
+#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y)
+#else
+#define POSIX_TEST TEST
+#endif
+
+POSIX_TEST(io, ReadFdExactly_whole) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -51,7 +57,7 @@
   EXPECT_STREQ(expected, buf);
 }
 
-TEST(io, ReadFdExactly_eof) {
+POSIX_TEST(io, ReadFdExactly_eof) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -65,7 +71,7 @@
   EXPECT_EQ(0, errno) << strerror(errno);
 }
 
-TEST(io, ReadFdExactly_partial) {
+POSIX_TEST(io, ReadFdExactly_partial) {
   const char input[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -82,7 +88,7 @@
   EXPECT_STREQ(expected.c_str(), buf);
 }
 
-TEST(io, WriteFdExactly_whole) {
+POSIX_TEST(io, WriteFdExactly_whole) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -97,7 +103,7 @@
   EXPECT_STREQ(expected, s.c_str());
 }
 
-TEST(io, WriteFdExactly_partial) {
+POSIX_TEST(io, WriteFdExactly_partial) {
   const char buf[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -114,7 +120,7 @@
   EXPECT_EQ(expected, s);
 }
 
-TEST(io, WriteFdExactly_ENOSPC) {
+POSIX_TEST(io, WriteFdExactly_ENOSPC) {
     int fd = open("/dev/full", O_WRONLY);
     ASSERT_NE(-1, fd);
 
@@ -123,7 +129,7 @@
     ASSERT_EQ(ENOSPC, errno);
 }
 
-TEST(io, WriteFdExactly_string) {
+POSIX_TEST(io, WriteFdExactly_string) {
   const char str[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -137,7 +143,7 @@
   EXPECT_STREQ(str, s.c_str());
 }
 
-TEST(io, WriteFdFmt) {
+POSIX_TEST(io, WriteFdFmt) {
     TemporaryFile tf;
     ASSERT_NE(-1, tf.fd);
 
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index e8c2338..f54603c 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -20,18 +20,55 @@
 #include <stdlib.h>
 
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/sockets.h>
 
 #include "sysdeps.h"
 #include "transport.h"
 
-int gListenAll = 0; /* Not static because it is used in commandline.c. */
+// Not static because it is used in commandline.c.
+int gListenAll = 0;
 
-static alistener listener_list = {
-    .next = &listener_list,
-    .prev = &listener_list,
+// A listener is an entity which binds to a local port and, upon receiving a connection on that
+// port, creates an asocket to connect the new local connection to a specific remote service.
+//
+// TODO: some listeners read from the new connection to determine what exact service to connect to
+// on the far side.
+class alistener {
+  public:
+    alistener(const std::string& _local_name, const std::string& _connect_to);
+    ~alistener();
+
+    fdevent fde;
+    int fd = -1;
+
+    std::string local_name;
+    std::string connect_to;
+    atransport* transport = nullptr;
+    adisconnect disconnect;
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(alistener);
 };
 
+alistener::alistener(const std::string& _local_name, const std::string& _connect_to)
+    : local_name(_local_name), connect_to(_connect_to) {
+}
+
+alistener::~alistener() {
+    // Closes the corresponding fd.
+    fdevent_remove(&fde);
+
+    if (transport) {
+        transport->RemoveDisconnect(&disconnect);
+    }
+}
+
+// listener_list retains ownership of all created alistener objects. Removing an alistener from
+// this list will cause it to be deleted.
+typedef std::list<std::unique_ptr<alistener>> ListenerList;
+static ListenerList& listener_list = *new ListenerList();
+
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
         sockaddr_storage ss;
@@ -73,7 +110,7 @@
         s = create_local_socket(fd);
         if (s) {
             s->transport = listener->transport;
-            connect_to_remote(s, listener->connect_to);
+            connect_to_remote(s, listener->connect_to.c_str());
             return;
         }
 
@@ -81,66 +118,63 @@
     }
 }
 
-static void free_listener(alistener*  l)
-{
-    if (l->next) {
-        l->next->prev = l->prev;
-        l->prev->next = l->next;
-        l->next = l->prev = l;
-    }
-
-    // closes the corresponding fd
-    fdevent_remove(&l->fde);
-
-    if (l->local_name)
-        free((char*)l->local_name);
-
-    if (l->connect_to)
-        free((char*)l->connect_to);
-
-    if (l->transport) {
-        l->transport->RemoveDisconnect(&l->disconnect);
-    }
-    free(l);
-}
-
+// Called as a transport disconnect function. |arg| is the raw alistener*.
 static void listener_disconnect(void* arg, atransport*) {
-    alistener* listener = reinterpret_cast<alistener*>(arg);
-    listener->transport = nullptr;
-    free_listener(listener);
-}
-
-static int local_name_to_fd(const char* name, std::string* error) {
-    if (!strncmp("tcp:", name, 4)) {
-        int port = atoi(name + 4);
-        if (gListenAll > 0) {
-            return network_inaddr_any_server(port, SOCK_STREAM, error);
-        } else {
-            return network_loopback_server(port, SOCK_STREAM, error);
+    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+        if (iter->get() == arg) {
+            (*iter)->transport = nullptr;
+            listener_list.erase(iter);
+            return;
         }
     }
+}
+
+int local_name_to_fd(alistener* listener, int* resolved_tcp_port, std::string* error) {
+    if (android::base::StartsWith(listener->local_name, "tcp:")) {
+        int requested_port = atoi(&listener->local_name[4]);
+        int sock = -1;
+        if (gListenAll > 0) {
+            sock = network_inaddr_any_server(requested_port, SOCK_STREAM, error);
+        } else {
+            sock = network_loopback_server(requested_port, SOCK_STREAM, error);
+        }
+
+        // If the caller requested port 0, update the listener name with the resolved port.
+        if (sock >= 0 && requested_port == 0) {
+            int local_port = adb_socket_get_local_port(sock);
+            if (local_port > 0) {
+                listener->local_name = android::base::StringPrintf("tcp:%d", local_port);
+                if (resolved_tcp_port != nullptr) {
+                    *resolved_tcp_port = local_port;
+                }
+            }
+        }
+
+        return sock;
+    }
 #if !defined(_WIN32)  // No Unix-domain sockets on Windows.
-    // It's nonsensical to support the "reserved" space on the adb host side
-    if (!strncmp(name, "local:", 6)) {
-        return network_local_server(name + 6,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
-    } else if (!strncmp(name, "localabstract:", 14)) {
-        return network_local_server(name + 14,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
-    } else if (!strncmp(name, "localfilesystem:", 16)) {
-        return network_local_server(name + 16,
-                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
+    // It's nonsensical to support the "reserved" space on the adb host side.
+    if (android::base::StartsWith(listener->local_name, "local:")) {
+        return network_local_server(&listener->local_name[6], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+                                    SOCK_STREAM, error);
+    } else if (android::base::StartsWith(listener->local_name, "localabstract:")) {
+        return network_local_server(&listener->local_name[14], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+                                    SOCK_STREAM, error);
+    } else if (android::base::StartsWith(listener->local_name, "localfilesystem:")) {
+        return network_local_server(&listener->local_name[16], ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
+                                    SOCK_STREAM, error);
     }
 
 #endif
-    *error = android::base::StringPrintf("unknown local portname '%s'", name);
+    *error = android::base::StringPrintf("unknown local portname '%s'",
+                                         listener->local_name.c_str());
     return -1;
 }
 
 // Write the list of current listeners (network redirections) into a string.
 std::string format_listeners() {
     std::string result;
-    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+    for (auto& l : listener_list) {
         // Ignore special listeners like those for *smartsocket*
         if (l->connect_to[0] == '*') {
             continue;
@@ -149,65 +183,51 @@
         // Entries from "adb reverse" have no serial.
         android::base::StringAppendF(&result, "%s %s %s\n",
                                      l->transport->serial ? l->transport->serial : "(reverse)",
-                                     l->local_name, l->connect_to);
+                                     l->local_name.c_str(), l->connect_to.c_str());
     }
     return result;
 }
 
-InstallStatus remove_listener(const char *local_name, atransport* transport) {
-    alistener *l;
-
-    for (l = listener_list.next; l != &listener_list; l = l->next) {
-        if (!strcmp(local_name, l->local_name)) {
-            free_listener(l);
+InstallStatus remove_listener(const char* local_name, atransport* transport) {
+    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+        if (local_name == (*iter)->local_name) {
+            listener_list.erase(iter);
             return INSTALL_STATUS_OK;
         }
     }
     return INSTALL_STATUS_LISTENER_NOT_FOUND;
 }
 
-void remove_all_listeners(void)
-{
-    alistener *l, *l_next;
-    for (l = listener_list.next; l != &listener_list; l = l_next) {
-        l_next = l->next;
+void remove_all_listeners() {
+    auto iter = listener_list.begin();
+    while (iter != listener_list.end()) {
         // Never remove smart sockets.
-        if (l->connect_to[0] == '*')
-            continue;
-        free_listener(l);
+        if ((*iter)->connect_to[0] == '*') {
+            ++iter;
+        } else {
+            iter = listener_list.erase(iter);
+        }
     }
 }
 
-InstallStatus install_listener(const std::string& local_name,
-                                  const char *connect_to,
-                                  atransport* transport,
-                                  int no_rebind,
-                                  std::string* error)
-{
-    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+                               atransport* transport, int no_rebind, int* resolved_tcp_port,
+                               std::string* error) {
+    for (auto& l : listener_list) {
         if (local_name == l->local_name) {
-            char* cto;
-
-            /* can't repurpose a smartsocket */
+            // Can't repurpose a smartsocket.
             if(l->connect_to[0] == '*') {
                 *error = "cannot repurpose smartsocket";
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
-            /* can't repurpose a listener if 'no_rebind' is true */
+            // Can't repurpose a listener if 'no_rebind' is true.
             if (no_rebind) {
                 *error = "cannot rebind";
                 return INSTALL_STATUS_CANNOT_REBIND;
             }
 
-            cto = strdup(connect_to);
-            if(cto == 0) {
-                *error = "cannot duplicate string";
-                return INSTALL_STATUS_INTERNAL_ERROR;
-            }
-
-            free((void*) l->connect_to);
-            l->connect_to = cto;
+            l->connect_to = connect_to;
             if (l->transport != transport) {
                 l->transport->RemoveDisconnect(&l->disconnect);
                 l->transport = transport;
@@ -217,54 +237,29 @@
         }
     }
 
-    alistener* listener = reinterpret_cast<alistener*>(
-        calloc(1, sizeof(alistener)));
-    if (listener == nullptr) {
-        goto nomem;
-    }
+    std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));
 
-    listener->local_name = strdup(local_name.c_str());
-    if (listener->local_name == nullptr) {
-        goto nomem;
-    }
-
-    listener->connect_to = strdup(connect_to);
-    if (listener->connect_to == nullptr) {
-        goto nomem;
-    }
-
-    listener->fd = local_name_to_fd(listener->local_name, error);
+    listener->fd = local_name_to_fd(listener.get(), resolved_tcp_port, error);
     if (listener->fd < 0) {
-        free(listener->local_name);
-        free(listener->connect_to);
-        free(listener);
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
     close_on_exec(listener->fd);
-    if (!strcmp(listener->connect_to, "*smartsocket*")) {
-        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
-                        listener);
+    if (listener->connect_to == "*smartsocket*") {
+        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
     } else {
-        fdevent_install(&listener->fde, listener->fd, listener_event_func,
-                        listener);
+        fdevent_install(&listener->fde, listener->fd, listener_event_func, listener.get());
     }
     fdevent_set(&listener->fde, FDE_READ);
 
-    listener->next = &listener_list;
-    listener->prev = listener_list.prev;
-    listener->next->prev = listener;
-    listener->prev->next = listener;
     listener->transport = transport;
 
     if (transport) {
-        listener->disconnect.opaque = listener;
+        listener->disconnect.opaque = listener.get();
         listener->disconnect.func   = listener_disconnect;
         transport->AddDisconnect(&listener->disconnect);
     }
-    return INSTALL_STATUS_OK;
 
-nomem:
-    fatal("cannot allocate listener");
-    return INSTALL_STATUS_INTERNAL_ERROR;
+    listener_list.push_back(std::move(listener));
+    return INSTALL_STATUS_OK;
 }
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index fa98eed..8eba00a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -21,6 +21,8 @@
 
 #include <string>
 
+#include <android-base/macros.h>
+
 // error/status codes for install_listener.
 enum InstallStatus {
   INSTALL_STATUS_OK = 0,
@@ -30,10 +32,8 @@
   INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
 };
 
-InstallStatus install_listener(const std::string& local_name,
-                               const char* connect_to,
-                               atransport* transport,
-                               int no_rebind,
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+                               atransport* transport, int no_rebind, int* resolved_tcp_port,
                                std::string* error);
 
 std::string format_listeners();
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
new file mode 100644
index 0000000..b697769
--- /dev/null
+++ b/adb/adb_listeners_test.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_listeners.h"
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+// Returns true if the given listener is present in format_listeners(). Empty parameters will
+// be ignored.
+static bool listener_is_installed(const std::string& serial, const std::string& source,
+                                  const std::string& dest) {
+    // format_listeners() gives lines of "<serial> <source> <dest>\n".
+    for (const std::string& line : android::base::Split(format_listeners(), "\n")) {
+        std::vector<std::string> info = android::base::Split(line, " ");
+        if (info.size() == 3 &&
+                (serial.empty() || info[0] == serial) &&
+                (source.empty() || info[1] == source) &&
+                (dest.empty() || info[2] == dest)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+class AdbListenersTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        // We don't need an fdevent loop, but adding/removing listeners must be done from the
+        // fdevent thread if one exists. Since previously run tests may have created an fdevent
+        // thread, we need to reset to prevent the thread check.
+        fdevent_reset();
+    }
+
+    void TearDown() override {
+        // Clean up any listeners that may have been installed.
+        remove_all_listeners();
+
+        // Make sure we didn't leave any dangling events.
+        ASSERT_EQ(0u, fdevent_installed_count());
+    }
+
+  protected:
+    atransport transport_;
+};
+
+TEST_F(AdbListenersTest, test_install_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_rebind) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9001"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_no_rebind) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, true, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_CANNOT_REBIND,
+              install_listener("tcp:9000", "tcp:9001", &transport_, true, nullptr, &error));
+    ASSERT_FALSE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_tcp_port_0) {
+    int port = 0;
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:0", "tcp:9000", &transport_, true, &port, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", android::base::StringPrintf("tcp:%d", port), "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK, remove_listener("tcp:9000", &transport_));
+    ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_remove_nonexistent_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_LISTENER_NOT_FOUND, remove_listener("tcp:1", &transport_));
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_all_listeners) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    remove_all_listeners();
+    ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_transport_disconnect) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    transport_.RunDisconnects();
+    ASSERT_TRUE(format_listeners().empty());
+}
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 3333fc6..5d4755f 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -27,6 +27,7 @@
 #include <algorithm>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -230,3 +231,26 @@
     return true;
 }
 #endif
+
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+                               std::string* error) {
+    if (android::base::StartsWith(source, "tcp:")) {
+        // The source port may be 0 to allow the system to select an open port.
+        int port;
+        if (!android::base::ParseInt(&source[4], &port) || port < 0) {
+            *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]);
+            return false;
+        }
+    }
+
+    if (android::base::StartsWith(dest, "tcp:")) {
+        // The destination port must be > 0.
+        int port;
+        if (!android::base::ParseInt(&dest[4], &port) || port <= 0) {
+            *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]);
+            return false;
+        }
+    }
+
+    return true;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 89fcd66..abf481b 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -43,6 +43,13 @@
 
 extern int adb_close(int fd);
 
+// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
+// |error| and returns false.
+// Currently this only checks "tcp:" targets. Additional checking could be added for other targets
+// if needed.
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+                               std::string* error);
+
 // Helper to automatically close an FD when it goes out of scope.
 class ScopedFd {
   public:
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index f1ebaa1..aabc5d7 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -149,3 +149,24 @@
   ASSERT_EQ(0, adb_close(fd));
 }
 #endif
+
+TEST(adb_utils, test_forward_targets_are_valid) {
+    std::string error;
+
+    // Source port can be >= 0.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:-1", "tcp:9000", &error));
+    EXPECT_TRUE(forward_targets_are_valid("tcp:0", "tcp:9000", &error));
+    EXPECT_TRUE(forward_targets_are_valid("tcp:8000", "tcp:9000", &error));
+
+    // Destination port must be >0.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:-1", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:0", &error));
+
+    // Port must be a number.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:a", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:22x", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:a", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:22x", &error));
+}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 27b7109..65640ad 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -117,7 +117,7 @@
 
     std::string error;
     std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
-    if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+    if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
         fatal("could not install *smartsocket* listener: %s", error.c_str());
     }
 
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index a856672..28dbb78 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -126,7 +126,7 @@
         "                                    <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
         "  adb forward <local> <remote> - forward socket connections\n"
         "                                 forward specs are one of: \n"
-        "                                   tcp:<port>\n"
+        "                                   tcp:<port> (<local> may be \"tcp:0\" to pick any open port)\n"
         "                                   localabstract:<unix domain socket name>\n"
         "                                   localreserved:<unix domain socket name>\n"
         "                                   localfilesystem:<unix domain socket name>\n"
@@ -140,7 +140,7 @@
         "  adb reverse --list           - list all reverse socket connections from device\n"
         "  adb reverse <remote> <local> - reverse socket connections\n"
         "                                 reverse specs are one of:\n"
-        "                                   tcp:<port>\n"
+        "                                   tcp:<port> (<remote> may be \"tcp:0\" to pick any open port)\n"
         "                                   localabstract:<unix domain socket name>\n"
         "                                   localreserved:<unix domain socket name>\n"
         "                                   localfilesystem:<unix domain socket name>\n"
@@ -239,6 +239,9 @@
         "  - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
         "    is updated.\n"
         "\n"
+        "internal debugging:\n"
+        "  adb reconnect                  Kick current connection from host side and make it reconnect.\n"
+        "  adb reconnect device           Kick current connection from device side and make it reconnect.\n"
         "environment variables:\n"
         "  ADB_TRACE                    - Print debug information. A comma separated list of the following values\n"
         "                                 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
@@ -1025,50 +1028,40 @@
 #endif /* !defined(_WIN32) */
 }
 
-static bool check_wait_for_device_syntax(const char* service) {
-    // TODO: when we have libc++ for Windows, use a regular expression instead.
-    // wait-for-((any|local|usb)-)?(bootloader|device|recovery|sideload)
-
-    char type[20 + 1]; // sscanf's %20[...] doesn't include the NUL.
-    char state[20 + 1];
-    int length = 0;
-    if (sscanf(service, "wait-for-%20[a-z]-%20[a-z]%n", type, state, &length) < 2 ||
-        length != static_cast<int>(strlen(service))) {
+static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+    std::vector<std::string> components = android::base::Split(service, "-");
+    if (components.size() < 3 || components.size() > 4) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
         return false;
     }
 
-    if (strcmp(type, "any") != 0 && strcmp(type, "local") != 0 && strcmp(type, "usb") != 0) {
-        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n", type);
-        return false;
-    }
-    if (strcmp(state, "bootloader") != 0 && strcmp(state, "device") != 0 &&
-        strcmp(state, "recovery") != 0 && strcmp(state, "sideload") != 0) {
-        fprintf(stderr, "adb: unknown state %s; "
-                        "expected 'bootloader', 'device', 'recovery', or 'sideload'\n", state);
-        return false;
-    }
-    return true;
-}
-
-static bool wait_for_device(const char* service, TransportType t, const char* serial) {
     // Was the caller vague about what they'd like us to wait for?
     // If so, check they weren't more specific in their choice of transport type.
-    if (strcmp(service, "wait-for-device") == 0) {
+    if (components.size() == 3) {
+        auto it = components.begin() + 2;
         if (t == kTransportUsb) {
-            service = "wait-for-usb-device";
+            components.insert(it, "usb");
         } else if (t == kTransportLocal) {
-            service = "wait-for-local-device";
+            components.insert(it, "local");
         } else {
-            service = "wait-for-any-device";
+            components.insert(it, "any");
         }
-    }
-
-    if (!check_wait_for_device_syntax(service)) {
+    } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
+        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
+                components[2].c_str());
         return false;
     }
 
-    std::string cmd = format_host_command(service, t, serial);
+    if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
+        components[3] != "recovery" && components[3] != "sideload") {
+        fprintf(stderr,
+                "adb: unknown state %s; "
+                "expected 'any', 'bootloader', 'device', 'recovery', or 'sideload'\n",
+                components[3].c_str());
+        return false;
+    }
+
+    std::string cmd = format_host_command(android::base::Join(components, "-").c_str(), t, serial);
     return adb_command(cmd);
 }
 
@@ -1114,7 +1107,7 @@
     TransportType type;
     const char* serial;
     adb_get_transport(&type, &serial);
-    return wait_for_device("wait-for-device", type, serial);
+    return wait_for_device("wait-for-any", type, serial);
 }
 
 // Connects to the device "shell" service with |command| and prints the
@@ -1620,6 +1613,11 @@
     else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
         int exec_in = !strcmp(argv[0], "exec-in");
 
+        if (argc < 2) {
+            fprintf(stderr, "Usage: adb %s command\n", argv[0]);
+            return 1;
+        }
+
         std::string cmd = "exec:";
         cmd += argv[1];
         argc -= 2;
@@ -1721,7 +1719,7 @@
             }
         }
 
-        std::string cmd;
+        std::string cmd, error;
         if (strcmp(argv[0], "--list") == 0) {
             if (argc != 1) return usage();
             return adb_query_command(host_prefix + ":list-forward");
@@ -1735,14 +1733,37 @@
         } else if (strcmp(argv[0], "--no-rebind") == 0) {
             // forward --no-rebind <local> <remote>
             if (argc != 3) return usage();
-            cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+            if (forward_targets_are_valid(argv[1], argv[2], &error)) {
+                cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+            }
         } else {
             // forward <local> <remote>
             if (argc != 2) return usage();
-            cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+            if (forward_targets_are_valid(argv[0], argv[1], &error)) {
+                cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+            }
         }
 
-        return adb_command(cmd) ? 0 : 1;
+        if (!error.empty()) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+
+        int fd = adb_connect(cmd, &error);
+        if (fd < 0 || !adb_status(fd, &error)) {
+            adb_close(fd);
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+
+        // Server or device may optionally return a resolved TCP port number.
+        std::string resolved_port;
+        if (ReadProtocolString(fd, &resolved_port, &error) && !resolved_port.empty()) {
+            printf("%s\n", resolved_port.c_str());
+        }
+
+        ReadOrderlyShutdown(fd);
+        return 0;
     }
     /* do_sync_*() commands */
     else if (!strcmp(argv[0], "ls")) {
@@ -1905,6 +1926,14 @@
             }
         }
         return 0;
+    } else if (!strcmp(argv[0], "reconnect")) {
+        if (argc == 1) {
+            return adb_query_command("host:reconnect");
+        } else if (argc == 2 && !strcmp(argv[1], "device")) {
+            std::string err;
+            adb_connect("reconnect", &err);
+            return 0;
+        }
     }
 
     usage();
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 7f40b96..916bedf 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -142,10 +142,8 @@
         std::string error;
         std::string local_name =
             android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
-                             &error)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener: "
-                       << error;
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
         }
     }
 }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 902548e..04cd865 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -55,7 +55,7 @@
   fdevent* fde;
   adb_pollfd pollfd;
 
-  PollNode(fdevent* fde) : fde(fde) {
+  explicit PollNode(fdevent* fde) : fde(fde) {
       memset(&pollfd, 0, sizeof(pollfd));
       pollfd.fd = fde->fd;
 
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index c853bce..ef65b74 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -49,6 +49,16 @@
         dummy = dummy_fds[0];
     }
 
+    size_t GetAdditionalLocalSocketCount() {
+#if ADB_HOST
+        // dummy socket installed in PrepareThread()
+        return 1;
+#else
+        // dummy socket and one more socket installed in fdevent_subproc_setup()
+        return 2;
+#endif
+    }
+
     void TerminateThread(adb_thread_t thread) {
         fdevent_terminate_loop();
         ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
diff --git a/adb/services.cpp b/adb/services.cpp
index d5e963b..3b212e9 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -184,6 +184,13 @@
     adb_close(fd);
 }
 
+static void reconnect_service(int fd, void* arg) {
+    WriteFdExactly(fd, "done");
+    adb_close(fd);
+    atransport* t = static_cast<atransport*>(arg);
+    kick_transport(t);
+}
+
 int reverse_service(const char* command) {
     int s[2];
     if (adb_socketpair(s)) {
@@ -345,6 +352,8 @@
         ret = create_service_thread(set_verity_enabled_state_service, (void*)0);
     } else if(!strncmp(name, "enable-verity:", 15)) {
         ret = create_service_thread(set_verity_enabled_state_service, (void*)1);
+    } else if (!strcmp(name, "reconnect")) {
+        ret = create_service_thread(reconnect_service, const_cast<atransport*>(transport));
 #endif
     }
     if (ret >= 0) {
@@ -370,7 +379,7 @@
         std::string error = "unknown error";
         const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
         atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
-        if (t != nullptr && t->connection_state == sinfo->state) {
+        if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->connection_state)) {
             SendOkay(fd);
             break;
         } else if (!is_ambiguous) {
@@ -534,6 +543,8 @@
             sinfo->state = kCsSideload;
         } else if (!strcmp(name, "-bootloader")) {
             sinfo->state = kCsBootloader;
+        } else if (!strcmp(name, "-any")) {
+            sinfo->state = kCsAny;
         } else {
             return nullptr;
         }
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 20a3bbb..d2ce2d8 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -44,6 +44,8 @@
     fdevent_loop();
 }
 
+const size_t SLEEP_FOR_FDEVENT_IN_MS = 100;
+
 TEST_F(LocalSocketTest, smoke) {
     // Join two socketpairs with a chain of intermediate socketpairs.
     int first[2];
@@ -99,7 +101,8 @@
     ASSERT_EQ(0, adb_close(last[1]));
 
     // Wait until the local sockets are closed.
-    adb_sleep_ms(100);
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -151,12 +154,13 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
-
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -175,10 +179,10 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Verify if we can read successfully.
     std::vector<char> buf(arg.bytes_written);
@@ -186,6 +190,8 @@
     ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -208,10 +214,12 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
-    EXPECT_EQ(3u, fdevent_installed_count());
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -260,12 +268,14 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Wait until the client closes its socket.
     ASSERT_TRUE(adb_thread_join(client_thread));
 
+    adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 81d201e..3586da8 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -287,6 +287,9 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
+// Returns the local port number of a bound socket, or -1 on failure.
+int adb_socket_get_local_port(int fd);
+
 extern int  adb_setsockopt(int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen);
 
 #undef   setsockopt
@@ -691,6 +694,10 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
+inline int adb_socket_get_local_port(int fd) {
+    return socket_get_local_port(fd);
+}
+
 // Operate on a file descriptor returned from unix_open() or a well-known file
 // descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
 //
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 78efea8..fde344a 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -215,3 +215,32 @@
     // Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
     EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
 }
+
+TEST_F(sysdeps_poll, fd_count) {
+    // https://code.google.com/p/android/issues/detail?id=12141
+    static constexpr int num_sockets = 256;
+    std::vector<int> sockets;
+    std::vector<adb_pollfd> pfds;
+    sockets.resize(num_sockets * 2);
+    for (int32_t i = 0; i < num_sockets; ++i) {
+        ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno);
+        ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i)));
+        adb_pollfd pfd;
+        pfd.events = POLLIN;
+        pfd.fd = sockets[i * 2 + 1];
+        pfds.push_back(pfd);
+    }
+
+    ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0));
+    for (int i = 0; i < num_sockets; ++i) {
+        ASSERT_NE(0, pfds[i].revents & POLLIN);
+
+        int32_t buf[2] = { -1, -1 };
+        ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast<ssize_t>(sizeof(int32_t)));
+        ASSERT_EQ(i, buf[0]);
+    }
+
+    for (int fd : sockets) {
+        adb_close(fd);
+    }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a2f34fb..faf7f3e 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -191,7 +191,7 @@
 #define  fh_socket  u.socket
 
 #define  WIN32_FH_BASE    2048
-#define  WIN32_MAX_FHS    128
+#define  WIN32_MAX_FHS    2048
 
 static adb_mutex_t   _win32_lock;
 static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
@@ -1128,6 +1128,24 @@
     return result;
 }
 
+int adb_socket_get_local_port(int fd) {
+    sockaddr_storage addr_storage;
+    socklen_t addr_len = sizeof(addr_storage);
+
+    if (adb_getsockname(fd, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
+        D("adb_socket_get_local_port: adb_getsockname failed: %s", strerror(errno));
+        return -1;
+    }
+
+    if (!(addr_storage.ss_family == AF_INET || addr_storage.ss_family == AF_INET6)) {
+        D("adb_socket_get_local_port: unknown address family received: %d", addr_storage.ss_family);
+        errno = ECONNABORTED;
+        return -1;
+    }
+
+    return ntohs(reinterpret_cast<sockaddr_in*>(&addr_storage)->sin_port);
+}
+
 int  adb_shutdown(int  fd)
 {
     FH   f = _fh_from_int(fd, __func__);
@@ -1154,9 +1172,7 @@
     int server = -1;
     int client = -1;
     int accepted = -1;
-    sockaddr_storage addr_storage;
-    socklen_t addr_len = sizeof(addr_storage);
-    sockaddr_in* addr = nullptr;
+    int local_port = -1;
     std::string error;
 
     server = network_loopback_server(0, SOCK_STREAM, &error);
@@ -1165,20 +1181,14 @@
         goto fail;
     }
 
-    if (adb_getsockname(server, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
-        D("adb_socketpair: adb_getsockname failed: %s", strerror(errno));
+    local_port = adb_socket_get_local_port(server);
+    if (local_port < 0) {
+        D("adb_socketpair: failed to get server port number: %s", error.c_str());
         goto fail;
     }
+    D("adb_socketpair: bound on port %d", local_port);
 
-    if (addr_storage.ss_family != AF_INET) {
-        D("adb_socketpair: unknown address family received: %d", addr_storage.ss_family);
-        errno = ECONNABORTED;
-        goto fail;
-    }
-
-    addr = reinterpret_cast<sockaddr_in*>(&addr_storage);
-    D("adb_socketpair: bound on port %d", ntohs(addr->sin_port));
-    client = network_loopback_client(ntohs(addr->sin_port), SOCK_STREAM, &error);
+    client = network_loopback_client(local_port, SOCK_STREAM, &error);
     if (client < 0) {
         D("adb_socketpair: failed to connect client: %s", error.c_str());
         goto fail;
diff --git a/adb/test_device.py b/adb/test_device.py
index 9dab3ae..cdc57c6 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -191,6 +191,22 @@
         msg = self.device.forward_list()
         self.assertEqual('', msg.strip())
 
+    def test_forward_tcp_port_0(self):
+        self.assertEqual('', self.device.forward_list().strip(),
+                         'Forwarding list must be empty to run this test.')
+
+        try:
+            # If resolving TCP port 0 is supported, `adb forward` will print
+            # the actual port number.
+            port = self.device.forward('tcp:0', 'tcp:8888').strip()
+            if not port:
+                raise unittest.SkipTest('Forwarding tcp:0 is not available.')
+
+            self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+                                      self.device.forward_list()))
+        finally:
+            self.device.forward_remove_all()
+
     def test_reverse(self):
         msg = self.device.reverse_list()
         self.assertEqual('', msg.strip(),
@@ -210,6 +226,22 @@
         msg = self.device.reverse_list()
         self.assertEqual('', msg.strip())
 
+    def test_reverse_tcp_port_0(self):
+        self.assertEqual('', self.device.reverse_list().strip(),
+                         'Reverse list must be empty to run this test.')
+
+        try:
+            # If resolving TCP port 0 is supported, `adb reverse` will print
+            # the actual port number.
+            port = self.device.reverse('tcp:0', 'tcp:8888').strip()
+            if not port:
+                raise unittest.SkipTest('Reversing tcp:0 is not available.')
+
+            self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+                                      self.device.reverse_list()))
+        finally:
+            self.device.reverse_remove_all()
+
     # Note: If you run this test when adb connect'd to a physical device over
     # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
     def test_forward_reverse_echo(self):
@@ -279,7 +311,7 @@
         Raises:
           unittest.SkipTest: The device doesn't support exit codes.
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('exit codes are unavailable on this device')
 
         proc = subprocess.Popen(
@@ -342,7 +374,7 @@
         a terminal stdin to test so this test will be skipped if stdin
         is not a terminal.
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('PTY arguments unsupported on this device')
         if not os.isatty(sys.stdin.fileno()):
             raise unittest.SkipTest('PTY tests require stdin terminal')
@@ -394,7 +426,7 @@
 
         Bug: http://b/19734861
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('shell protocol unsupported on this device')
 
         # Shell protocol should be used by default.
@@ -424,7 +456,7 @@
 
         Bug: http://b/23825725
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('shell protocol unsupported on this device')
 
         # Start a long-running process.
@@ -445,7 +477,7 @@
 
     def test_non_interactive_stdin(self):
         """Tests that non-interactive shells send stdin."""
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('non-interactive stdin unsupported '
                                     'on this device')
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e3340af..55082a5 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -295,17 +295,13 @@
     transport_unref(t);
 }
 
-static void kick_transport_locked(atransport* t) {
-    CHECK(t != nullptr);
-    if (!t->kicked) {
-        t->kicked = true;
-        t->kick(t);
-    }
-}
-
 void kick_transport(atransport* t) {
     adb_mutex_lock(&transport_lock);
-    kick_transport_locked(t);
+    // As kick_transport() can be called from threads without guarantee that t is valid,
+    // check if the transport is in transport_list first.
+    if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
+        t->Kick();
+    }
     adb_mutex_unlock(&transport_lock);
 }
 
@@ -617,7 +613,6 @@
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
-        kick_transport_locked(t);
         t->close(t);
         remove_transport(t);
     } else {
@@ -744,6 +739,14 @@
     return result;
 }
 
+void atransport::Kick() {
+    if (!kicked_) {
+        kicked_ = true;
+        CHECK(kick_func_ != nullptr);
+        kick_func_(this);
+    }
+}
+
 const std::string atransport::connection_state_name() const {
     switch (connection_state) {
         case kCsOffline: return "offline";
@@ -924,10 +927,7 @@
 void close_usb_devices() {
     adb_mutex_lock(&transport_lock);
     for (const auto& t : transport_list) {
-        if (!t->kicked) {
-            t->kicked = 1;
-            t->kick(t);
-        }
+        t->Kick();
     }
     adb_mutex_unlock(&transport_lock);
 }
@@ -998,7 +998,7 @@
             // the read_transport thread will notify the main thread to make this transport
             // offline. Then the main thread will notify the write_transport thread to exit.
             // Finally, this transport will be closed and freed in the main thread.
-            kick_transport_locked(t);
+            t->Kick();
         }
     }
     adb_mutex_unlock(&transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index 5857249..35d7b50 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -60,7 +60,13 @@
     int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
     int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
     void (*close)(atransport* t) = nullptr;
-    void (*kick)(atransport* t) = nullptr;
+    void SetKickFunction(void (*kick_func)(atransport*)) {
+        kick_func_ = kick_func;
+    }
+    bool IsKicked() {
+        return kicked_;
+    }
+    void Kick();
 
     int fd = -1;
     int transport_socket = -1;
@@ -82,7 +88,6 @@
     char* device = nullptr;
     char* devpath = nullptr;
     int adb_port = -1;  // Use for emulators (local transport)
-    bool kicked = false;
 
     void* key = nullptr;
     unsigned char token[TOKEN_SIZE] = {};
@@ -123,6 +128,9 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
+    bool kicked_ = false;
+    void (*kick_func_)(atransport*) = nullptr;
+
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
     FeatureSet features_;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index f6c9df4..4121f47 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,7 +388,7 @@
 {
     int  fail = 0;
 
-    t->kick = remote_kick;
+    t->SetKickFunction(remote_kick);
     t->close = remote_close;
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2028ecc..a6db07a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,47 +20,6 @@
 
 #include "adb.h"
 
-class TestTransport : public atransport {
-public:
-    bool operator==(const atransport& rhs) const {
-        EXPECT_EQ(read_from_remote, rhs.read_from_remote);
-        EXPECT_EQ(write_to_remote, rhs.write_to_remote);
-        EXPECT_EQ(close, rhs.close);
-        EXPECT_EQ(kick, rhs.kick);
-
-        EXPECT_EQ(fd, rhs.fd);
-        EXPECT_EQ(transport_socket, rhs.transport_socket);
-
-        EXPECT_EQ(
-            0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
-
-        EXPECT_EQ(ref_count, rhs.ref_count);
-        EXPECT_EQ(sync_token, rhs.sync_token);
-        EXPECT_EQ(connection_state, rhs.connection_state);
-        EXPECT_EQ(online, rhs.online);
-        EXPECT_EQ(type, rhs.type);
-
-        EXPECT_EQ(usb, rhs.usb);
-        EXPECT_EQ(sfd, rhs.sfd);
-
-        EXPECT_EQ(serial, rhs.serial);
-        EXPECT_EQ(product, rhs.product);
-        EXPECT_EQ(model, rhs.model);
-        EXPECT_EQ(device, rhs.device);
-        EXPECT_EQ(devpath, rhs.devpath);
-        EXPECT_EQ(adb_port, rhs.adb_port);
-        EXPECT_EQ(kicked, rhs.kicked);
-
-        EXPECT_EQ(key, rhs.key);
-        EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
-        EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
-
-        EXPECT_EQ(features(), rhs.features());
-
-        return true;
-    }
-};
-
 class TransportSetup {
 public:
   TransportSetup() {
@@ -83,35 +42,19 @@
 static TransportSetup g_TransportSetup;
 
 TEST(transport, kick_transport) {
-  TestTransport t;
-
+  atransport t;
+  static size_t kick_count;
+  kick_count = 0;
   // Mutate some member so we can test that the function is run.
-  t.kick = [](atransport* trans) { trans->fd = 42; };
-
-  TestTransport expected;
-  expected.kick = t.kick;
-  expected.fd = 42;
-  expected.kicked = 1;
-
-  kick_transport(&t);
-  ASSERT_EQ(42, t.fd);
-  ASSERT_EQ(1, t.kicked);
-  ASSERT_EQ(expected, t);
-}
-
-TEST(transport, kick_transport_already_kicked) {
-  // Ensure that the transport is not modified if the transport has already been
-  // kicked.
-  TestTransport t;
-  t.kicked = 1;
-  t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
-
-  TestTransport expected;
-  expected.kicked = 1;
-  expected.kick = t.kick;
-
-  kick_transport(&t);
-  ASSERT_EQ(expected, t);
+  t.SetKickFunction([](atransport* trans) { kick_count++; });
+  ASSERT_FALSE(t.IsKicked());
+  t.Kick();
+  ASSERT_TRUE(t.IsKicked());
+  ASSERT_EQ(1u, kick_count);
+  // A transport can only be kicked once.
+  t.Kick();
+  ASSERT_TRUE(t.IsKicked());
+  ASSERT_EQ(1u, kick_count);
 }
 
 static void DisconnectFunc(void* arg, atransport*) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 263f9e7..d05d928 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -84,7 +84,7 @@
 {
     D("transport: usb");
     t->close = remote_close;
-    t->kick = remote_kick;
+    t->SetKickFunction(remote_kick);
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
     t->sync_token = 1;
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c863ed2..0ba6b4b 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,6 +31,9 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <atomic>
+
+#include <android-base/logging.h>
 
 #include "adb.h"
 #include "transport.h"
@@ -49,14 +52,19 @@
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
 
+static int dummy_fd = -1;
+
 struct usb_handle
 {
     adb_cond_t notify;
     adb_mutex_t lock;
+    bool open_new_connection;
+    std::atomic<bool> kicked;
 
     int (*write)(usb_handle *h, const void *data, int len);
     int (*read)(usb_handle *h, void *data, int len);
     void (*kick)(usb_handle *h);
+    void (*close)(usb_handle *h);
 
     // Legacy f_adb
     int fd;
@@ -241,8 +249,10 @@
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
-        while (usb->fd != -1)
+        while (!usb->open_new_connection) {
             adb_cond_wait(&usb->notify, &usb->lock);
+        }
+        usb->open_new_connection = false;
         adb_mutex_unlock(&usb->lock);
 
         D("[ usb_thread - opening device ]");
@@ -281,6 +291,10 @@
             h->fd, n, errno, strerror(errno));
         return -1;
     }
+    if (h->kicked) {
+        D("usb_adb_write finished due to kicked");
+        return -1;
+    }
     D("[ done fd=%d ]", h->fd);
     return 0;
 }
@@ -299,6 +313,10 @@
                 h->fd, n, errno, strerror(errno));
             return -1;
         }
+        if (h->kicked) {
+            D("usb_adb_read finished due to kicked");
+            return -1;
+        }
         len -= n;
         data = ((char*)data) + n;
     }
@@ -306,14 +324,23 @@
     return 0;
 }
 
-static void usb_adb_kick(usb_handle *h)
-{
+static void usb_adb_kick(usb_handle *h) {
     D("usb_kick");
-    adb_mutex_lock(&h->lock);
-    unix_close(h->fd);
-    h->fd = -1;
+    // Other threads may be calling usb_adb_read/usb_adb_write at the same time.
+    // If we close h->fd, the file descriptor will be reused to open other files,
+    // and the read/write thread may operate on the wrong file. So instead
+    // we set the kicked flag and reopen h->fd to a dummy file here. After read/write
+    // threads finish, we close h->fd in usb_adb_close().
+    h->kicked = true;
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->fd));
+}
 
-    // notify usb_adb_open_thread that we are disconnected
+static void usb_adb_close(usb_handle *h) {
+    h->kicked = false;
+    adb_close(h->fd);
+    // Notify usb_adb_open_thread to open a new connection.
+    adb_mutex_lock(&h->lock);
+    h->open_new_connection = true;
     adb_cond_signal(&h->notify);
     adb_mutex_unlock(&h->lock);
 }
@@ -326,8 +353,11 @@
     h->write = usb_adb_write;
     h->read = usb_adb_read;
     h->kick = usb_adb_kick;
+    h->close = usb_adb_close;
+    h->kicked = false;
     h->fd = -1;
 
+    h->open_new_connection = true;
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
@@ -350,7 +380,7 @@
 }
 
 
-static void init_functionfs(struct usb_handle *h)
+static bool init_functionfs(struct usb_handle *h)
 {
     ssize_t ret;
     struct desc_v1 v1_descriptor;
@@ -413,7 +443,7 @@
         goto err;
     }
 
-    return;
+    return true;
 
 err:
     if (h->bulk_in > 0) {
@@ -428,7 +458,7 @@
         adb_close(h->control);
         h->control = -1;
     }
-    return;
+    return false;
 }
 
 static void usb_ffs_open_thread(void* x) {
@@ -439,16 +469,16 @@
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
-        while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
+        while (!usb->open_new_connection) {
             adb_cond_wait(&usb->notify, &usb->lock);
+        }
+        usb->open_new_connection = false;
         adb_mutex_unlock(&usb->lock);
 
         while (true) {
-            init_functionfs(usb);
-
-            if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
+            if (init_functionfs(usb)) {
                 break;
-
+            }
             adb_sleep_ms(1000);
         }
         property_set("sys.usb.ffs.ready", "1");
@@ -513,16 +543,22 @@
         D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
     }
 
-    adb_mutex_lock(&h->lock);
-
     // don't close ep0 here, since we may not need to reinitialize it with
     // the same descriptors again. if however ep1/ep2 fail to re-open in
     // init_functionfs, only then would we close and open ep0 again.
+    // Ditto the comment in usb_adb_kick.
+    h->kicked = true;
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_out));
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_in));
+}
+
+static void usb_ffs_close(usb_handle *h) {
+    h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
-    h->bulk_out = h->bulk_in = -1;
-
-    // notify usb_ffs_open_thread that we are disconnected
+    // Notify usb_adb_open_thread to open a new connection.
+    adb_mutex_lock(&h->lock);
+    h->open_new_connection = true;
     adb_cond_signal(&h->notify);
     adb_mutex_unlock(&h->lock);
 }
@@ -537,10 +573,13 @@
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
+    h->close = usb_ffs_close;
+    h->kicked = false;
     h->control = -1;
     h->bulk_out = -1;
     h->bulk_out = -1;
 
+    h->open_new_connection = true;
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
@@ -552,6 +591,8 @@
 
 void usb_init()
 {
+    dummy_fd = adb_open("/dev/null", O_WRONLY);
+    CHECK_NE(dummy_fd, -1);
     if (access(USB_FFS_ADB_EP0, F_OK) == 0)
         usb_ffs_init();
     else
@@ -569,6 +610,7 @@
 }
 int usb_close(usb_handle *h)
 {
+    h->close(h);
     return 0;
 }
 
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 54d4c6c..ddde454 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,86 +29,96 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <vector>
+
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
 #include "adb.h"
 #include "transport.h"
 
-#define  DBG   D
-
-// There's no strerror equivalent for the errors returned by IOKit.
-// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
-// Search the web for "IOReturn.h" to find a complete up to date list.
-
-static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t            notificationIterator;
-
 struct usb_handle
 {
     UInt8 bulkIn;
     UInt8 bulkOut;
     IOUSBInterfaceInterface190** interface;
-    io_object_t usbNotification;
     unsigned int zero_mask;
+
+    // For garbage collecting disconnected devices.
+    bool mark;
+    std::string devpath;
+    std::atomic<bool> dead;
+
+    usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
+        zero_mask(0), mark(false), dead(false) {
+    }
 };
 
-static CFRunLoopRef currentRunLoop = 0;
-static pthread_mutex_t start_lock;
-static pthread_cond_t start_cond;
+static std::atomic<bool> usb_inited_flag;
 
+static auto& g_usb_handles_mutex = *new std::mutex();
+static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
 
-static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
-                                   natural_t messageType,
-                                   void *messageArgument);
-static usb_handle* CheckInterface(IOUSBInterfaceInterface190 **iface,
-                                  UInt16 vendor, UInt16 product);
-
-static int
-InitUSB()
-{
-    CFMutableDictionaryRef  matchingDict;
-    CFRunLoopSourceRef      runLoopSource;
-
-    //* To set up asynchronous notifications, create a notification port and
-    //* add its run loop event source to the program's run loop
-    notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
-    runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
-    //* Create our matching dictionary to find the Android device's
-    //* adb interface
-    //* IOServiceAddMatchingNotification consumes the reference, so we do
-    //* not need to release this
-    matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
-    if (!matchingDict) {
-        LOG(ERROR) << "Couldn't create USB matching dictionary.";
-        return -1;
+static bool IsKnownDevice(const std::string& devpath) {
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    for (auto& usb : g_usb_handles) {
+        if (usb->devpath == devpath) {
+            // Set mark flag to indicate this device is still alive.
+            usb->mark = true;
+            return true;
+        }
     }
+    return false;
+}
 
-    //* We have to get notifications for all potential candidates and test them
-    //* at connection time because the matching rules don't allow for a
-    //* USB interface class of 0xff for class+subclass+protocol matches
-    //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
-    IOServiceAddMatchingNotification(
-            notificationPort,
-            kIOFirstMatchNotification,
-            matchingDict,
-            AndroidInterfaceAdded,
-            NULL,
-            &notificationIterator);
+static void usb_kick_locked(usb_handle* handle);
 
-    //* Iterate over set of matching interfaces to access already-present
-    //* devices and to arm the notification
-    AndroidInterfaceAdded(NULL, notificationIterator);
+static void KickDisconnectedDevices() {
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    for (auto& usb : g_usb_handles) {
+        if (!usb->mark) {
+            usb_kick_locked(usb.get());
+        } else {
+            usb->mark = false;
+        }
+    }
+}
 
-    return 0;
+static void AddDevice(std::unique_ptr<usb_handle> handle) {
+    handle->mark = true;
+    std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+    g_usb_handles.push_back(std::move(handle));
+}
+
+static void AndroidInterfaceAdded(io_iterator_t iterator);
+static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
+                                                  UInt16 vendor, UInt16 product);
+
+static bool FindUSBDevices() {
+    // Create the matching dictionary to find the Android device's adb interface.
+    CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+    if (!matchingDict) {
+        LOG(ERROR) << "couldn't create USB matching dictionary";
+        return false;
+    }
+    // Create an iterator for all I/O Registry objects that match the dictionary.
+    io_iterator_t iter = 0;
+    kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
+    if (kr != KERN_SUCCESS) {
+        LOG(ERROR) << "failed to get matching services";
+        return false;
+    }
+    // Iterate over all matching objects.
+    AndroidInterfaceAdded(iter);
+    IOObjectRelease(iter);
+    return true;
 }
 
 static void
-AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(io_iterator_t iterator)
 {
     kern_return_t            kr;
     io_service_t             usbDevice;
@@ -124,8 +134,7 @@
     UInt16                   product;
     UInt8                    serialIndex;
     char                     serial[256];
-    char                     devpathBuf[64];
-    char                     *devpath = NULL;
+    std::string devpath;
 
     while ((usbInterface = IOIteratorNext(iterator))) {
         //* Create an intermediate interface plugin
@@ -199,9 +208,11 @@
         kr = (*dev)->GetDeviceVendor(dev, &vendor);
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->GetLocationID(dev, &locationId);
-        if (kr == 0) {
-            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
-            devpath = devpathBuf;
+        if (kr == KERN_SUCCESS) {
+            devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
+            if (IsKnownDevice(devpath)) {
+                continue;
+            }
         }
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
@@ -256,49 +267,29 @@
 
         (*dev)->Release(dev);
 
-        LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+        VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
                         vendor, product, serial);
-
-        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
-                                            vendor, product);
-        if (handle == NULL) {
-            LOG(ERROR) << "Could not find device interface";
+        if (devpath.empty()) {
+            devpath = serial;
+        }
+        if (IsKnownDevice(devpath)) {
+            (*iface)->USBInterfaceClose(iface);
             (*iface)->Release(iface);
             continue;
         }
 
-        LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
-        register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
-
-        // Register for an interest notification of this device being removed.
-        // Pass the reference to our private data as the refCon for the
-        // notification.
-        kr = IOServiceAddInterestNotification(notificationPort,
-                usbInterface,
-                kIOGeneralInterest,
-                AndroidInterfaceNotify,
-                handle,
-                &handle->usbNotification);
-
-        if (kIOReturnSuccess != kr) {
-            LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
+        std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
+                                                            vendor, product);
+        if (handle == nullptr) {
+            LOG(ERROR) << "Could not find device interface";
+            (*iface)->Release(iface);
+            continue;
         }
-    }
-}
-
-static void
-AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
-{
-    usb_handle *handle = (usb_handle *)refCon;
-
-    if (messageType == kIOMessageServiceIsTerminated) {
-        if (!handle) {
-            LOG(ERROR) << "NULL handle";
-            return;
-        }
-        LOG(DEBUG) << "AndroidInterfaceNotify";
-        IOObjectRelease(handle->usbNotification);
-        usb_kick(handle);
+        handle->devpath = devpath;
+        usb_handle* handle_p = handle.get();
+        VLOG(USB) << "Add usb device " << serial;
+        AddDevice(std::move(handle));
+        register_usb_transport(handle_p, serial, devpath.c_str(), 1);
     }
 }
 
@@ -316,10 +307,10 @@
 
 //* TODO: simplify this further since we only register to get ADB interface
 //* subclass+protocol events
-static usb_handle*
+static std::unique_ptr<usb_handle>
 CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
 {
-    usb_handle* handle;
+    std::unique_ptr<usb_handle> handle;
     IOReturn kr;
     UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
     UInt8 endpoint;
@@ -353,8 +344,10 @@
         goto err_bad_adb_interface;
     }
 
-    handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
-    if (handle == nullptr) goto err_bad_adb_interface;
+    handle.reset(new usb_handle);
+    if (handle == nullptr) {
+        goto err_bad_adb_interface;
+    }
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
@@ -392,39 +385,37 @@
     return handle;
 
 err_get_pipe_props:
-    free(handle);
 err_bad_adb_interface:
 err_get_interface_class:
 err_get_num_ep:
     (*interface)->USBInterfaceClose(interface);
-    return NULL;
+    return nullptr;
 }
 
+std::mutex& operate_device_lock = *new std::mutex();
+
 static void RunLoopThread(void* unused) {
     adb_thread_setname("RunLoop");
-    InitUSB();
 
-    currentRunLoop = CFRunLoopGetCurrent();
-
-    // Signal the parent that we are running
-    adb_mutex_lock(&start_lock);
-    adb_cond_signal(&start_cond);
-    adb_mutex_unlock(&start_lock);
-
-    CFRunLoopRun();
-    currentRunLoop = 0;
-
-    IOObjectRelease(notificationIterator);
-    IONotificationPortDestroy(notificationPort);
-
-    LOG(DEBUG) << "RunLoopThread done";
+    VLOG(USB) << "RunLoopThread started";
+    while (true) {
+        {
+            std::lock_guard<std::mutex> lock_guard(operate_device_lock);
+            FindUSBDevices();
+            KickDisconnectedDevices();
+        }
+        // Signal the parent that we are running
+        usb_inited_flag = true;
+        adb_sleep_ms(1000);
+    }
+    VLOG(USB) << "RunLoopThread done";
 }
 
 static void usb_cleanup() {
-    LOG(DEBUG) << "usb_cleanup";
+    VLOG(USB) << "usb_cleanup";
+    // Wait until usb operations in RunLoopThread finish, and prevent further operations.
+    operate_device_lock.lock();
     close_usb_devices();
-    if (currentRunLoop)
-        CFRunLoopStop(currentRunLoop);
 }
 
 void usb_init() {
@@ -432,20 +423,16 @@
     if (!initialized) {
         atexit(usb_cleanup);
 
-        adb_mutex_init(&start_lock, NULL);
-        adb_cond_init(&start_cond, NULL);
+        usb_inited_flag = false;
 
         if (!adb_thread_create(RunLoopThread, nullptr)) {
             fatal_errno("cannot create RunLoop thread");
         }
 
         // Wait for initialization to finish
-        adb_mutex_lock(&start_lock);
-        adb_cond_wait(&start_cond, &start_lock);
-        adb_mutex_unlock(&start_lock);
-
-        adb_mutex_destroy(&start_lock);
-        adb_cond_destroy(&start_cond);
+        while (!usb_inited_flag) {
+            adb_sleep_ms(100);
+        }
 
         initialized = true;
     }
@@ -458,7 +445,7 @@
     if (!len)
         return 0;
 
-    if (!handle)
+    if (!handle || handle->dead)
         return -1;
 
     if (NULL == handle->interface) {
@@ -499,7 +486,7 @@
         return 0;
     }
 
-    if (!handle) {
+    if (!handle || handle->dead) {
         return -1;
     }
 
@@ -532,20 +519,33 @@
 
 int usb_close(usb_handle *handle)
 {
+    std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+    for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
+        if ((*it).get() == handle) {
+            g_usb_handles.erase(it);
+            break;
+        }
+    }
     return 0;
 }
 
-void usb_kick(usb_handle *handle)
+static void usb_kick_locked(usb_handle *handle)
 {
     LOG(INFO) << "Kicking handle";
     /* release the interface */
     if (!handle)
         return;
 
-    if (handle->interface)
+    if (!handle->dead)
     {
+        handle->dead = true;
         (*handle->interface)->USBInterfaceClose(handle->interface);
         (*handle->interface)->Release(handle->interface);
-        handle->interface = 0;
     }
 }
+
+void usb_kick(usb_handle *handle) {
+    // Use the lock to avoid multiple thread kicking the device at the same time.
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    usb_kick_locked(handle);
+}
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 913a9a0..299ec35 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -123,8 +123,11 @@
   ((sizeof(a) / sizeof(*(a))) / \
     static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
 
-#define LIKELY(x) __builtin_expect((x), true)
-#define UNLIKELY(x) __builtin_expect((x), false)
+// Changing this definition will cause you a lot of pain.  A majority of
+// vendor code defines LIKELY and UNLIKELY this way, and includes
+// this header through an indirect path.
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
 #define WARN_UNUSED __attribute__((warn_unused_result))
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 8bc49ce..ab41c55 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -19,7 +19,10 @@
 
 #include <unistd.h>
 
-#include <android-base/macros.h>
+// DO NOT INCLUDE OTHER LIBBASE HEADERS!
+// This file gets used in libbinder, and libbinder is used everywhere.
+// Including other headers from libbase frequently results in inclusion of
+// android-base/macros.h, which causes macro collisions.
 
 // Container for a file descriptor that automatically closes the descriptor as
 // it goes out of scope.
@@ -75,7 +78,8 @@
  private:
   int value_;
 
-  DISALLOW_COPY_AND_ASSIGN(unique_fd);
+  unique_fd(const unique_fd&);
+  void operator=(const unique_fd&);
 };
 
 }  // namespace base
diff --git a/bootstat/Android.mk b/bootstat/Android.mk
index 6300941..bdd680d 100644
--- a/bootstat/Android.mk
+++ b/bootstat/Android.mk
@@ -16,8 +16,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-bootstat_c_includes := external/gtest/include
-
 bootstat_lib_src_files := \
         boot_event_record_store.cpp \
         event_log_list_builder.cpp \
@@ -57,7 +55,7 @@
 
 LOCAL_MODULE := libbootstat
 LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
 LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
 LOCAL_SRC_FILES := $(bootstat_lib_src_files)
 # Clang is required because of C++14
@@ -72,7 +70,7 @@
 
 LOCAL_MODULE := libbootstat_debug
 LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
 LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
 LOCAL_SRC_FILES := $(bootstat_lib_src_files)
 # Clang is required because of C++14
@@ -87,7 +85,7 @@
 
 LOCAL_MODULE := libbootstat_host_debug
 LOCAL_CFLAGS := $(bootstat_debug_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
 LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
 LOCAL_SRC_FILES := $(bootstat_lib_src_files)
 # Clang is required because of C++14
@@ -102,7 +100,7 @@
 
 LOCAL_MODULE := bootstat
 LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
 LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
 LOCAL_STATIC_LIBRARIES := libbootstat
 LOCAL_INIT_RC := bootstat.rc
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index b819797..7c1b7f3 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -176,14 +176,54 @@
   return kUnknownBootReason;
 }
 
+// Returns the appropriate metric key prefix for the boot_complete metric such
+// that boot metrics after a system update are labeled as ota_boot_complete;
+// otherwise, they are labeled as boot_complete.  This method encapsulates the
+// bookkeeping required to track when a system update has occurred by storing
+// the UTC timestamp of the system build date and comparing against the current
+// system build date.
+std::string CalculateBootCompletePrefix() {
+  static const std::string kBuildDateKey = "build_date";
+  std::string boot_complete_prefix = "boot_complete";
+
+  std::string build_date_str = GetProperty("ro.build.date.utc");
+  int32_t build_date = std::stoi(build_date_str);
+
+  BootEventRecordStore boot_event_store;
+  BootEventRecordStore::BootEventRecord record;
+  if (!boot_event_store.GetBootEvent(kBuildDateKey, &record) ||
+      build_date != record.second) {
+    boot_complete_prefix = "ota_" + boot_complete_prefix;
+    boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
+  }
+
+  return boot_complete_prefix;
+}
+
 // Records several metrics related to the time it takes to boot the device,
 // including disambiguating boot time on encrypted or non-encrypted devices.
 void RecordBootComplete() {
   BootEventRecordStore boot_event_store;
-  time_t uptime = bootstat::ParseUptime();
-
   BootEventRecordStore::BootEventRecord record;
 
+  time_t uptime = bootstat::ParseUptime();
+  time_t current_time_utc = time(nullptr);
+
+  if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
+    time_t last_boot_time_utc = record.second;
+    time_t time_since_last_boot = difftime(current_time_utc,
+                                           last_boot_time_utc);
+    boot_event_store.AddBootEventWithValue("time_since_last_boot",
+                                           time_since_last_boot);
+  }
+
+  boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc);
+
+  // The boot_complete metric has two variants: boot_complete and
+  // ota_boot_complete.  The latter signifies that the device is booting after
+  // a system update.
+  std::string boot_complete_prefix = CalculateBootCompletePrefix();
+
   // post_decrypt_time_elapsed is only logged on encrypted devices.
   if (boot_event_store.GetBootEvent("post_decrypt_time_elapsed", &record)) {
     // Log the amount of time elapsed until the device is decrypted, which
@@ -193,18 +233,18 @@
 
     // Subtract the decryption time to normalize the boot cycle timing.
     time_t boot_complete = uptime - record.second;
-    boot_event_store.AddBootEventWithValue("boot_complete_post_decrypt",
+    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
                                            boot_complete);
 
 
   } else {
-    boot_event_store.AddBootEventWithValue("boot_complete_no_encryption",
+    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
                                            uptime);
   }
 
   // Record the total time from device startup to boot complete, regardless of
   // encryption state.
-  boot_event_store.AddBootEventWithValue("boot_complete", uptime);
+  boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
 }
 
 // Records the boot_reason metric by querying the ro.boot.bootreason system
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 6469db4..9ce94c5 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -54,7 +54,7 @@
 
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES := crasher.cpp
 LOCAL_SRC_FILES_arm    := arm/crashglue.S
 LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
 LOCAL_SRC_FILES_mips   := mips/crashglue.S
@@ -63,9 +63,9 @@
 LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
+LOCAL_CPPFLAGS := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 # The arm emulator has VFP but not VFPv3-D32.
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index 32843d8..8f4a53f 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -29,6 +29,7 @@
 #include <sys/ptrace.h>
 
 #include <memory>
+#include <string>
 
 #include <backtrace/Backtrace.h>
 
@@ -96,11 +97,11 @@
   }
 }
 
-void dump_backtrace(int fd, int amfd, BacktraceMap* map, pid_t pid, pid_t tid,
-                    const std::set<pid_t>& siblings) {
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
+                    const std::set<pid_t>& siblings, std::string* amfd_data) {
   log_t log;
   log.tfd = fd;
-  log.amfd = amfd;
+  log.amfd_data = amfd_data;
 
   dump_process_header(&log, pid);
   dump_thread(&log, map, pid, tid);
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 98c433b..acd5eaa 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <set>
+#include <string>
 
 #include "utility.h"
 
@@ -28,8 +29,8 @@
 
 // Dumps a backtrace using a format similar to what Dalvik uses so that the result
 // can be intermixed in a bug report.
-void dump_backtrace(int fd, int amfd, BacktraceMap* map, pid_t pid, pid_t tid,
-                    const std::set<pid_t>& siblings);
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
+                    const std::set<pid_t>& siblings, std::string* amfd_data);
 
 /* Dumps the backtrace in the backtrace data structure to the log. */
 void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.cpp
similarity index 93%
rename from debuggerd/crasher.c
rename to debuggerd/crasher.cpp
index 75f070b..bdeaf0b 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.cpp
@@ -22,8 +22,9 @@
 
 extern const char* __progname;
 
-void crash1(void);
-void crashnostack(void);
+extern "C" void crash1(void);
+extern "C" void crashnostack(void);
+
 static int do_action(const char* arg);
 
 static void maybe_abort() {
@@ -159,6 +160,10 @@
         __assert("some_file.c", 123, "false");
     } else if (!strcmp(arg, "assert2")) {
         __assert2("some_file.c", 123, "some_function", "false");
+    } else if (!strcmp(arg, "fortify")) {
+        char buf[10];
+        __read_chk(-1, buf, 32, 10);
+        while (true) pause();
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
         LOG_ALWAYS_FATAL("hello %s", "world");
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
@@ -172,7 +177,7 @@
     } else if (!strcmp(arg, "heap-usage")) {
         abuse_heap();
     } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
-        char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+        char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
         munmap(map, sizeof(int));
         map[0] = '8';
     }
@@ -189,6 +194,7 @@
     fprintf(stderr, "  abort                 call abort()\n");
     fprintf(stderr, "  assert                call assert() without a function\n");
     fprintf(stderr, "  assert2               call assert() with a function\n");
+    fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 6064568..d87594c 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <arpa/inet.h>
 #include <dirent.h>
 #include <elf.h>
 #include <errno.h>
@@ -25,17 +26,22 @@
 #include <sys/poll.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/un.h>
 #include <time.h>
 
+#include <memory>
 #include <set>
+#include <string>
 
 #include <selinux/android.h>
 
 #include <log/logger.h>
 
+#include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <cutils/debugger.h>
 #include <cutils/properties.h>
@@ -248,6 +254,78 @@
   return 0;
 }
 
+static int activity_manager_connect() {
+  android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));
+  if (amfd.get() < -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (socket failed: %s)", strerror(errno));
+    return -1;
+  }
+
+  struct sockaddr_un address;
+  memset(&address, 0, sizeof(address));
+  address.sun_family = AF_UNIX;
+  // The path used here must match the value defined in NativeCrashListener.java.
+  strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
+  if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address),
+                                 sizeof(address))) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (connect failed: %s)", strerror(errno));
+    return -1;
+  }
+
+  struct timeval tv;
+  memset(&tv, 0, sizeof(tv));
+  tv.tv_sec = 1;  // tight leash
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
+          strerror(errno));
+    return -1;
+  }
+
+  tv.tv_sec = 3;  // 3 seconds on handshake read
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
+          strerror(errno));
+    return -1;
+  }
+
+  return amfd.release();
+}
+
+static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) {
+  if (amfd == -1) {
+    return;
+  }
+
+  // Activity Manager protocol: binary 32-bit network-byte-order ints for the
+  // pid and signal number, followed by the raw text of the dump, culminating
+  // in a zero byte that marks end-of-data.
+  uint32_t datum = htonl(pid);
+  if (!android::base::WriteFully(amfd, &datum, 4)) {
+    ALOGE("AM pid write failed: %s\n", strerror(errno));
+    return;
+  }
+  datum = htonl(signal);
+  if (!android::base::WriteFully(amfd, &datum, 4)) {
+    ALOGE("AM signal write failed: %s\n", strerror(errno));
+    return;
+  }
+
+  if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) {
+    ALOGE("AM data write failed: %s\n", strerror(errno));
+    return;
+  }
+
+  // Send EOD to the Activity Manager, then wait for its ack to avoid racing
+  // ahead and killing the target out from under it.
+  uint8_t eodMarker = 0;
+  if (!android::base::WriteFully(amfd, &eodMarker, 1)) {
+    ALOGE("AM eod write failed: %s\n", strerror(errno));
+    return;
+  }
+  // 3 sec timeout reading the ack; we're fine if the read fails.
+  android::base::ReadFully(amfd, &eodMarker, 1);
+}
+
 static bool should_attach_gdb(const debugger_request_t& request) {
   if (request.action == DEBUGGER_ACTION_CRASH) {
     return property_get_bool("debug.debuggerd.wait_for_gdb", false);
@@ -375,7 +453,7 @@
 
 static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
                          BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
-                         int* crash_signal) {
+                         int* crash_signal, std::string* amfd_data) {
   if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
     ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
     return false;
@@ -393,10 +471,10 @@
         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);
+                            request.original_si_code, request.abort_msg_address, amfd_data);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
-          dump_backtrace(fd, -1, backtrace_map, request.pid, request.tid, siblings);
+          dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
         } else {
           ALOGV("debuggerd: stopped -- continuing");
           if (ptrace(PTRACE_CONT, request.tid, 0, 0) != 0) {
@@ -419,7 +497,7 @@
         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);
+                          request.original_si_code, request.abort_msg_address, amfd_data);
         break;
 
       default:
@@ -433,13 +511,21 @@
 }
 
 static bool drop_privileges() {
+  // AID_LOG: for reading the logs data associated with the crashing process.
+  // AID_READPROC: for reading /proc/<PID>/{comm,cmdline}.
+  gid_t groups[] = { AID_DEBUGGERD, AID_LOG, AID_READPROC };
+  if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+    ALOGE("debuggerd: failed to setgroups: %s", strerror(errno));
+    return false;
+  }
+
   if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
-    ALOGE("debuggerd: failed to setresgid");
+    ALOGE("debuggerd: failed to setresgid: %s", strerror(errno));
     return false;
   }
 
   if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
-    ALOGE("debuggerd: failed to setresuid");
+    ALOGE("debuggerd: failed to setresuid: %s", strerror(errno));
     return false;
   }
 
@@ -505,6 +591,14 @@
   // Generate the backtrace map before dropping privileges.
   std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
 
+  int amfd = -1;
+  std::unique_ptr<std::string> amfd_data;
+  if (request.action == DEBUGGER_ACTION_CRASH) {
+    // Connect to the activity manager before dropping privileges.
+    amfd = activity_manager_connect();
+    amfd_data.reset(new std::string);
+  }
+
   bool succeeded = false;
 
   // Now that we've done everything that requires privileges, we can drop them.
@@ -514,11 +608,12 @@
   }
 
   int crash_signal = SIGKILL;
-  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings, &crash_signal);
+  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
+                           &crash_signal, amfd_data.get());
   if (succeeded) {
     if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
       if (!tombstone_path.empty()) {
-        write(fd, tombstone_path.c_str(), tombstone_path.length());
+        android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length());
       }
     }
   }
@@ -531,6 +626,13 @@
     }
   }
 
+  if (!attach_gdb) {
+    // Tell the Activity Manager about the crashing process. If we are
+    // waiting for gdb to attach, do not send this or Activity Manager
+    // might kill the process before anyone can attach.
+    activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
+  }
+
   if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) {
     ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
   }
@@ -547,9 +649,12 @@
   }
 
   // Wait for gdb, if requested.
-  if (attach_gdb && succeeded) {
+  if (attach_gdb) {
     wait_for_user_action(request);
 
+    // Now tell the activity manager about this process.
+    activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
+
     // Tell the signal process to send SIGCONT to the target.
     if (!send_signal(request.pid, 0, SIGCONT)) {
       ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno));
@@ -558,6 +663,8 @@
     uninit_getevent();
   }
 
+  close(amfd);
+
   exit(!succeeded);
 }
 
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
index 2addd5d..49f3690 100644
--- a/debuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -125,7 +125,7 @@
     }
 
     log_.tfd = tombstone_fd;
-    log_.amfd = -1;
+    log_.amfd_data = nullptr;
     log_.crashed_tid = 12;
     log_.current_tid = 12;
     log_.should_retrieve_logcat = false;
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index 96b3a7a..58d640e 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -68,7 +68,8 @@
     }
 
     log_.tfd = tombstone_fd;
-    log_.amfd = -1;
+    amfd_data_.clear();
+    log_.amfd_data = &amfd_data_;
     log_.crashed_tid = 12;
     log_.current_tid = 12;
     log_.should_retrieve_logcat = false;
@@ -90,6 +91,7 @@
   std::unique_ptr<BacktraceMock> backtrace_mock_;
 
   log_t log_;
+  std::string amfd_data_;
 };
 
 TEST_F(TombstoneTest, single_map) {
@@ -117,6 +119,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -150,6 +154,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -189,6 +195,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -251,6 +259,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -305,6 +315,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -359,6 +371,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -411,6 +425,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -469,6 +485,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -501,6 +519,8 @@
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
+  ASSERT_STREQ("", amfd_data_.c_str());
+
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
@@ -562,6 +582,8 @@
         << "Signal " << si.si_signo << " is not expected to include an address.";
     }
 
+    ASSERT_STREQ("", amfd_data_.c_str());
+
     // Verify that the log buf is empty, and no error messages.
     ASSERT_STREQ("", getFakeLogBuf().c_str());
     ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -582,6 +604,8 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
+
+  ASSERT_STREQ("", amfd_data_.c_str());
 }
 
 TEST_F(TombstoneTest, dump_log_file_error) {
@@ -596,4 +620,14 @@
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
                getFakeLogPrint().c_str());
+
+  ASSERT_STREQ("", amfd_data_.c_str());
+}
+
+TEST_F(TombstoneTest, dump_header_info) {
+  dump_header_info(&log_);
+
+  std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n";
+  expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
+  ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
 }
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 7cf2ffc..fa983fa 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -16,7 +16,6 @@
 
 #define LOG_TAG "DEBUG"
 
-#include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -28,9 +27,7 @@
 #include <string.h>
 #include <time.h>
 #include <sys/ptrace.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
-#include <sys/un.h>
 
 #include <memory>
 #include <string>
@@ -59,9 +56,6 @@
 #define TOMBSTONE_DIR   "/data/tombstones"
 #define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
-// Must match the path defined in NativeCrashListener.java
-#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-
 static bool signal_has_si_addr(int sig) {
   switch (sig) {
     case SIGBUS:
@@ -207,7 +201,7 @@
 static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
   char path[64];
   char threadnamebuf[1024];
-  char* threadname = NULL;
+  char* threadname = nullptr;
   FILE *fp;
 
   snprintf(path, sizeof(path), "/proc/%d/comm", tid);
@@ -223,13 +217,13 @@
   }
   // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
   static const char logd[] = "logd";
-  if (!strncmp(threadname, logd, sizeof(logd) - 1)
+  if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1)
       && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
     log->should_retrieve_logcat = false;
   }
 
   char procnamebuf[1024];
-  char* procname = NULL;
+  char* procname = nullptr;
 
   snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
   if ((fp = fopen(path, "r"))) {
@@ -618,16 +612,6 @@
   property_get("ro.debuggable", value, "0");
   bool want_logs = (value[0] == '1');
 
-  if (log->amfd >= 0) {
-    // Activity Manager protocol: binary 32-bit network-byte-order ints for the
-    // pid and signal number, followed by the raw text of the dump, culminating
-    // in a zero byte that marks end-of-data.
-    uint32_t datum = htonl(pid);
-    TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
-    datum = htonl(signal);
-    TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
-  }
-
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(log);
@@ -645,17 +629,6 @@
   if (want_logs) {
     dump_logs(log, pid, 0);
   }
-
-  // send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
-  // and killing the target out from under it
-  if (log->amfd >= 0) {
-    uint8_t eodMarker = 0;
-    TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
-    // 3 sec timeout reading the ack; we're fine if that happens
-    TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
-  }
-
-  return;
 }
 
 // open_tombstone - find an available tombstone slot, if any, of the
@@ -711,39 +684,9 @@
   return fd;
 }
 
-static int activity_manager_connect() {
-  int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
-  if (amfd >= 0) {
-    struct sockaddr_un address;
-    int err;
-
-    memset(&address, 0, sizeof(address));
-    address.sun_family = AF_UNIX;
-    strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
-    err = TEMP_FAILURE_RETRY(connect(
-        amfd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)));
-    if (!err) {
-      struct timeval tv;
-      memset(&tv, 0, sizeof(tv));
-      tv.tv_sec = 1;  // tight leash
-      err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-      if (!err) {
-        tv.tv_sec = 3;  // 3 seconds on handshake read
-        err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-      }
-    }
-    if (err) {
-      close(amfd);
-      amfd = -1;
-    }
-  }
-
-  return amfd;
-}
-
 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) {
+                       uintptr_t abort_msg_address, std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
@@ -754,12 +697,6 @@
   }
 
   log.tfd = tombstone_fd;
-  // Preserve amfd since it can be modified through the calls below without
-  // being closed.
-  int amfd = activity_manager_connect();
-  log.amfd = amfd;
+  log.amfd_data = amfd_data;
   dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
-
-  // This file descriptor can be -1, any error is ignored.
-  close(amfd);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 2b8b8be..487d950 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -34,6 +34,6 @@
 /* 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);
+                       uintptr_t abort_msg_address, std::string* amfd_data);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index cd252ce..bd06095 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -25,7 +25,8 @@
 #include <sys/ptrace.h>
 #include <sys/wait.h>
 
-#include <android-base/file.h>
+#include <string>
+
 #include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
@@ -49,7 +50,6 @@
                       && log->crashed_tid != -1
                       && log->current_tid != -1
                       && (log->crashed_tid == log->current_tid);
-  bool write_to_activitymanager = (log->amfd != -1);
 
   char buf[512];
   va_list ap;
@@ -68,12 +68,8 @@
 
   if (write_to_logcat) {
     __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
-    if (write_to_activitymanager) {
-      if (!android::base::WriteFully(log->amfd, buf, len)) {
-        // timeout or other failure on write; stop informing the activity manager
-        ALOGE("AM write failed: %s", strerror(errno));
-        log->amfd = -1;
-      }
+    if (log->amfd_data != nullptr) {
+      *log->amfd_data += buf;
     }
   }
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index ed08ddc..cd01188 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
+#include <string>
+
 #include <backtrace/Backtrace.h>
 
 // Figure out the abi based on defined macros.
@@ -42,10 +44,10 @@
 
 
 struct log_t{
-    /* tombstone file descriptor */
+    // Tombstone file descriptor.
     int tfd;
-    /* Activity Manager socket file descriptor */
-    int amfd;
+    // Data to be sent to the Activity Manager.
+    std::string* amfd_data;
     // The tid of the thread that crashed.
     pid_t crashed_tid;
     // The tid of the thread we are currently working with.
@@ -54,7 +56,8 @@
     bool should_retrieve_logcat;
 
     log_t()
-        : tfd(-1), amfd(-1), crashed_tid(-1), current_tid(-1), should_retrieve_logcat(true) {}
+        : tfd(-1), amfd_data(nullptr), crashed_tid(-1), current_tid(-1),
+          should_retrieve_logcat(true) {}
 };
 
 // List of types of logs to simplify the logging decision in _LOG
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 47567c0..db5d0e0 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -351,21 +351,21 @@
         }
         if (a->op == OP_DOWNLOAD) {
             status = fb_download_data(transport, a->data, a->size);
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_COMMAND) {
             status = fb_command(transport, a->cmd);
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_QUERY) {
             status = fb_command_response(transport, a->cmd, resp);
-            status = a->func(a, status, status ? fb_get_error() : resp);
+            status = a->func(a, status, status ? fb_get_error().c_str() : resp);
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
         } else if (a->op == OP_DOWNLOAD_SPARSE) {
             status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
             transport->WaitForDisconnect();
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index fa8f19a..1839d25 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -49,6 +49,7 @@
 
 #include <android-base/parseint.h>
 #include <android-base/parsenetaddress.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <sparse/sparse.h>
 #include <ziparchive/zip_archive.h>
@@ -108,12 +109,9 @@
     {"vendor.img", "vendor.sig", "vendor", true},
 };
 
-static char* find_item(const char* item, const char* product) {
-    char *dir;
+static std::string find_item(const char* item, const char* product) {
     const char *fn;
-    char path[PATH_MAX + 128];
-
-    if(!strcmp(item,"boot")) {
+    if (!strcmp(item,"boot")) {
         fn = "boot.img";
     } else if(!strcmp(item,"recovery")) {
         fn = "recovery.img";
@@ -129,24 +127,22 @@
         fn = "android-info.txt";
     } else {
         fprintf(stderr,"unknown partition '%s'\n", item);
-        return 0;
+        return "";
     }
 
-    if(product) {
-        get_my_path(path);
-        sprintf(path + strlen(path),
-                "../../../target/product/%s/%s", product, fn);
-        return strdup(path);
+    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);
     }
 
-    dir = getenv("ANDROID_PRODUCT_OUT");
-    if((dir == 0) || (dir[0] == 0)) {
+    char* dir = getenv("ANDROID_PRODUCT_OUT");
+    if (dir == nullptr || dir[0] == '\0') {
         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
-        return 0;
     }
 
-    sprintf(path, "%s/%s", dir, fn);
-    return strdup(path);
+    return android::base::StringPrintf("%s/%s", dir, fn);
 }
 
 static int64_t get_file_size(int fd) {
@@ -179,8 +175,8 @@
     return 0;
 }
 
-static void* load_file(const char* fn, int64_t* sz) {
-    int fd = open(fn, O_RDONLY | O_BINARY);
+static void* load_file(const std::string& path, int64_t* sz) {
+    int fd = open(path.c_str(), O_RDONLY | O_BINARY);
     if (fd == -1) return nullptr;
     return load_fd(fd, sz);
 }
@@ -721,10 +717,10 @@
     return partition_type == "ext4";
 }
 
-static int load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
     int64_t sz = get_file_size(fd);
     if (sz == -1) {
-        return -1;
+        return false;
     }
 
     lseek64(fd, 0, SEEK_SET);
@@ -732,7 +728,7 @@
     if (limit) {
         sparse_file** s = load_sparse_files(fd, limit);
         if (s == nullptr) {
-            return -1;
+            return false;
         }
         buf->type = FB_BUFFER_SPARSE;
         buf->data = s;
@@ -744,18 +740,14 @@
         buf->sz = sz;
     }
 
-    return 0;
+    return true;
 }
 
-static int load_buf(Transport* transport, const char *fname, struct fastboot_buffer *buf)
-{
-    int fd;
-
-    fd = open(fname, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        return -1;
+static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+    int fd = open(fname, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        return false;
     }
-
     return load_buf_fd(transport, fd, buf);
 }
 
@@ -899,8 +891,8 @@
 static void do_flash(Transport* transport, const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
-    if (load_buf(transport, fname, &buf)) {
-        die("cannot load '%s'", fname);
+    if (!load_buf(transport, fname, &buf)) {
+        die("cannot load '%s': %s", fname, strerror(errno));
     }
     flash_buf(pname, &buf);
 }
@@ -944,8 +936,9 @@
             exit(1); // unzip_to_file already explained why.
         }
         fastboot_buffer buf;
-        int rc = load_buf_fd(transport, fd, &buf);
-        if (rc) die("cannot load %s from flash", images[i].img_name);
+        if (!load_buf_fd(transport, fd, &buf)) {
+            die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
+        }
 
         auto update = [&](const std::string &partition) {
             do_update_signature(zip, images[i].sig_name);
@@ -964,18 +957,19 @@
     CloseArchive(zip);
 }
 
-static void do_send_signature(char* fn) {
-    char* xtn = strrchr(fn, '.');
-    if (!xtn) return;
+static void do_send_signature(const char* filename) {
+    if (android::base::EndsWith(filename, ".img") == false) {
+        return;
+    }
 
-    if (strcmp(xtn, ".img")) return;
-
-    strcpy(xtn, ".sig");
+    std::string sig_path = filename;
+    sig_path.erase(sig_path.size() - 4);
+    sig_path += ".sig";
 
     int64_t sz;
-    void* data = load_file(fn, &sz);
-    strcpy(xtn, ".img");
+    void* data = load_file(sig_path, &sz);
     if (data == nullptr) return;
+
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
@@ -985,8 +979,8 @@
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    char* fname = find_item("info", product);
-    if (fname == nullptr) die("cannot find android-info.txt");
+    std::string fname = find_item("info", product);
+    if (fname.empty()) die("cannot find android-info.txt");
 
     int64_t sz;
     void* data = load_file(fname, &sz);
@@ -997,14 +991,13 @@
     for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
         fname = find_item(images[i].part_name, product);
         fastboot_buffer buf;
-        if (load_buf(transport, fname, &buf)) {
-            if (images[i].is_optional)
-                continue;
-            die("could not load %s\n", images[i].img_name);
+        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));
         }
 
         auto flashall = [&](const std::string &partition) {
-            do_send_signature(fname);
+            do_send_signature(fname.c_str());
             if (erase_first && needs_erase(transport, partition.c_str())) {
                 fb_queue_erase(partition.c_str());
             }
@@ -1167,7 +1160,7 @@
         return;
     }
 
-    if (load_buf_fd(transport, fd, &buf)) {
+    if (!load_buf_fd(transport, fd, &buf)) {
         fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
         close(fd);
         return;
@@ -1180,7 +1173,7 @@
         fprintf(stderr, "Erase successful, but not automatically formatting.\n");
         if (errMsg) fprintf(stderr, "%s", errMsg);
     }
-    fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+    fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
 }
 
 int main(int argc, char **argv)
@@ -1441,8 +1434,8 @@
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
         } else if(!strcmp(*argv, "flash")) {
-            char *pname = argv[1];
-            char *fname = 0;
+            char* pname = argv[1];
+            std::string fname;
             require(2);
             if (argc > 2) {
                 fname = argv[2];
@@ -1451,13 +1444,13 @@
                 fname = find_item(pname, product);
                 skip(2);
             }
-            if (fname == 0) die("cannot determine image filename for '%s'", pname);
+            if (fname.empty()) die("cannot determine image filename for '%s'", pname);
 
             auto flash = [&](const std::string &partition) {
                 if (erase_first && needs_erase(transport, partition.c_str())) {
                     fb_queue_erase(partition.c_str());
                 }
-                do_flash(transport, partition.c_str(), fname);
+                do_flash(transport, partition.c_str(), fname.c_str());
             };
             do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
         } else if(!strcmp(*argv, "flash:raw")) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1932bab..c2ea551 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,7 +43,7 @@
 int fb_command_response(Transport* transport, const char* cmd, char* response);
 int fb_download_data(Transport* transport, const void* data, uint32_t size);
 int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-char *fb_get_error(void);
+const std::string fb_get_error();
 
 #define FB_COMMAND_SZ 64
 #define FB_RESPONSE_SZ 64
@@ -72,7 +72,7 @@
 char *mkmsg(const char *fmt, ...);
 __attribute__((__noreturn__)) void die(const char *fmt, ...);
 
-void get_my_path(char *path);
+std::string get_my_path();
 
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 4850b4a..bfa83b0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -36,16 +36,16 @@
 
 #include <algorithm>
 
+#include <android-base/stringprintf.h>
 #include <sparse/sparse.h>
 
 #include "fastboot.h"
 #include "transport.h"
 
-static char ERROR[128];
+static std::string g_error;
 
-char *fb_get_error(void)
-{
-    return ERROR;
+const std::string fb_get_error() {
+    return g_error;
 }
 
 static int check_response(Transport* transport, uint32_t size, char* response) {
@@ -54,14 +54,14 @@
     while (true) {
         int r = transport->Read(status, 64);
         if (r < 0) {
-            sprintf(ERROR, "status read failed (%s)", strerror(errno));
+            g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
             transport->Close();
             return -1;
         }
         status[r] = 0;
 
         if (r < 4) {
-            sprintf(ERROR, "status malformed (%d bytes)", r);
+            g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
             transport->Close();
             return -1;
         }
@@ -80,9 +80,9 @@
 
         if (!memcmp(status, "FAIL", 4)) {
             if (r > 4) {
-                sprintf(ERROR, "remote: %s", status + 4);
+                g_error = android::base::StringPrintf("remote: %s", status + 4);
             } else {
-                strcpy(ERROR, "remote failure");
+                g_error = "remote failure";
             }
             return -1;
         }
@@ -90,14 +90,14 @@
         if (!memcmp(status, "DATA", 4) && size > 0){
             uint32_t dsize = strtol(status + 4, 0, 16);
             if (dsize > size) {
-                strcpy(ERROR, "data size too large");
+                g_error = android::base::StringPrintf("data size too large (%d)", dsize);
                 transport->Close();
                 return -1;
             }
             return dsize;
         }
 
-        strcpy(ERROR,"unknown status code");
+        g_error = "unknown status code";
         transport->Close();
         break;
     }
@@ -108,7 +108,7 @@
 static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
     size_t cmdsize = strlen(cmd);
     if (cmdsize > 64) {
-        sprintf(ERROR, "command too large");
+        g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
         return -1;
     }
 
@@ -117,7 +117,7 @@
     }
 
     if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
-        sprintf(ERROR, "command write failed (%s)", strerror(errno));
+        g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
@@ -128,12 +128,12 @@
 static int _command_data(Transport* transport, const void* data, uint32_t size) {
     int r = transport->Write(data, size);
     if (r < 0) {
-        sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
+        g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
     if (r != ((int) size)) {
-        sprintf(ERROR, "data transfer failure (short transfer)");
+        g_error = "data transfer failure (short transfer)";
         transport->Close();
         return -1;
     }
@@ -182,7 +182,7 @@
 
 int fb_download_data(Transport* transport, const void* data, uint32_t size) {
     char cmd[64];
-    sprintf(cmd, "download:%08x", size);
+    snprintf(cmd, sizeof(cmd), "download:%08x", size);
     return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
 }
 
@@ -216,7 +216,7 @@
 
     if (len > TRANSPORT_BUF_SIZE) {
         if (transport_buf_len > 0) {
-            sprintf(ERROR, "internal error: transport_buf not empty\n");
+            g_error = "internal error: transport_buf not empty";
             return -1;
         }
         to_write = round_down(len, TRANSPORT_BUF_SIZE);
@@ -230,7 +230,7 @@
 
     if (len > 0) {
         if (len > TRANSPORT_BUF_SIZE) {
-            sprintf(ERROR, "internal error: too much left for transport_buf\n");
+            g_error = "internal error: too much left for transport_buf";
             return -1;
         }
         memcpy(transport_buf, ptr, len);
@@ -257,7 +257,7 @@
     }
 
     char cmd[64];
-    sprintf(cmd, "download:%08x", size);
+    snprintf(cmd, sizeof(cmd), "download:%08x", size);
     int r = _command_start(transport, cmd, size, 0);
     if (r < 0) {
         return -1;
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index 14ecd93..e56ffcf 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -167,7 +167,7 @@
 // Implements the Socket interface for TCP.
 class TcpSocket : public Socket {
   public:
-    TcpSocket(cutils_socket_t sock) : Socket(sock) {}
+    explicit TcpSocket(cutils_socket_t sock) : Socket(sock) {}
 
     bool Send(const void* data, size_t length) override;
     bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index e42c4e1..dd6fbf8 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -66,7 +66,7 @@
     int Close() override;
 
   private:
-    TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
+    explicit TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
 
     // Connects to the device and performs the initial handshake. Returns false and fills |error|
     // on failure.
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index b36bd60..53fb347 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -111,7 +111,7 @@
     int Close() override;
 
   private:
-    UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
+    explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
 
     // Performs the UDP initialization procedure. Returns true on success.
     bool InitializeProtocol(std::string* error);
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index d4824fb..6db1e27 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -89,7 +89,7 @@
 
 class LinuxUsbTransport : public Transport {
   public:
-    LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
     ~LinuxUsbTransport() override = default;
 
     ssize_t Read(void* data, size_t len) override;
diff --git a/fastboot/util_linux.cpp b/fastboot/util_linux.cpp
index b788199..2c6aedb 100644
--- a/fastboot/util_linux.cpp
+++ b/fastboot/util_linux.cpp
@@ -28,27 +28,16 @@
 
 #include "fastboot.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
 
-void get_my_path(char *path)
-{
-    char proc[64];
-    char *x;
+#include <android-base/stringprintf.h>
 
-    sprintf(proc, "/proc/%d/exe", getpid());
-    int err = readlink(proc, path, PATH_MAX - 1);
-
-    if(err <= 0) {
-        path[0] = 0;
-    } else {
-        path[err] = 0;
-        x = strrchr(path,'/');
-        if(x) x[1] = 0;
-    }
+std::string get_my_path() {
+    std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid());
+    char path[PATH_MAX + 1];
+    int rc = readlink(proc.c_str(), path, sizeof(path) - 1);
+    if (rc == -1) return "";
+    path[rc] = '\0';
+    return path;
 }
diff --git a/fastboot/util_osx.cpp b/fastboot/util_osx.cpp
index ae0b024..4bae7c4 100644
--- a/fastboot/util_osx.cpp
+++ b/fastboot/util_osx.cpp
@@ -31,19 +31,15 @@
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
-void get_my_path(char s[PATH_MAX])
-{
+std::string get_my_path() {
     CFBundleRef mainBundle = CFBundleGetMainBundle();
     CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
     CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
     CFRelease(executableURL);
 
-    CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
+    char path[PATH_MAX + 1];
+    CFStringGetFileSystemRepresentation(executablePathString, path, sizeof(PATH_MAX)-1);
     CFRelease(executablePathString);
 
-	char *x;
-    x = strrchr(s, '/');
-    if(x) x[1] = 0;
+    return path;
 }
-
-
diff --git a/fastboot/util_windows.cpp b/fastboot/util_windows.cpp
index ec52f39..3b22c55 100644
--- a/fastboot/util_windows.cpp
+++ b/fastboot/util_windows.cpp
@@ -38,14 +38,12 @@
 
 #include <windows.h>
 
-void get_my_path(char exe[PATH_MAX])
-{
-	char*  r;
+std::string get_my_path() {
+    char path[PATH_MAX + 1];
 
-	GetModuleFileName( NULL, exe, PATH_MAX-1 );
-	exe[PATH_MAX-1] = 0;
-	r = strrchr( exe, '\\' );
-	if (r)
-		*r = 0;
+    DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
+    if (result == 0 || result == sizeof(path) - 1) return "";
+    path[PATH_MAX - 1] = 0;
+
+    return path;
 }
-
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 44d8020..dfd2abc 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -27,7 +27,7 @@
 class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
 {
 public:
-    BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
+    explicit BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
             BpInterface<IFingerprintDaemonCallback>(impl) {
     }
     virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 28fff3f..d0d5630 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -7,7 +7,7 @@
     libfec \
     libfec_rs \
     libbase \
-    libmincrypt \
+    libcrypto_utils_static \
     libcrypto_static \
     libext4_utils_static \
     libsquashfs_utils
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 02aff55..b3e65cb 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -14,35 +14,32 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#include <errno.h>
+#include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <libgen.h>
 #include <time.h>
-#include <sys/swap.h>
-#include <dirent.h>
-#include <ext4.h>
-#include <ext4_sb.h>
-#include <ext4_crypt_init_extensions.h>
+#include <unistd.h>
 
-#include <linux/loop.h>
-#include <private/android_filesystem_config.h>
+#include <ext4.h>
+#include <ext4_crypt_init_extensions.h>
+#include <ext4_sb.h>
+
 #include <cutils/android_reboot.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
+#include <linux/loop.h>
 #include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
+#include <private/android_filesystem_config.h>
 
 #include "ext4_utils.h"
 #include "wipe.h"
@@ -638,11 +635,18 @@
             }
             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else {
-            ERROR("Failed to mount an un-encryptable or wiped partition on"
-                   "%s at %s options: %s error: %s\n",
-                   fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
-                   fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
-            ++error_count;
+            if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
+                ERROR("Ignoring failure to mount an un-encryptable or wiped partition on"
+                       "%s at %s options: %s error: %s\n",
+                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                       fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+            } else {
+                ERROR("Failed to mount an un-encryptable or wiped partition on"
+                       "%s at %s options: %s error: %s\n",
+                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                       fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+                ++error_count;
+            }
             continue;
         }
     }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index cf35b3f..5b92db7 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -75,6 +75,7 @@
     { "notrim",       MF_NOTRIM },
     { "formattable", MF_FORMATTABLE },
     { "slotselect",  MF_SLOTSELECT },
+    { "nofail",      MF_NOFAIL },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -491,3 +492,8 @@
 {
     return fstab->fs_mgr_flags & MF_SLOTSELECT;
 }
+
+int fs_mgr_is_nofail(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOFAIL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ba0e097..775f36d 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_NOFAIL       0x40000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index b5141c9..72554a8 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -14,29 +14,30 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#include <errno.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <libgen.h>
 #include <time.h>
+#include <unistd.h>
 
 #include <android-base/file.h>
-#include <private/android_filesystem_config.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
 
 #include "fec/io.h"
 
@@ -83,48 +84,45 @@
 
 extern struct fs_info info;
 
-static RSAPublicKey *load_key(const char *path)
+static RSA *load_key(const char *path)
 {
-    RSAPublicKey* key = static_cast<RSAPublicKey*>(malloc(sizeof(RSAPublicKey)));
-    if (!key) {
-        ERROR("Can't malloc key\n");
-        return NULL;
-    }
+    uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
 
     FILE* f = fopen(path, "r");
     if (!f) {
         ERROR("Can't open '%s'\n", path);
-        free(key);
+        free(key_data);
         return NULL;
     }
 
-    if (!fread(key, sizeof(*key), 1, f)) {
+    if (!fread(key_data, sizeof(key_data), 1, f)) {
         ERROR("Could not read key!\n");
         fclose(f);
-        free(key);
-        return NULL;
-    }
-
-    if (key->len != RSANUMWORDS) {
-        ERROR("Invalid key length %d\n", key->len);
-        fclose(f);
-        free(key);
+        free(key_data);
         return NULL;
     }
 
     fclose(f);
+
+    RSA* key = NULL;
+    if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
+        ERROR("Could not parse key!\n");
+        free(key_data);
+        return NULL;
+    }
+
     return key;
 }
 
-static int verify_table(const uint8_t *signature, const char *table,
-        uint32_t table_length)
+static int verify_table(const uint8_t *signature, size_t signature_size,
+        const char *table, uint32_t table_length)
 {
-    RSAPublicKey *key;
-    uint8_t hash_buf[SHA256_DIGEST_SIZE];
+    RSA *key;
+    uint8_t hash_buf[SHA256_DIGEST_LENGTH];
     int retval = -1;
 
     // Hash the table
-    SHA256_hash((uint8_t*)table, table_length, hash_buf);
+    SHA256((uint8_t*)table, table_length, hash_buf);
 
     // Now get the public key from the keyfile
     key = load_key(VERITY_TABLE_RSA_KEY);
@@ -134,11 +132,8 @@
     }
 
     // verify the result
-    if (!RSA_verify(key,
-                    signature,
-                    RSANUMBYTES,
-                    (uint8_t*) hash_buf,
-                    SHA256_DIGEST_SIZE)) {
+    if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
+                    signature_size, key)) {
         ERROR("Couldn't verify table\n");
         goto out;
     }
@@ -146,7 +141,7 @@
     retval = 0;
 
 out:
-    free(key);
+    RSA_free(key);
     return retval;
 }
 
@@ -217,7 +212,7 @@
 }
 
 struct verity_table_params {
-    const char *table;
+    char *table;
     int mode;
     struct fec_ecc_metadata ecc;
     const char *ecc_dev;
@@ -610,8 +605,8 @@
     off64_t offset = 0;
     struct fec_handle *f = NULL;
     struct fec_verity_metadata verity;
-    uint8_t curr[SHA256_DIGEST_SIZE];
-    uint8_t prev[SHA256_DIGEST_SIZE];
+    uint8_t curr[SHA256_DIGEST_LENGTH];
+    uint8_t prev[SHA256_DIGEST_LENGTH];
 
     *match = 1;
 
@@ -629,7 +624,7 @@
         goto out;
     }
 
-    SHA256_hash(verity.signature, RSANUMBYTES, curr);
+    SHA256(verity.signature, sizeof(verity.signature), curr);
 
     if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
             basename(fstab->mount_point)) >= (int)sizeof(tag)) {
@@ -637,7 +632,7 @@
         goto out;
     }
 
-    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
             &offset) < 0) {
         goto out;
     }
@@ -656,7 +651,7 @@
         goto out;
     }
 
-    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+    *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
 
     if (!*match) {
         /* update current signature hash */
@@ -849,15 +844,42 @@
     return rc;
 }
 
+static void update_verity_table_blk_device(char *blk_device, char **table)
+{
+    std::string result, word;
+    auto tokens = android::base::Split(*table, " ");
+
+    for (const auto token : tokens) {
+        if (android::base::StartsWith(token, "/dev/block/") &&
+            android::base::StartsWith(blk_device, token.c_str())) {
+            word = blk_device;
+        } else {
+            word = token;
+        }
+
+        if (result.empty()) {
+            result = word;
+        } else {
+            result += " " + word;
+        }
+    }
+
+    if (result.empty()) {
+        return;
+    }
+
+    free(*table);
+    *table = strdup(result.c_str());
+}
+
 int fs_mgr_setup_verity(struct fstab_rec *fstab)
 {
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
-    char *invalid_table = NULL;
     char *verity_blk_name = NULL;
     struct fec_handle *f = NULL;
     struct fec_verity_metadata verity;
-    struct verity_table_params params;
+    struct verity_table_params params = { .table = NULL };
 
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -918,8 +940,17 @@
         params.mode = VERITY_MODE_EIO;
     }
 
+    if (!verity.table) {
+        goto out;
+    }
+
+    params.table = strdup(verity.table);
+    if (!params.table) {
+        goto out;
+    }
+
     // verify the signature on the table
-    if (verify_table(verity.signature, verity.table,
+    if (verify_table(verity.signature, sizeof(verity.signature), params.table,
             verity.table_length) < 0) {
         if (params.mode == VERITY_MODE_LOGGING) {
             // the user has been warned, allow mounting without dm-verity
@@ -928,20 +959,18 @@
         }
 
         // invalidate root hash and salt to trigger device-specific recovery
-        invalid_table = strdup(verity.table);
-
-        if (!invalid_table ||
-                invalidate_table(invalid_table, verity.table_length) < 0) {
+        if (invalidate_table(params.table, verity.table_length) < 0) {
             goto out;
         }
-
-        params.table = invalid_table;
-    } else {
-        params.table = verity.table;
     }
 
     INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
 
+    if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
+        // Update the verity params using the actual block device path
+        update_verity_table_blk_device(fstab->blk_device, &params.table);
+    }
+
     // load the verity mapping table
     if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
             format_verity_table) == 0) {
@@ -1007,7 +1036,7 @@
     }
 
     fec_close(f);
-    free(invalid_table);
+    free(params.table);
     free(verity_blk_name);
 
     return retval;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 27fccf7..c5e1f32 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -105,6 +105,7 @@
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_nofail(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 
 int fs_mgr_do_format(struct fstab_rec *fstab);
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
index 8645fc2..8167d19 100644
--- a/gatekeeperd/IUserManager.cpp
+++ b/gatekeeperd/IUserManager.cpp
@@ -27,7 +27,7 @@
 class BpUserManager : public BpInterface<IUserManager>
 {
 public:
-    BpUserManager(const sp<IBinder>& impl) :
+    explicit BpUserManager(const sp<IBinder>& impl) :
             BpInterface<IUserManager>(impl) {
     }
     virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
diff --git a/healthd/Android.mk b/healthd/Android.mk
index ddd9f1f..127f39e 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -8,6 +8,8 @@
 LOCAL_CFLAGS := -Werror
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libbinder
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -15,7 +17,7 @@
 LOCAL_MODULE := libbatterymonitor
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils
+LOCAL_STATIC_LIBRARIES := libutils libbinder
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/include/binderwrapper/binder_wrapper.h b/include/binderwrapper/binder_wrapper.h
index ccda825..a104bff 100644
--- a/include/binderwrapper/binder_wrapper.h
+++ b/include/binderwrapper/binder_wrapper.h
@@ -70,7 +70,7 @@
   // is currently registered for |binder|, it will be replaced.
   virtual bool RegisterForDeathNotifications(
       const sp<IBinder>& binder,
-      const base::Closure& callback) = 0;
+      const ::base::Closure& callback) = 0;
 
   // Unregisters the callback, if any, for |binder|.
   virtual bool UnregisterForDeathNotifications(const sp<IBinder>& binder) = 0;
diff --git a/include/binderwrapper/stub_binder_wrapper.h b/include/binderwrapper/stub_binder_wrapper.h
index 01c9648..9d4578e 100644
--- a/include/binderwrapper/stub_binder_wrapper.h
+++ b/include/binderwrapper/stub_binder_wrapper.h
@@ -98,7 +98,7 @@
                        const sp<IBinder>& binder) override;
   sp<BBinder> CreateLocalBinder() override;
   bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const base::Closure& callback) override;
+                                     const ::base::Closure& callback) override;
   bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
   uid_t GetCallingUid() override;
   pid_t GetCallingPid() override;
@@ -119,7 +119,7 @@
 
   // Map from binder handle to the callback that should be invoked on binder
   // death.
-  std::map<sp<IBinder>, base::Closure> death_callbacks_;
+  std::map<sp<IBinder>, ::base::Closure> death_callbacks_;
 
   // Values to return from GetCallingUid() and GetCallingPid();
   uid_t calling_uid_;
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index 25b233e..acedf73 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -12,6 +12,10 @@
 
 #include <stddef.h>
 
+#if defined(__BIONIC__)
+#include <linux/ashmem.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -26,20 +30,4 @@
 }
 #endif
 
-#ifndef __ASHMEMIOC	/* in case someone included <linux/ashmem.h> too */
-
-#define ASHMEM_NAME_LEN		256
-
-#define ASHMEM_NAME_DEF		"dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED	0
-#define ASHMEM_WAS_PURGED	1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_IS_UNPINNED	0
-#define ASHMEM_IS_PINNED	1
-
-#endif	/* ! __ASHMEMIOC */
-
 #endif	/* _CUTILS_ASHMEM_H */
diff --git a/include/log/log.h b/include/log/log.h
index e606a84..045feca 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -614,11 +614,11 @@
  * The stuff in the rest of this file should not be used directly.
  */
 
-#define android_printLog(prio, tag, fmt...) \
-    __android_log_print(prio, tag, fmt)
+#define android_printLog(prio, tag, ...) \
+    __android_log_print(prio, tag, __VA_ARGS__)
 
-#define android_vprintLog(prio, cond, tag, fmt...) \
-    __android_log_vprint(prio, tag, fmt)
+#define android_vprintLog(prio, cond, tag, ...) \
+    __android_log_vprint(prio, tag, __VA_ARGS__)
 
 /* XXX Macros to work around syntax errors in places where format string
  * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
@@ -635,9 +635,9 @@
  */
 #define __android_rest(first, ...)               , ## __VA_ARGS__
 
-#define android_printAssert(cond, tag, fmt...) \
+#define android_printAssert(cond, tag, ...) \
     __android_log_assert(cond, tag, \
-        __android_second(0, ## fmt, NULL) __android_rest(fmt))
+        __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
 
 #define android_writeLog(prio, tag, text) \
     __android_log_write(prio, tag, text)
diff --git a/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h
deleted file mode 100644
index b0d91cd..0000000
--- a/include/mincrypt/dsa_sig.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-
-#include "mincrypt/p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if input sig is not a valid ASN.1 sequence
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
deleted file mode 100644
index c813b44..0000000
--- a/include/mincrypt/hash-internal.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif  // __cplusplus
-
-struct HASH_CTX;  // forward decl
-
-typedef struct HASH_VTAB {
-  void (* const init)(struct HASH_CTX*);
-  void (* const update)(struct HASH_CTX*, const void*, int);
-  const uint8_t* (* const final)(struct HASH_CTX*);
-  const uint8_t* (* const hash)(const void*, int, uint8_t*);
-  int size;
-} HASH_VTAB;
-
-typedef struct HASH_CTX {
-  const HASH_VTAB * f;
-  uint64_t count;
-  uint8_t buf[64];
-  uint32_t state[8];  // upto SHA2
-} HASH_CTX;
-
-#define HASH_init(ctx) (ctx)->f->init(ctx)
-#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
-#define HASH_final(ctx) (ctx)->f->final(ctx)
-#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
-#define HASH_size(ctx) (ctx)->f->size
-
-#ifdef __cplusplus
-}
-#endif  // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h
deleted file mode 100644
index 465a1b9..0000000
--- a/include/mincrypt/p256.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-
-// Collection of routines manipulating 256 bit unsigned integers.
-// Just enough to implement ecdsa-p256 and related algorithms.
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define P256_BITSPERDIGIT 32
-#define P256_NDIGITS 8
-#define P256_NBYTES 32
-
-typedef int p256_err;
-typedef uint32_t p256_digit;
-typedef int32_t p256_sdigit;
-typedef uint64_t p256_ddigit;
-typedef int64_t p256_sddigit;
-
-// Defining p256_int as struct to leverage struct assigment.
-typedef struct {
-  p256_digit a[P256_NDIGITS];
-} p256_int;
-
-extern const p256_int SECP256r1_n;  // Curve order
-extern const p256_int SECP256r1_p;  // Curve prime
-extern const p256_int SECP256r1_b;  // Curve param
-
-// Initialize a p256_int to zero.
-void p256_init(p256_int* a);
-
-// Clear a p256_int to zero.
-void p256_clear(p256_int* a);
-
-// Return bit. Index 0 is least significant.
-int p256_get_bit(const p256_int* a, int index);
-
-// b := a % MOD
-void p256_mod(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// c := a * (top_b | b) % MOD
-void p256_modmul(
-    const p256_int* MOD,
-    const p256_int* a,
-    const p256_digit top_b,
-    const p256_int* b,
-    p256_int* c);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-void p256_modinv(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-// Faster than p256_modinv()
-void p256_modinv_vartime(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// b := a << (n % P256_BITSPERDIGIT)
-// Returns the bits shifted out of most significant digit.
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
-
-// b := a >> (n % P256_BITSPERDIGIT)
-void p256_shr(const p256_int* a, int n, p256_int* b);
-
-int p256_is_zero(const p256_int* a);
-int p256_is_odd(const p256_int* a);
-int p256_is_even(const p256_int* a);
-
-// Returns -1, 0 or 1.
-int p256_cmp(const p256_int* a, const p256_int *b);
-
-// c: = a - b
-// Returns -1 on borrow.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + b
-// Returns 1 on carry.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + (single digit)b
-// Returns carry 1 on carry.
-int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
-
-// ec routines.
-
-// {out_x,out_y} := nG
-void p256_base_point_mul(const p256_int *n,
-                         p256_int *out_x,
-                         p256_int *out_y);
-
-// {out_x,out_y} := n{in_x,in_y}
-void p256_point_mul(const p256_int *n,
-                    const p256_int *in_x,
-                    const p256_int *in_y,
-                    p256_int *out_x,
-                    p256_int *out_y);
-
-// {out_x,out_y} := n1G + n2{in_x,in_y}
-void p256_points_mul_vartime(
-    const p256_int *n1, const p256_int *n2,
-    const p256_int *in_x, const p256_int *in_y,
-    p256_int *out_x, p256_int *out_y);
-
-// Return whether point {x,y} is on curve.
-int p256_is_valid_point(const p256_int* x, const p256_int* y);
-
-// Outputs big-endian binary form. No leading zero skips.
-void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
-
-// Reads from big-endian binary form,
-// thus pre-pad with leading zeros if short.
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
-
-#define P256_DIGITS(x) ((x)->a)
-#define P256_DIGIT(x,y) ((x)->a[y])
-
-#define P256_ZERO {{0}}
-#define P256_ONE {{1}}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h
deleted file mode 100644
index da339fa..0000000
--- a/include/mincrypt/p256_ecdsa.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-
-// Using current directory as relative include path here since
-// this code typically gets lifted into a variety of build systems
-// and directory structures.
-#include "p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if {r,s} is not a signature on message for
-// public key {key_x,key_y}.
-//
-// Note: message is a p256_int.
-// Convert from a binary string using p256_from_bin().
-int p256_ecdsa_verify(const p256_int* key_x,
-                      const p256_int* key_y,
-                      const p256_int* message,
-                      const p256_int* r, const p256_int* s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
deleted file mode 100644
index 3d0556b..0000000
--- a/include/mincrypt/rsa.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* rsa.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-
-#include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RSANUMBYTES 256           /* 2048 bit key length */
-#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
-
-typedef struct RSAPublicKey {
-    int len;                  /* Length of n[] in number of uint32_t */
-    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
-    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
-    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
-    int exponent;             /* 3 or 65537 */
-} RSAPublicKey;
-
-int RSA_verify(const RSAPublicKey *key,
-               const uint8_t* signature,
-               const int len,
-               const uint8_t* hash,
-               const int hash_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
deleted file mode 100644
index ef60aab..0000000
--- a/include/mincrypt/sha.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA_CTX;
-
-void SHA_init(SHA_CTX* ctx);
-void SHA_update(SHA_CTX* ctx, const void* data, int len);
-const uint8_t* SHA_final(SHA_CTX* ctx);
-
-// Convenience method. Returns digest address.
-// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA_DIGEST_SIZE 20
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
deleted file mode 100644
index 3a87c31..0000000
--- a/include/mincrypt/sha256.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA256_CTX;
-
-void SHA256_init(SHA256_CTX* ctx);
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
-const uint8_t* SHA256_final(SHA256_CTX* ctx);
-
-// Convenience method. Returns digest address.
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA256_DIGEST_SIZE 32
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/libcutils/atomic.c b/include/private/canned_fs_config.h
similarity index 61%
copy from libcutils/atomic.c
copy to include/private/canned_fs_config.h
index d34aa00..d9f51ca 100644
--- a/libcutils/atomic.c
+++ b/include/private/canned_fs_config.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#ifndef _CANNED_FS_CONFIG_H
+#define _CANNED_FS_CONFIG_H
 
-#define ANDROID_ATOMIC_INLINE
+#include <inttypes.h>
 
-#include <cutils/atomic.h>
+int load_canned_fs_config(const char* fn);
+void canned_fs_config(const char* path, int dir, const char* target_out_path,
+                      unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities);
+
+#endif
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
deleted file mode 100644
index 0854775..0000000
--- a/include/utils/ashmem.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* utils/ashmem.h
- **
- ** Copyright 2008 The Android Open Source Project
- **
- ** This file is dual licensed.  It may be redistributed and/or modified
- ** under the terms of the Apache 2.0 License OR version 2 of the GNU
- ** General Public License.
- */
-
-#ifndef _UTILS_ASHMEM_H
-#define _UTILS_ASHMEM_H
-
-#include <linux/limits.h>
-#include <linux/ioctl.h>
-
-#define ASHMEM_NAME_LEN		256
-
-#define ASHMEM_NAME_DEF		"dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_REAPED	0
-#define ASHMEM_WAS_REAPED	1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_NOW_UNPINNED	0
-#define ASHMEM_NOW_PINNED	1
-
-#define __ASHMEMIOC		0x77
-
-#define ASHMEM_SET_NAME		_IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
-#define ASHMEM_GET_NAME		_IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, size_t)
-#define ASHMEM_GET_SIZE		_IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned long)
-#define ASHMEM_GET_PROT_MASK	_IO(__ASHMEMIOC, 6)
-#define ASHMEM_PIN		_IO(__ASHMEMIOC, 7)
-#define ASHMEM_UNPIN		_IO(__ASHMEMIOC, 8)
-#define ASHMEM_ISPINNED		_IO(__ASHMEMIOC, 9)
-#define ASHMEM_PURGE_ALL_CACHES	_IO(__ASHMEMIOC, 10)
-
-#endif	/* _UTILS_ASHMEM_H */
diff --git a/init/Android.mk b/init/Android.mk
index 66ce8a8..e1a3638 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -95,7 +95,7 @@
     libc \
     libselinux \
     liblog \
-    libmincrypt \
+    libcrypto_utils_static \
     libcrypto_static \
     libc++_static \
     libdl \
diff --git a/init/action.cpp b/init/action.cpp
index 510ea89..b7e431c 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -264,7 +264,7 @@
 
 class EventTrigger : public Trigger {
 public:
-    EventTrigger(const std::string& trigger) : trigger_(trigger) {
+    explicit EventTrigger(const std::string& trigger) : trigger_(trigger) {
     }
     bool CheckTriggers(const Action& action) const override {
         return action.CheckEventTrigger(trigger_);
@@ -288,7 +288,7 @@
 
 class BuiltinTrigger : public Trigger {
 public:
-    BuiltinTrigger(Action* action) : action_(action) {
+    explicit BuiltinTrigger(Action* action) : action_(action) {
     }
     bool CheckTriggers(const Action& action) const override {
         return action_ == &action;
diff --git a/init/devices.cpp b/init/devices.cpp
index e74140b..1410e3b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -43,6 +43,7 @@
 #include <sys/wait.h>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <cutils/list.h>
 #include <cutils/uevent.h>
 
@@ -130,49 +131,6 @@
     return 0;
 }
 
-void fixup_sys_perms(const char *upath)
-{
-    char buf[512];
-    struct listnode *node;
-    struct perms_ *dp;
-
-    /* upaths omit the "/sys" that paths in this list
-     * contain, so we add 4 when comparing...
-     */
-    list_for_each(node, &sys_perms) {
-        dp = &(node_to_item(node, struct perm_node, plist))->dp;
-        if (dp->prefix) {
-            if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
-                continue;
-        } else if (dp->wildcard) {
-            if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
-                continue;
-        } else {
-            if (strcmp(upath, dp->name + 4))
-                continue;
-        }
-
-        if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
-            break;
-
-        snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr);
-        INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
-        chown(buf, dp->uid, dp->gid);
-        chmod(buf, dp->perm);
-    }
-
-    // Now fixup SELinux file labels
-    int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
-    if ((len < 0) || ((size_t) len >= sizeof(buf))) {
-        // Overflow
-        return;
-    }
-    if (access(buf, F_OK) == 0) {
-        INFO("restorecon_recursive: %s\n", buf);
-        restorecon_recursive(buf);
-    }
-}
-
 static bool perm_path_matches(const char *path, struct perms_ *dp)
 {
     if (dp->prefix) {
@@ -189,6 +147,44 @@
     return false;
 }
 
+static bool match_subsystem(perms_* dp, const char* pattern,
+                            const char* path, const char* subsystem) {
+    if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
+        return false;
+    }
+
+    std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
+    return perm_path_matches(subsys_path.c_str(), dp);
+}
+
+static void fixup_sys_perms(const char* upath, const char* subsystem) {
+    // upaths omit the "/sys" that paths in this list
+    // contain, so we prepend it...
+    std::string path = std::string(SYSFS_PREFIX) + upath;
+
+    listnode* node;
+    list_for_each(node, &sys_perms) {
+        perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
+        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+            ; // matched
+        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+            ; // matched
+        } else if (!perm_path_matches(path.c_str(), dp)) {
+            continue;
+        }
+
+        std::string attr_file = path + "/" + dp->attr;
+        INFO("fixup %s %d %d 0%o\n", attr_file.c_str(), dp->uid, dp->gid, dp->perm);
+        chown(attr_file.c_str(), dp->uid, dp->gid);
+        chmod(attr_file.c_str(), dp->perm);
+    }
+
+    if (access(path.c_str(), F_OK) == 0) {
+        INFO("restorecon_recursive: %s\n", path.c_str());
+        restorecon_recursive(path.c_str());
+    }
+}
+
 static mode_t get_device_perm(const char *path, const char **links,
                 unsigned *uid, unsigned *gid)
 {
@@ -244,7 +240,11 @@
 
     mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
-    selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
+    if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+        ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
+                path, strerror(errno));
+        return;
+    }
     setfscreatecon(secontext);
 
     dev = makedev(major, minor);
@@ -254,14 +254,19 @@
      * racy. Fixing the gid race at least fixed the issue with system_server
      * opening dynamic input devices under the AID_INPUT gid. */
     setegid(gid);
-    mknod(path, mode, dev);
+    /* If the node already exists update its SELinux label to handle cases when
+     * it was created with the wrong context during coldboot procedure. */
+    if (mknod(path, mode, dev) && (errno == EEXIST)) {
+        if (lsetfilecon(path, secontext)) {
+            ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
+                    secontext, path, strerror(errno));
+        }
+    }
     chown(path, uid, -1);
     setegid(AID_ROOT);
 
-    if (secontext) {
-        freecon(secontext);
-        setfscreatecon(NULL);
-    }
+    freecon(secontext);
+    setfscreatecon(NULL);
 }
 
 static void add_platform_device(const char *path)
@@ -738,7 +743,7 @@
 static void handle_device_event(struct uevent *uevent)
 {
     if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
-        fixup_sys_perms(uevent->path);
+        fixup_sys_perms(uevent->path, uevent->subsystem);
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
         handle_block_device_event(uevent);
diff --git a/init/init.cpp b/init/init.cpp
index 9b7d108..78c33d5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -139,59 +139,19 @@
             });
 }
 
-static void msg_start(const std::string& name)
-{
-    Service* svc = nullptr;
-    std::vector<std::string> vargs;
-
-    size_t colon_pos = name.find(':');
-    if (colon_pos == std::string::npos) {
-        svc = ServiceManager::GetInstance().FindServiceByName(name);
-    } else {
-        std::string service_name(name.substr(0, colon_pos));
-        std::string args(name.substr(colon_pos + 1));
-        vargs = android::base::Split(args, " ");
-
-        svc = ServiceManager::GetInstance().FindServiceByName(service_name);
-    }
-
-    if (svc) {
-        svc->Start(vargs);
-    } else {
-        ERROR("no such service '%s'\n", name.c_str());
-    }
-}
-
-static void msg_stop(const std::string& name)
-{
+void handle_control_message(const std::string& msg, const std::string& name) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
-    if (svc) {
-        svc->Stop();
-    } else {
+    if (svc == nullptr) {
         ERROR("no such service '%s'\n", name.c_str());
+        return;
     }
-}
 
-static void msg_restart(const std::string& name)
-{
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
-    if (svc) {
-        svc->Restart();
-    } else {
-        ERROR("no such service '%s'\n", name.c_str());
-    }
-}
-
-void handle_control_message(const std::string& msg, const std::string& arg)
-{
     if (msg == "start") {
-        msg_start(arg);
+        svc->Start();
     } else if (msg == "stop") {
-        msg_stop(arg);
+        svc->Stop();
     } else if (msg == "restart") {
-        msg_restart(arg);
+        svc->Restart();
     } else {
         ERROR("unknown control msg '%s'\n", msg.c_str());
     }
diff --git a/init/service.cpp b/init/service.cpp
index e509f46..f5b8b00 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -316,7 +316,7 @@
     return (this->*handler)(args, err);
 }
 
-bool Service::Start(const std::vector<std::string>& dynamic_args) {
+bool Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -352,13 +352,6 @@
         return false;
     }
 
-    if ((!(flags_ & SVC_ONESHOT)) && !dynamic_args.empty()) {
-        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
-              args_[0].c_str());
-        flags_ |= SVC_DISABLED;
-        return false;
-    }
-
     std::string scon;
     if (!seclabel_.empty()) {
         scon = seclabel_;
@@ -480,9 +473,6 @@
         for (const auto& s : args_) {
             strs.push_back(const_cast<char*>(s.c_str()));
         }
-        for (const auto& s : dynamic_args) {
-            strs.push_back(const_cast<char*>(s.c_str()));
-        }
         strs.push_back(nullptr);
         if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
             ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
@@ -511,11 +501,6 @@
     return true;
 }
 
-bool Service::Start() {
-    const std::vector<std::string> null_dynamic_args;
-    return Start(null_dynamic_args);
-}
-
 bool Service::StartIfNotDisabled() {
     if (!(flags_ & SVC_DISABLED)) {
         return Start();
diff --git a/init/service.h b/init/service.h
index b003ca0..d6ce664 100644
--- a/init/service.h
+++ b/init/service.h
@@ -76,7 +76,6 @@
             const std::string& seclabel,  const std::vector<std::string>& args);
 
     bool HandleLine(const std::vector<std::string>& args, std::string* err);
-    bool Start(const std::vector<std::string>& dynamic_args);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index a8a7c4a..632b1b6 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -95,7 +95,7 @@
 	BacktraceOffline.cpp \
 
 # Use shared llvm library on device to save space.
-libbacktrace_offline_shared_libraries := \
+libbacktrace_offline_shared_libraries_target := \
 	libbacktrace \
 	libbase \
 	liblog \
@@ -103,47 +103,20 @@
 	libutils \
 	libLLVM \
 
-libbacktrace_offline_static_libraries := \
+libbacktrace_offline_static_libraries_target := \
 	libziparchive \
 	libz \
 
-module := libbacktrace_offline
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-
-libbacktrace_offline_shared_libraries := \
-	libbacktrace \
-	libbase \
-	liblog \
-	libunwind \
-	libziparchive-host \
-
 # Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
 # which is not included in the prebuilt.
-libbacktrace_offline_static_libraries := \
-	libLLVMObject \
-	libLLVMBitReader \
-	libLLVMMC \
-	libLLVMMCParser \
-	libLLVMCore \
-	libLLVMSupport \
-
-module := libbacktrace_offline
-build_type := host
-libbacktrace_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-
-libbacktrace_offline_shared_libraries :=
-libbacktrace_offline_static_libraries := \
+libbacktrace_offline_static_libraries_host := \
 	libbacktrace \
-	libbase \
-	libcutils \
-	liblog \
 	libunwind \
-	liblzma \
-	libziparchive \
+	libziparchive-host \
 	libz \
+	libbase \
+	liblog \
+	libutils \
 	libLLVMObject \
 	libLLVMBitReader \
 	libLLVMMC \
@@ -154,6 +127,9 @@
 module := libbacktrace_offline
 build_type := target
 build_target := STATIC_LIBRARY
+libbacktrace_offline_multilib := both
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
 include $(LOCAL_PATH)/Android.build.mk
 
 #-------------------------------------------------------------------------
@@ -200,13 +176,33 @@
 backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
-	libbacktrace_offline \
 	libbase \
 	libcutils \
+	liblog \
 	libunwind \
 
 backtrace_test_shared_libraries_target += \
 	libdl \
+	libutils \
+	libLLVM \
+
+backtrace_test_static_libraries := \
+	libbacktrace_offline \
+
+backtrace_test_static_libraries_target := \
+	libziparchive \
+	libz \
+
+backtrace_test_static_libraries_host := \
+	libziparchive-host \
+	libz \
+	libutils \
+	libLLVMObject \
+	libLLVMBitReader \
+	libLLVMMC \
+	libLLVMMCParser \
+	libLLVMCore \
+	libLLVMSupport \
 
 backtrace_test_ldlibs_host += \
 	-ldl \
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index ba86632..19551dc 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <inttypes.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -46,8 +47,8 @@
 }
 
 bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
-  unsigned long int start;
-  unsigned long int end;
+  uint64_t start;
+  uint64_t end;
   char permissions[5];
   int name_pos;
 
@@ -56,14 +57,14 @@
 // __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
-  if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+  if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c  %n",
              &start, &end, permissions, &name_pos) != 3) {
 #else
 // Linux /proc/<pid>/maps lines:
 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
-  if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d %n",
+  if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
              &start, &end, permissions, &name_pos) != 3) {
 #endif
     return false;
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 9a4f622..c2b68bc 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -665,7 +665,7 @@
 
 class ScopedZiparchiveHandle {
  public:
-  ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
+  explicit ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
   }
 
   ~ScopedZiparchiveHandle() {
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 09a721d..b4dc48d 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -33,7 +33,7 @@
 #define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
 #define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
 
-static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+static bool ReadData(int fd, off_t place, uint64_t *data) {
   if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
     return false;
   }
@@ -71,12 +71,13 @@
       total_pss = 0;
       break;
     }
-    for (size_t page = start/pagesize; page < end/pagesize; page++) {
+    for (off_t page = static_cast<off_t>(start/pagesize);
+         page < static_cast<off_t>(end/pagesize); page++) {
       uint64_t data;
       if (ReadData(pagemap_fd, page, &data)) {
         if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
           uint64_t count;
-          if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+          if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
             total_pss += (count >= 1) ? pagesize / count : 0;
           }
         }
diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc
index 1c51822..f93f183 100644
--- a/libbinderwrapper/real_binder_wrapper.cc
+++ b/libbinderwrapper/real_binder_wrapper.cc
@@ -29,7 +29,7 @@
 // be awkward.
 class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient {
  public:
-  explicit DeathRecipient(const base::Closure& callback)
+  explicit DeathRecipient(const ::base::Closure& callback)
       : callback_(callback) {}
   ~DeathRecipient() = default;
 
@@ -40,7 +40,7 @@
 
  private:
   // Callback to run in response to binder death.
-  base::Closure callback_;
+  ::base::Closure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(DeathRecipient);
 };
@@ -85,7 +85,7 @@
 
 bool RealBinderWrapper::RegisterForDeathNotifications(
     const sp<IBinder>& binder,
-    const base::Closure& callback) {
+    const ::base::Closure& callback) {
   sp<DeathRecipient> recipient(new DeathRecipient(callback));
   if (binder->linkToDeath(recipient) != OK) {
     LOG(ERROR) << "Failed to register for death notifications on "
diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h
index ea08371..1675432 100644
--- a/libbinderwrapper/real_binder_wrapper.h
+++ b/libbinderwrapper/real_binder_wrapper.h
@@ -36,7 +36,7 @@
                        const sp<IBinder>& binder) override;
   sp<BBinder> CreateLocalBinder() override;
   bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const base::Closure& callback) override;
+                                     const ::base::Closure& callback) override;
   bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
   uid_t GetCallingUid() override;
   pid_t GetCallingPid() override;
diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc
index 87c6ab7..8e75f62 100644
--- a/libbinderwrapper/stub_binder_wrapper.cc
+++ b/libbinderwrapper/stub_binder_wrapper.cc
@@ -64,7 +64,7 @@
 
 bool StubBinderWrapper::RegisterForDeathNotifications(
     const sp<IBinder>& binder,
-    const base::Closure& callback) {
+    const ::base::Closure& callback) {
   death_callbacks_[binder] = callback;
   return true;
 }
diff --git a/libcrypto_utils/Android.mk b/libcrypto_utils/Android.mk
new file mode 100644
index 0000000..5e9763f
--- /dev/null
+++ b/libcrypto_utils/Android.mk
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto-host
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils_static
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcrypto_static
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils_static
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcrypto_static
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcrypto_utils/android_pubkey.c b/libcrypto_utils/android_pubkey.c
new file mode 100644
index 0000000..3052e52
--- /dev/null
+++ b/libcrypto_utils/android_pubkey.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <crypto_utils/android_pubkey.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+
+// Better safe than sorry.
+#if (ANDROID_PUBKEY_MODULUS_SIZE % 4) != 0
+#error RSA modulus size must be multiple of the word size!
+#endif
+
+// Size of the RSA modulus in words.
+#define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
+
+// This file implements encoding and decoding logic for Android's custom RSA
+// public key binary format. Public keys are stored as a sequence of
+// little-endian 32 bit words. Note that Android only supports little-endian
+// processors, so we don't do any byte order conversions when parsing the binary
+// struct.
+typedef struct RSAPublicKey {
+    // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
+    uint32_t modulus_size_words;
+
+    // Precomputed montgomery parameter: -1 / n[0] mod 2^32
+    uint32_t n0inv;
+
+    // RSA modulus as a little-endian array.
+    uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
+
+    // Montgomery parameter R^2 as a little-endian array of little-endian words.
+    uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
+
+    // RSA modulus: 3 or 65537
+    uint32_t exponent;
+} RSAPublicKey;
+
+// Reverses byte order in |buffer|.
+static void reverse_bytes(uint8_t* buffer, size_t size) {
+  for (size_t i = 0; i < (size + 1) / 2; ++i) {
+    uint8_t tmp = buffer[i];
+    buffer[i] = buffer[size - i - 1];
+    buffer[size - i - 1] = tmp;
+  }
+}
+
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key) {
+  const RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+  bool ret = false;
+  uint8_t modulus_buffer[ANDROID_PUBKEY_MODULUS_SIZE];
+  RSA* new_key = RSA_new();
+  if (!new_key) {
+    goto cleanup;
+  }
+
+  // Check |size| is large enough and the modulus size is correct.
+  if (size < sizeof(RSAPublicKey)) {
+    goto cleanup;
+  }
+  if (key_struct->modulus_size_words != ANDROID_PUBKEY_MODULUS_SIZE_WORDS) {
+    goto cleanup;
+  }
+
+  // Convert the modulus to big-endian byte order as expected by BN_bin2bn.
+  memcpy(modulus_buffer, key_struct->modulus, sizeof(modulus_buffer));
+  reverse_bytes(modulus_buffer, sizeof(modulus_buffer));
+  new_key->n = BN_bin2bn(modulus_buffer, sizeof(modulus_buffer), NULL);
+  if (!new_key->n) {
+    goto cleanup;
+  }
+
+  // Read the exponent.
+  new_key->e = BN_new();
+  if (!new_key->e || !BN_set_word(new_key->e, key_struct->exponent)) {
+    goto cleanup;
+  }
+
+  // Note that we don't extract the montgomery parameters n0inv and rr from
+  // the RSAPublicKey structure. They assume a word size of 32 bits, but
+  // BoringSSL may use a word size of 64 bits internally, so we're lacking the
+  // top 32 bits of n0inv in general. For now, we just ignore the parameters
+  // and have BoringSSL recompute them internally. More sophisticated logic can
+  // be added here if/when we want the additional speedup from using the
+  // pre-computed montgomery parameters.
+
+  *key = new_key;
+  ret = true;
+
+cleanup:
+  if (!ret && new_key) {
+    RSA_free(new_key);
+  }
+  return ret;
+}
+
+static bool android_pubkey_encode_bignum(const BIGNUM* num, uint8_t* buffer) {
+  if (!BN_bn2bin_padded(buffer, ANDROID_PUBKEY_MODULUS_SIZE, num)) {
+    return false;
+  }
+
+  reverse_bytes(buffer, ANDROID_PUBKEY_MODULUS_SIZE);
+  return true;
+}
+
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size) {
+  RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+  bool ret = false;
+  BN_CTX* ctx = BN_CTX_new();
+  BIGNUM* r32 = BN_new();
+  BIGNUM* n0inv = BN_new();
+  BIGNUM* rr = BN_new();
+
+  if (sizeof(RSAPublicKey) > size ||
+      RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
+    goto cleanup;
+  }
+
+  // Store the modulus size.
+  key_struct->modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
+
+  // Compute and store n0inv = -1 / N[0] mod 2^32.
+  if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) ||
+      !BN_mod(n0inv, key->n, r32, ctx) ||
+      !BN_mod_inverse(n0inv, n0inv, r32, ctx) || !BN_sub(n0inv, r32, n0inv)) {
+    goto cleanup;
+  }
+  key_struct->n0inv = (uint32_t)BN_get_word(n0inv);
+
+  // Store the modulus.
+  if (!android_pubkey_encode_bignum(key->n, key_struct->modulus)) {
+    goto cleanup;
+  }
+
+  // Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
+  if (!ctx || !rr || !BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) ||
+      !BN_mod_sqr(rr, rr, key->n, ctx) ||
+      !android_pubkey_encode_bignum(rr, key_struct->rr)) {
+    goto cleanup;
+  }
+
+  // Store the exponent.
+  key_struct->exponent = (uint32_t)BN_get_word(key->e);
+
+  ret = true;
+
+cleanup:
+  BN_free(rr);
+  BN_free(n0inv);
+  BN_free(r32);
+  BN_CTX_free(ctx);
+  return ret;
+}
diff --git a/libcrypto_utils/include/crypto_utils/android_pubkey.h b/libcrypto_utils/include/crypto_utils/android_pubkey.h
new file mode 100644
index 0000000..1045eba
--- /dev/null
+++ b/libcrypto_utils/include/crypto_utils/android_pubkey.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CRYPTO_UTILS_ANDROID_PUBKEY_H
+#define CRYPTO_UTILS_ANDROID_PUBKEY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <openssl/rsa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Size of an RSA modulus such as an encrypted block or a signature.
+#define ANDROID_PUBKEY_MODULUS_SIZE (2048 / 8)
+
+// Size of an encoded RSA key.
+#define ANDROID_PUBKEY_ENCODED_SIZE \
+  (3 * sizeof(uint32_t) + 2 * ANDROID_PUBKEY_MODULUS_SIZE)
+
+/* Allocates a new RSA |key| object, decodes a public RSA key stored in
+ * Android's custom binary format from |key_buffer| and sets the key parameters
+ * in |key|. |size| specifies the size of the key buffer and must be at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|. The resulting |*key| can be used with the
+ * standard BoringSSL API to perform public operations.
+ *
+ * Returns true if successful, in which case the caller receives ownership of
+ * the |*key| object, i.e. needs to call RSA_free() when done with it. If there
+ * is an error, |key| is left untouched and the return value will be false.
+ */
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key);
+
+/* Encodes |key| in the Android RSA public key binary format and stores the
+ * bytes in |key_buffer|. |key_buffer| should be of size at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|.
+ *
+ * Returns true if successful, false on error.
+ */
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif  // CRYPTO_UTILS_ANDROID_PUBKEY_H
diff --git a/libcrypto_utils/tests/Android.mk b/libcrypto_utils/tests/Android.mk
new file mode 100644
index 0000000..dad82f7
--- /dev/null
+++ b/libcrypto_utils/tests/Android.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils_test
+LOCAL_SRC_FILES := android_pubkey_test.cpp
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c++11
+LOCAL_SHARED_LIBRARIES := libcrypto_utils libcrypto-host
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcrypto_utils/tests/android_pubkey_test.cpp b/libcrypto_utils/tests/android_pubkey_test.cpp
new file mode 100644
index 0000000..f8c2e0c
--- /dev/null
+++ b/libcrypto_utils/tests/android_pubkey_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <crypto_utils/android_pubkey.h>
+
+#include <string.h>
+
+#include <memory>
+
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+
+#include <gtest/gtest.h>
+
+// Test digest to verify.
+const uint8_t kDigest[] = {
+    0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0,
+    0x06, 0x4e, 0x4a, 0x01, 0x64, 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8,
+    0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3,
+};
+
+// 2048 RSA test key.
+const uint8_t kKey2048[ANDROID_PUBKEY_ENCODED_SIZE] = {
+    0x40, 0x00, 0x00, 0x00, 0x05, 0x75, 0x61, 0xd1, 0x33, 0xf0, 0x2d, 0x12,
+    0x45, 0xfb, 0xae, 0x07, 0x02, 0x15, 0x4f, 0x3a, 0x2b, 0xa3, 0xbc, 0x49,
+    0xbd, 0x14, 0x07, 0xa0, 0xc0, 0x9f, 0x0c, 0x52, 0x60, 0x77, 0x9f, 0xa2,
+    0x31, 0xd0, 0xa7, 0xfb, 0x7e, 0xde, 0xfb, 0xc9, 0x05, 0xc0, 0x97, 0xf7,
+    0x74, 0x99, 0xe6, 0xd1, 0x08, 0xa6, 0xc2, 0x59, 0x5a, 0xd8, 0x37, 0x1d,
+    0xe0, 0x48, 0x5e, 0x63, 0x44, 0x04, 0x8b, 0x05, 0x20, 0xf6, 0x25, 0x67,
+    0x38, 0xb2, 0xb6, 0xf9, 0xbe, 0xb6, 0x1d, 0x7f, 0x1b, 0x71, 0x8a, 0xeb,
+    0xb7, 0xf8, 0x01, 0xc1, 0x5e, 0xf7, 0xfe, 0x48, 0x08, 0x27, 0x0f, 0x27,
+    0x2a, 0x64, 0x1a, 0x43, 0x8d, 0xcf, 0x5a, 0x33, 0x5c, 0x18, 0xc5, 0xf4,
+    0xe7, 0xfe, 0xee, 0xd3, 0x12, 0x62, 0xad, 0x61, 0x78, 0x9a, 0x03, 0xb0,
+    0xaf, 0xab, 0x91, 0x57, 0x46, 0xbf, 0x18, 0xc6, 0xbc, 0x0c, 0x6b, 0x55,
+    0xcd, 0xda, 0xc4, 0xcc, 0x98, 0x46, 0x91, 0x99, 0xbc, 0xa3, 0xca, 0x6c,
+    0x86, 0xa6, 0x1c, 0x8f, 0xca, 0xf8, 0xf6, 0x8a, 0x00, 0x8e, 0x05, 0xd7,
+    0x13, 0x43, 0xe2, 0xf2, 0x1a, 0x13, 0xf3, 0x50, 0x13, 0xa4, 0xf2, 0x4e,
+    0x41, 0xb1, 0x36, 0x78, 0x55, 0x4c, 0x5e, 0x27, 0xc5, 0xc0, 0x4b, 0xd8,
+    0x93, 0xaa, 0x7e, 0xf0, 0x90, 0x08, 0x10, 0x26, 0x72, 0x6d, 0xb9, 0x21,
+    0xae, 0x4d, 0x01, 0x4b, 0x55, 0x1d, 0xe7, 0x1e, 0x5e, 0x31, 0x6e, 0x62,
+    0xd1, 0x33, 0x26, 0xcb, 0xdb, 0xfe, 0x72, 0x98, 0xc8, 0x06, 0x1c, 0x12,
+    0xdf, 0xfc, 0x74, 0xe5, 0x7a, 0x6f, 0xf5, 0xa3, 0x63, 0x08, 0xe3, 0x02,
+    0x68, 0x4d, 0x7c, 0x70, 0x05, 0xec, 0x95, 0x7e, 0x24, 0xa4, 0xbc, 0x4c,
+    0xcd, 0x39, 0x14, 0xb5, 0x2a, 0x8f, 0xc1, 0xe3, 0x4e, 0xfa, 0xf8, 0x70,
+    0x50, 0x8f, 0xd5, 0x8e, 0xc7, 0xb5, 0x32, 0x89, 0x4d, 0xbb, 0x6a, 0xc1,
+    0xc1, 0xa2, 0x42, 0x57, 0x57, 0xbd, 0x2a, 0xdc, 0xa6, 0xfd, 0xc8, 0x86,
+    0x44, 0x6a, 0x03, 0x5d, 0x4d, 0x28, 0xe1, 0xde, 0xb4, 0xa9, 0xa5, 0x03,
+    0x61, 0x7a, 0x5f, 0xb1, 0x09, 0x17, 0x2b, 0x9c, 0xa2, 0x54, 0x28, 0xad,
+    0x34, 0xc9, 0x5f, 0x6c, 0x9f, 0xb8, 0xd2, 0xa9, 0x78, 0xa7, 0xaa, 0xb3,
+    0x11, 0x2f, 0x65, 0x9b, 0x4e, 0x67, 0x0c, 0xcc, 0x20, 0x36, 0xbf, 0x26,
+    0x2b, 0x4e, 0xc0, 0xd4, 0xbd, 0x22, 0x64, 0xc4, 0x1c, 0x56, 0x69, 0xdb,
+    0x5f, 0x89, 0xe1, 0x75, 0x68, 0x8d, 0x0e, 0xab, 0x1c, 0x10, 0x1a, 0xc0,
+    0x12, 0x5d, 0x6f, 0xbd, 0x09, 0xbb, 0x47, 0xcb, 0xe7, 0x34, 0xef, 0x56,
+    0xab, 0xea, 0xc3, 0xe9, 0x7f, 0x9a, 0x3d, 0xe9, 0x2d, 0x14, 0x61, 0x25,
+    0x37, 0x5c, 0x3b, 0x4b, 0xaf, 0x5a, 0x4b, 0xc8, 0x99, 0x1a, 0x32, 0x8f,
+    0x54, 0x07, 0xd3, 0x57, 0x8a, 0x3d, 0x2a, 0xf7, 0x9e, 0x7e, 0x92, 0x2a,
+    0x50, 0xe9, 0xd8, 0xdb, 0xd6, 0x03, 0xd3, 0x8e, 0x54, 0x32, 0xce, 0x87,
+    0x93, 0x92, 0xe7, 0x75, 0xe1, 0x6b, 0x78, 0x1a, 0x85, 0xc2, 0x46, 0xa1,
+    0x31, 0xbb, 0xc7, 0xb9, 0x1d, 0xd1, 0x71, 0xe0, 0xe2, 0x9b, 0x9c, 0x0d,
+    0xa3, 0xcf, 0x93, 0x4d, 0x87, 0x7b, 0x65, 0xd9, 0xda, 0x4c, 0xd9, 0x6a,
+    0xa6, 0x36, 0xc2, 0xc7, 0xe3, 0x33, 0xe2, 0xc3, 0x83, 0xd1, 0x72, 0x54,
+    0x30, 0x81, 0x5e, 0x34, 0x2c, 0x61, 0xee, 0xf4, 0x48, 0x97, 0xb6, 0xaa,
+    0x47, 0x6a, 0x05, 0x09, 0xd8, 0x4d, 0x90, 0xaf, 0xa8, 0x4e, 0x82, 0xe4,
+    0x8e, 0xb5, 0xe2, 0x65, 0x86, 0x67, 0xe9, 0x5b, 0x4b, 0x9a, 0x68, 0x08,
+    0x30, 0xf6, 0x25, 0x8b, 0x20, 0xda, 0x26, 0x6f, 0xbd, 0x0d, 0xa5, 0xd8,
+    0x6a, 0x7b, 0x01, 0x2f, 0xab, 0x7b, 0xb5, 0xfe, 0x62, 0x37, 0x2d, 0x94,
+    0x43, 0x2f, 0x4d, 0x16, 0x01, 0x00, 0x01, 0x00,
+};
+
+// 2048 bit RSA signature.
+const uint8_t kSignature2048[ANDROID_PUBKEY_MODULUS_SIZE] = {
+    0x3a, 0x11, 0x84, 0x40, 0xc1, 0x2f, 0x13, 0x8c, 0xde, 0xb0, 0xc3, 0x89,
+    0x8a, 0x63, 0xb2, 0x50, 0x93, 0x58, 0xc0, 0x0c, 0xb7, 0x08, 0xe7, 0x6c,
+    0x52, 0x87, 0x4e, 0x78, 0x89, 0xa3, 0x9a, 0x47, 0xeb, 0x11, 0x57, 0xbc,
+    0xb3, 0x97, 0xf8, 0x34, 0xf1, 0xf7, 0xbf, 0x3a, 0xfa, 0x1c, 0x6b, 0xdc,
+    0xd1, 0x02, 0xde, 0x9a, 0x0d, 0x72, 0xe7, 0x19, 0x63, 0x81, 0x46, 0x68,
+    0x1e, 0x63, 0x64, 0xc6, 0x59, 0xe7, 0x7c, 0x39, 0xed, 0x32, 0xd2, 0xd1,
+    0xd5, 0x1f, 0x13, 0x9b, 0x52, 0xdf, 0x34, 0xa3, 0xc0, 0xc4, 0x9a, 0x63,
+    0x9b, 0x9c, 0xbe, 0x22, 0xc8, 0xd8, 0x14, 0x2f, 0x4c, 0x78, 0x36, 0xdb,
+    0x16, 0x41, 0x67, 0xc1, 0x21, 0x8a, 0x73, 0xb2, 0xe5, 0xb0, 0xd3, 0x80,
+    0x91, 0x7a, 0xbf, 0xf9, 0x59, 0x4a, 0x4d, 0x78, 0x45, 0x44, 0xa1, 0x52,
+    0x86, 0x29, 0x48, 0x4d, 0xf0, 0x5d, 0xf2, 0x55, 0xa7, 0xcd, 0xc5, 0x2b,
+    0x7b, 0xe0, 0xb1, 0xf6, 0x2a, 0xd5, 0x61, 0xba, 0x1e, 0x1e, 0x3a, 0xf0,
+    0x55, 0xbc, 0x8c, 0x44, 0x41, 0xfc, 0xb8, 0x8c, 0x76, 0xbf, 0x80, 0x58,
+    0x82, 0x35, 0x4b, 0x0c, 0xfd, 0xef, 0xd5, 0x70, 0xd1, 0x64, 0xcb, 0x46,
+    0x58, 0x37, 0xbc, 0xa9, 0x7d, 0xd4, 0x70, 0xac, 0xce, 0xec, 0xca, 0x48,
+    0xcb, 0x0a, 0x40, 0x77, 0x04, 0x59, 0xca, 0x9c, 0x7d, 0x1a, 0x0b, 0xf0,
+    0xb5, 0xdd, 0xde, 0x71, 0x18, 0xb8, 0xef, 0x90, 0x2a, 0x09, 0x42, 0x39,
+    0x74, 0xff, 0x45, 0xa1, 0x39, 0x17, 0x50, 0x89, 0xa6, 0x5f, 0xbc, 0x9c,
+    0x0c, 0x9b, 0x47, 0x25, 0x79, 0x3e, 0xe3, 0xaa, 0xaf, 0xbe, 0x73, 0x6b,
+    0xcb, 0xe7, 0x35, 0xc1, 0x27, 0x09, 0xcd, 0xeb, 0xd7, 0xcf, 0x63, 0x83,
+    0x64, 0x8c, 0x45, 0x1c, 0x1d, 0x58, 0xcc, 0xd2, 0xf8, 0x2b, 0x4c, 0x4e,
+    0x14, 0x89, 0x2d, 0x70,
+};
+
+struct AndroidPubkeyTest : public ::testing::Test {
+  void SetUp() override {
+    RSA* new_key = nullptr;
+    ASSERT_TRUE(android_pubkey_decode(kKey2048, sizeof(kKey2048), &new_key));
+    key_.reset(new_key);
+  }
+
+  std::unique_ptr<RSA, void(*)(RSA*)> key_ = {nullptr, RSA_free};
+};
+
+TEST_F(AndroidPubkeyTest, Decode) {
+  // Make sure the decoded key successfully verifies a valid signature.
+  EXPECT_TRUE(RSA_verify(NID_sha256, kDigest, sizeof(kDigest), kSignature2048,
+                         sizeof(kSignature2048), key_.get()));
+}
+
+TEST_F(AndroidPubkeyTest, Encode) {
+  uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+  ASSERT_TRUE(android_pubkey_encode(key_.get(), key_data, sizeof(key_data)));
+  ASSERT_EQ(0, memcmp(kKey2048, key_data, sizeof(kKey2048)));
+}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c0d4d76..822a7d3 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -17,9 +17,9 @@
 include $(CLEAR_VARS)
 
 libcutils_common_sources := \
-        atomic.c.arm \
         config_utils.c \
         fs_config.c \
+        canned_fs_config.c \
         hashmap.c \
         iosched_policy.c \
         load_file.c \
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index c85f06b..1f9f753 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -62,12 +62,12 @@
 
 int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_NOT_PURGED;
+    return 0 /*ASHMEM_NOT_PURGED*/;
 }
 
 int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_IS_UNPINNED;
+    return 0 /*ASHMEM_IS_UNPINNED*/;
 }
 
 int ashmem_get_size_region(int fd)
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
new file mode 100644
index 0000000..5800857
--- /dev/null
+++ b/libcutils/canned_fs_config.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/canned_fs_config.h>
+
+typedef struct {
+	const char* path;
+	unsigned uid;
+	unsigned gid;
+	unsigned mode;
+	uint64_t capabilities;
+} Path;
+
+static Path* canned_data = NULL;
+static int canned_alloc = 0;
+static int canned_used = 0;
+
+static int path_compare(const void* a, const void* b) {
+	return strcmp(((Path*)a)->path, ((Path*)b)->path);
+}
+
+int load_canned_fs_config(const char* fn) {
+	FILE* f = fopen(fn, "r");
+	if (f == NULL) {
+		fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
+		return -1;
+	}
+
+	char line[PATH_MAX + 200];
+	while (fgets(line, sizeof(line), f)) {
+		while (canned_used >= canned_alloc) {
+			canned_alloc = (canned_alloc+1) * 2;
+			canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+		}
+		Path* p = canned_data + canned_used;
+		p->path = strdup(strtok(line, " "));
+		p->uid = atoi(strtok(NULL, " "));
+		p->gid = atoi(strtok(NULL, " "));
+		p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
+		p->capabilities = 0;
+
+		char* token = NULL;
+		do {
+			token = strtok(NULL, " ");
+			if (token && strncmp(token, "capabilities=", 13) == 0) {
+				p->capabilities = strtoll(token+13, NULL, 0);
+				break;
+			}
+		} while (token);
+
+		canned_used++;
+	}
+
+	fclose(f);
+
+	qsort(canned_data, canned_used, sizeof(Path), path_compare);
+	printf("loaded %d fs_config entries\n", canned_used);
+
+	return 0;
+}
+
+static const int kDebugCannedFsConfig = 0;
+
+void canned_fs_config(const char* path, int dir, const char* target_out_path,
+					  unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
+	Path key;
+    key.path = path;
+    if (path[0] == '/')
+        key.path++;   // canned paths lack the leading '/'
+	Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
+	if (p == NULL) {
+		fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+		exit(1);
+	}
+	*uid = p->uid;
+	*gid = p->gid;
+	*mode = p->mode;
+	*capabilities = p->capabilities;
+
+	if (kDebugCannedFsConfig) {
+		// for debugging, run the built-in fs_config and compare the results.
+
+		unsigned c_uid, c_gid, c_mode;
+		uint64_t c_capabilities;
+		fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+
+		if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
+		if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
+		if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
+		if (c_capabilities != *capabilities)
+			printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
+				path,
+				*capabilities,
+				c_capabilities);
+        }
+}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 6bba3a7..7bb8223 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -306,7 +306,7 @@
     char thread_name[255];
     int fd;
 
-    sprintf(statfile, "/proc/%d/stat", tid);
+    snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
     memset(thread_name, 0, sizeof(thread_name));
 
     fd = open(statfile, O_RDONLY);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 302e63c..7a95dbd 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -56,7 +56,9 @@
         android: {
             srcs: liblog_target_sources,
             // AddressSanitizer runtime library depends on liblog.
-            sanitize: ["never"],
+            sanitize: {
+                never: true,
+            },
         },
         android_arm: {
             // TODO: This is to work around b/24465209. Remove after root cause is fixed
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 64d872a..3cb04cf 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,7 +73,7 @@
     if (newTagMap == NULL)
         return NULL;
 
-    fd = open(fileName, O_RDONLY);
+    fd = open(fileName, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         fprintf(stderr, "%s: unable to open map '%s': %s\n",
             OUT_TAG, fileName, strerror(errno));
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 79a5670..bd8d5af 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -63,7 +63,6 @@
 
 static void refresh_cache(struct cache *cache, const char *key)
 {
-    uint32_t serial;
     char buf[PROP_VALUE_MAX];
 
     if (!cache->pinfo) {
@@ -71,13 +70,8 @@
         if (!cache->pinfo) {
             return;
         }
-        cache->serial = -1;
     }
-    serial = __system_property_serial(cache->pinfo);
-    if (serial == cache->serial) {
-        return;
-    }
-    cache->serial = serial;
+    cache->serial = __system_property_serial(cache->pinfo);
     __system_property_read(cache->pinfo, 0, buf);
     switch(buf[0]) {
     case 't': case 'T':
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index d844104..b894349 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -85,7 +85,7 @@
     .clear = logdClear,
     .getSize = logdGetSize,
     .setSize = logdSetSize,
-    .getReadableSize = logdGetSize,
+    .getReadableSize = logdGetReadableSize,
     .getPrune = logdGetPrune,
     .setPrune = logdSetPrune,
     .getStats = logdGetStats,
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 9b60d4a..59bd479 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <pwd.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -28,11 +29,11 @@
 #include <string.h>
 #include <inttypes.h>
 #include <sys/param.h>
+#include <sys/types.h>
 
 #include <cutils/list.h>
 #include <log/logd.h>
 #include <log/logprint.h>
-#include <private/android_filesystem_config.h>
 
 #include "log_portability.h"
 
@@ -1042,7 +1043,7 @@
          * Anything in the Android Logger before the dmesg logging span will
          * be highly suspect regarding the monotonic time calculations.
          */
-        FILE *p = popen("/system/bin/dmesg", "r");
+        FILE *p = popen("/system/bin/dmesg", "re");
         if (p) {
             char *line = NULL;
             size_t len = 0;
@@ -1352,17 +1353,17 @@
     uid[0] = '\0';
     if (p_format->uid_output) {
         if (entry->uid >= 0) {
-            const struct android_id_info *info = android_ids;
-            size_t i;
 
-            for (i = 0; i < android_id_count; ++i) {
-                if (info->aid == (unsigned int)entry->uid) {
-                    break;
-                }
-                ++info;
-            }
-            if ((i < android_id_count) && (strlen(info->name) <= 5)) {
-                 snprintf(uid, sizeof(uid), "%5s:", info->name);
+            /*
+             * This code is Android specific, bionic guarantees that
+             * calls to non-reentrant getpwuid() are thread safe.
+             */
+#ifndef __BIONIC__
+#warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
+#endif
+            struct passwd* pwd = getpwuid(entry->uid);
+            if (pwd && (strlen(pwd->pw_name) <= 5)) {
+                 snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
             } else {
                  // Not worth parsing package list, names all longer than 5
                  snprintf(uid, sizeof(uid), "%5d:", entry->uid);
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 5695e8a..2e4fc5d 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,13 +151,13 @@
     memset(log_msg, 0, sizeof(*log_msg));
 
     if (transp->context.fd <= 0) {
-        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
 
         if (fd < 0) {
             return -errno;
         }
         if (fd == 0) { /* Argggg */
-            fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+            fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
             close(0);
             if (fd < 0) {
                 return -errno;
@@ -227,7 +227,7 @@
                     log_msg->entry_v4.uid = buf.p.uid;
                 }
 
-                return ret;
+                return ret + log_msg->entry_v4.hdr_size;
             }
         }
 
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 9cd3c48..2ba31fa 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -54,7 +54,7 @@
 static int pmsgOpen()
 {
     if (pmsgLoggerWrite.context.fd < 0) {
-        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
     }
 
     return pmsgLoggerWrite.context.fd;
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 456f8b3..df2c766 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1338,7 +1338,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, levels[j].level));
                 }
@@ -1347,7 +1347,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, levels[j].level));
                 }
@@ -1368,6 +1368,7 @@
             snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
+            usleep(20000);
             property_set(key, buf);
             bool android_log_is_loggable = __android_log_is_loggable(
                 levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1379,7 +1380,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1388,11 +1389,12 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1408,7 +1410,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1417,11 +1419,12 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
 
             strcpy(key, log_namespace);
@@ -1439,7 +1442,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1448,11 +1451,12 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1468,7 +1472,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1477,11 +1481,12 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
         }
     }
@@ -1489,6 +1494,7 @@
     // All combinations of level and tag properties, but with global set to INFO
     strcpy(key, log_namespace);
     key[sizeof(log_namespace) - 2] = '\0';
+    usleep(20000);
     property_set(key, "I");
     snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
     for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
@@ -1502,6 +1508,7 @@
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
+            usleep(20000);
             property_set(key, buf);
             bool android_log_is_loggable = __android_log_is_loggable(
                 levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1513,7 +1520,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1522,11 +1529,12 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1542,7 +1550,7 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_FALSE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_FALSE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
@@ -1551,17 +1559,19 @@
                     fprintf(stderr, "\n");
                 }
                 EXPECT_TRUE(android_log_is_loggable);
-                for(size_t k = 1000; k; --k) {
+                for(size_t k = 10; k; --k) {
                     EXPECT_TRUE(__android_log_is_loggable(
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
         }
     }
 
     // reset parms
     snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+    usleep(20000);
     property_set(key, hold[0]);
     property_set(key + base_offset, hold[1]);
     strcpy(key, log_namespace);
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 19393ec..62366f2 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <inttypes.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include <map>
 #include <utility>
@@ -22,6 +25,7 @@
 #include "Allocator.h"
 #include "HeapWalker.h"
 #include "LeakFolding.h"
+#include "ScopedSignalHandler.h"
 #include "log.h"
 
 bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
@@ -37,18 +41,26 @@
     return true;
   } else {
     Range overlap = inserted.first->first;
-    ALOGE("range %p-%p overlaps with existing range %p-%p",
-        reinterpret_cast<void*>(begin),
-        reinterpret_cast<void*>(end),
-        reinterpret_cast<void*>(overlap.begin),
-        reinterpret_cast<void*>(overlap.end));
+    if (overlap != range) {
+      ALOGE("range %p-%p overlaps with existing range %p-%p",
+          reinterpret_cast<void*>(begin),
+          reinterpret_cast<void*>(end),
+          reinterpret_cast<void*>(overlap.begin),
+          reinterpret_cast<void*>(overlap.end));
+    }
     return false;
   }
 }
 
-bool HeapWalker::IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info) {
-  if (ptr >= valid_allocations_range_.begin && ptr < valid_allocations_range_.end) {
-    AllocationMap::iterator it = allocations_.find(Range{ptr, ptr + 1});
+bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
+  walking_ptr_ = word_ptr;
+  // This access may segfault if the process under test has done something strange,
+  // for example mprotect(PROT_NONE) on a native heap page.  If so, it will be
+  // caught and handled by mmaping a zero page over the faulting page.
+  uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+  walking_ptr_ = 0;
+  if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
+    AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
     if (it != allocations_.end()) {
       *range = it->first;
       *info = &it->second;
@@ -135,3 +147,30 @@
 
   return true;
 }
+
+static bool MapOverPage(void* addr) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  void *page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size-1));
+
+  void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+  if (ret == MAP_FAILED) {
+    ALOGE("failed to map page at %p: %s", page, strerror(errno));
+    return false;
+  }
+
+  return true;
+}
+
+void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si, void* /*uctx*/) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(si->si_addr);
+  if (addr != walking_ptr_) {
+    handler.reset();
+    return;
+  }
+  ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+  if (!MapOverPage(si->si_addr)) {
+    handler.reset();
+  }
+}
+
+ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 7b851c4..3c1b513 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -17,9 +17,12 @@
 #ifndef LIBMEMUNREACHABLE_HEAP_WALKER_H_
 #define LIBMEMUNREACHABLE_HEAP_WALKER_H_
 
+#include <signal.h>
+
 #include "android-base/macros.h"
 
 #include "Allocator.h"
+#include "ScopedSignalHandler.h"
 #include "Tarjan.h"
 
 // A range [begin, end)
@@ -28,6 +31,12 @@
   uintptr_t end;
 
   size_t size() const { return end - begin; };
+  bool operator==(const Range& other) const {
+    return this->begin == other.begin && this->end == other.end;
+  }
+  bool operator!=(const Range& other) const {
+    return !(*this == other);
+  }
 };
 
 // Comparator for Ranges that returns equivalence for overlapping ranges
@@ -41,10 +50,17 @@
  public:
   HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
     allocations_(allocator), allocation_bytes_(0),
-	roots_(allocator), root_vals_(allocator) {
+	roots_(allocator), root_vals_(allocator),
+	segv_handler_(allocator), walking_ptr_(0) {
     valid_allocations_range_.end = 0;
     valid_allocations_range_.begin = ~valid_allocations_range_.end;
+
+    segv_handler_.install(SIGSEGV,
+        [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+          this->HandleSegFault(handler, signal, siginfo, uctx);
+      });
   }
+
   ~HeapWalker() {}
   bool Allocation(uintptr_t begin, uintptr_t end);
   void Root(uintptr_t begin, uintptr_t end);
@@ -70,7 +86,8 @@
  private:
 
   void RecurseRoot(const Range& root);
-  bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
 
   DISALLOW_COPY_AND_ASSIGN(HeapWalker);
   Allocator<HeapWalker> allocator_;
@@ -81,6 +98,9 @@
 
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
+
+  ScopedSignalHandler segv_handler_;
+  uintptr_t walking_ptr_;
 };
 
 template<class F>
@@ -92,7 +112,7 @@
   for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
     Range ref_range;
     AllocationInfo* ref_info;
-    if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+    if (WordContainsAllocationPtr(i, &ref_range, &ref_info)) {
       f(ref_range, ref_info);
     }
   }
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index aa5b344..4e3c41e 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -37,7 +37,7 @@
 
 class Stack {
  public:
-  Stack(size_t size) : size_(size) {
+  explicit Stack(size_t size) : size_(size) {
     int prot = PROT_READ | PROT_WRITE;
     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
     page_size_ = sysconf(_SC_PAGE_SIZE);
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
new file mode 100644
index 0000000..e006d43
--- /dev/null
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+#define LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+
+#include <errno.h>
+#include <signal.h>
+
+#include <functional>
+
+#include "android-base/macros.h"
+
+#include "log.h"
+
+class ScopedSignalHandler {
+ public:
+  using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
+
+  ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+  ~ScopedSignalHandler() {
+    reset();
+  }
+
+  template <class F>
+  void install(int signal, F&& f) {
+    LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+
+    handler_ = SignalFn(std::allocator_arg, allocator_,
+        [=](int signal, siginfo_t* si, void* uctx) {
+          f(*this, signal, si, uctx);
+        });
+
+    struct sigaction act{};
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+      handler_(signal, si, uctx);
+    };
+    act.sa_flags = SA_SIGINFO;
+
+    int ret = sigaction(signal, &act, &old_act_);
+    if (ret < 0) {
+      LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+    }
+
+    signal_ = signal;
+  }
+
+  void reset() {
+    if (signal_ != -1) {
+      int ret = sigaction(signal_, &old_act_, NULL);
+      if (ret < 0) {
+        ALOGE("failed to uninstall segfault handler");
+      }
+      handler_ = SignalFn{};
+      signal_ = -1;
+    }
+  }
+
+
+ private:
+  using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+  DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
+  Allocator<Fn> allocator_;
+  int signal_;
+  struct sigaction old_act_;
+  // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
+  // to be a static map of signals to handlers, but allocated with Allocator.
+  static SignalFn handler_;
+};
+
+#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index c3e1c4d..98e4aa1 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
+#include <unistd.h>
+
 #include "HeapWalker.h"
 
 #include <gtest/gtest.h>
@@ -172,3 +175,27 @@
   EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
   ASSERT_EQ(2U, leaked.size());
 }
+
+TEST_F(HeapWalkerTest, segv) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+  ASSERT_NE(buffer1, nullptr);
+  void* buffer2;
+
+  buffer2 = &buffer1;
+
+  HeapWalker heap_walker(heap_);
+  heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
+  heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
+
+  ASSERT_EQ(true, heap_walker.DetectLeaks());
+
+  allocator::vector<Range> leaked(heap_);
+  size_t num_leaks = 0;
+  size_t leaked_bytes = 0;
+  ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
+
+  EXPECT_EQ(0U, num_leaks);
+  EXPECT_EQ(0U, leaked_bytes);
+  ASSERT_EQ(0U, leaked.size());
+}
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
deleted file mode 100644
index 09fbbb1..0000000
--- a/libmincrypt/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2008 The Android Open Source Project
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/NOTICE b/libmincrypt/NOTICE
deleted file mode 100644
index 430d3d6..0000000
--- a/libmincrypt/NOTICE
+++ /dev/null
@@ -1,23 +0,0 @@
- Copyright 2008, The Android Open Source Project
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-     * Redistributions of source code must retain the above copyright
-       notice, this list of conditions and the following disclaimer.
-     * Redistributions in binary form must reproduce the above copyright
-       notice, this list of conditions and the following disclaimer in the
-       documentation and/or other materials provided with the distribution.
-     * Neither the name of Google Inc. nor the names of its contributors may
-       be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
- EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
deleted file mode 100644
index 101314b..0000000
--- a/libmincrypt/dsa_sig.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-
-/**
- * Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
- */
-static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
-        int src_len) {
-    int dst_offset;
-    while (*src == '\0' && src_len > 0) {
-        src++;
-        src_len--;
-    }
-    if (src_len > P256_NBYTES || src_len < 1) {
-        return 0;
-    }
-    dst_offset = P256_NBYTES - src_len;
-    memset(dst, 0, dst_offset);
-    memcpy(dst + dst_offset, src, src_len);
-    return 1;
-}
-
-/**
- * Unpacks the ASN.1 DSA signature sequence.
- */
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
-    /*
-     * Structure is:
-     *   0x30 0xNN  SEQUENCE + s_length
-     *     0x02 0xNN  INTEGER + r_length
-     *       0xAA 0xBB ..   r_length bytes of "r" (offset 4)
-     *     0x02 0xNN  INTEGER + s_length
-     *       0xMM 0xNN ..   s_length bytes of "s" (offset 6 + r_len)
-     */
-    int seq_len;
-    unsigned char r_bytes[P256_NBYTES];
-    unsigned char s_bytes[P256_NBYTES];
-    int r_len;
-    int s_len;
-
-    memset(r_bytes, 0, sizeof(r_bytes));
-    memset(s_bytes, 0, sizeof(s_bytes));
-
-    /*
-     * Must have at least:
-     * 2 bytes sequence header and length
-     * 2 bytes R integer header and length
-     * 1 byte of R
-     * 2 bytes S integer header and length
-     * 1 byte of S
-     *
-     * 8 bytes total
-     */
-    if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
-        return 0;
-    }
-
-    seq_len = sig[1];
-    if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
-        return 0;
-    }
-
-    r_len = sig[3];
-    /*
-     * Must have at least:
-     * 2 bytes for R header and length
-     * 2 bytes S integer header and length
-     * 1 byte of S
-     */
-    if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
-        return 0;
-    }
-    s_len = sig[5 + r_len];
-
-    /**
-     * Must have:
-     * 2 bytes for R header and length
-     * r_len bytes for R
-     * 2 bytes S integer header and length
-     */
-    if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
-        return 0;
-    }
-
-    /*
-     * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
-     * a correctly-sized buffer and that the resulting integer isn't too large.
-     */
-    if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
-            || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
-        return 0;
-    }
-
-    p256_from_bin(r_bytes, r_int);
-    p256_from_bin(s_bytes, s_int);
-
-    return 1;
-}
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
deleted file mode 100644
index 555a07a..0000000
--- a/libmincrypt/p256.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// This is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-//          obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "mincrypt/p256.h"
-
-const p256_int SECP256r1_n =  // curve order
-  {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
-
-const p256_int SECP256r1_p =  // curve field size
-  {{-1, -1, -1, 0, 0, 0, 1, -1 }};
-
-const p256_int SECP256r1_b =  // curve b
-  {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
-    0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
-
-void p256_init(p256_int* a) {
-  memset(a, 0, sizeof(*a));
-}
-
-void p256_clear(p256_int* a) { p256_init(a); }
-
-int p256_get_bit(const p256_int* scalar, int bit) {
-  return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
-              >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
-}
-
-int p256_is_zero(const p256_int* a) {
-  int i, result = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
-  return !result;
-}
-
-// top, c[] += a[] * b
-// Returns new top
-static p256_digit mulAdd(const p256_int* a,
-                         p256_digit b,
-                         p256_digit top,
-                         p256_digit* c) {
-  int i;
-  p256_ddigit carry = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += *c;
-    carry += (p256_ddigit)P256_DIGIT(a, i) * b;
-    *c++ = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)carry;
-}
-
-// top, c[] -= top_a, a[]
-static p256_digit subTop(p256_digit top_a,
-                         const p256_digit* a,
-                         p256_digit top_c,
-                         p256_digit* c) {
-  int i;
-  p256_sddigit borrow = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += *c;
-    borrow -= *a++;
-    *c++ = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  borrow += top_c;
-  borrow -= top_a;
-  top_c = (p256_digit)borrow;
-  assert((borrow >> P256_BITSPERDIGIT) == 0);
-  return top_c;
-}
-
-// top, c[] -= MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit subM(const p256_int* MOD,
-                       p256_digit top,
-                       p256_digit* c,
-                       p256_digit mask) {
-  int i;
-  p256_sddigit borrow = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += *c;
-    borrow -= P256_DIGIT(MOD, i) & mask;
-    *c++ = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)borrow;
-}
-
-// top, c[] += MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit addM(const p256_int* MOD,
-                       p256_digit top,
-                       p256_digit* c,
-                       p256_digit mask) {
-  int i;
-  p256_ddigit carry = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += *c;
-    carry += P256_DIGIT(MOD, i) & mask;
-    *c++ = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)carry;
-}
-
-// c = a * b mod MOD. c can be a and/or b.
-void p256_modmul(const p256_int* MOD,
-                 const p256_int* a,
-                 const p256_digit top_b,
-                 const p256_int* b,
-                 p256_int* c) {
-  p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
-  p256_digit top = 0;
-  int i;
-
-  // Multiply/add into tmp.
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    if (i) tmp[i + P256_NDIGITS - 1] = top;
-    top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
-  }
-
-  // Multiply/add top digit
-  tmp[i + P256_NDIGITS - 1] = top;
-  top = mulAdd(a, top_b, 0, tmp + i);
-
-  // Reduce tmp, digit by digit.
-  for (; i >= 0; --i) {
-    p256_digit reducer[P256_NDIGITS] = { 0 };
-    p256_digit top_reducer;
-
-    // top can be any value at this point.
-    // Guestimate reducer as top * MOD, since msw of MOD is -1.
-    top_reducer = mulAdd(MOD, top, 0, reducer);
-
-    // Subtract reducer from top | tmp.
-    top = subTop(top_reducer, reducer, top, tmp + i);
-
-    // top is now either 0 or 1. Make it 0, fixed-timing.
-    assert(top <= 1);
-
-    top = subM(MOD, top, tmp + i, ~(top - 1));
-
-    assert(top == 0);
-
-    // We have now reduced the top digit off tmp. Fetch new top digit.
-    top = tmp[i + P256_NDIGITS - 1];
-  }
-
-  // tmp might still be larger than MOD, yet same bit length.
-  // Make sure it is less, fixed-timing.
-  addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
-
-  memcpy(c, tmp, P256_NBYTES);
-}
-int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
-int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
-
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
-  int i;
-  p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
-
-  n %= P256_BITSPERDIGIT;
-  for (i = P256_NDIGITS - 1; i > 0; --i) {
-    p256_digit accu = (P256_DIGIT(a, i) << n);
-    accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
-
-  top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
-
-  return top;
-}
-
-void p256_shr(const p256_int* a, int n, p256_int* b) {
-  int i;
-
-  n %= P256_BITSPERDIGIT;
-  for (i = 0; i < P256_NDIGITS - 1; ++i) {
-    p256_digit accu = (P256_DIGIT(a, i) >> n);
-    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
-}
-
-static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
-  int i;
-
-  for (i = 0; i < P256_NDIGITS - 1; ++i) {
-    p256_digit accu = (P256_DIGIT(a, i) >> 1);
-    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
-      (highbit << (P256_BITSPERDIGIT - 1));
-}
-
-// Return -1, 0, 1 for a < b, a == b or a > b respectively.
-int p256_cmp(const p256_int* a, const p256_int* b) {
-  int i;
-  p256_sddigit borrow = 0;
-  p256_digit notzero = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
-    // Track whether any result digit is ever not zero.
-    // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
-    notzero |= !!((p256_digit)borrow);
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return (int)borrow | notzero;
-}
-
-// c = a - b. Returns borrow: 0 or -1.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
-  int i;
-  p256_sddigit borrow = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
-    if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return (int)borrow;
-}
-
-// c = a + b. Returns carry: 0 or 1.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
-  int i;
-  p256_ddigit carry = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
-    if (c) P256_DIGIT(c, i) = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return (int)carry;
-}
-
-// b = a + d. Returns carry, 0 or 1.
-int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
-  int i;
-  p256_ddigit carry = d;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += (p256_ddigit)P256_DIGIT(a, i);
-    if (b) P256_DIGIT(b, i) = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return (int)carry;
-}
-
-// b = 1/a mod MOD, binary euclid.
-void p256_modinv_vartime(const p256_int* MOD,
-                         const p256_int* a,
-                         p256_int* b) {
-  p256_int R = P256_ZERO;
-  p256_int S = P256_ONE;
-  p256_int U = *MOD;
-  p256_int V = *a;
-
-  for (;;) {
-    if (p256_is_even(&U)) {
-      p256_shr1(&U, 0, &U);
-      if (p256_is_even(&R)) {
-        p256_shr1(&R, 0, &R);
-      } else {
-        // R = (R+MOD)/2
-        p256_shr1(&R, p256_add(&R, MOD, &R), &R);
-      }
-    } else if (p256_is_even(&V)) {
-      p256_shr1(&V, 0, &V);
-      if (p256_is_even(&S)) {
-        p256_shr1(&S, 0, &S);
-      } else {
-        // S = (S+MOD)/2
-        p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
-      }
-    } else {  // U,V both odd.
-      if (!p256_sub(&V, &U, NULL)) {
-        p256_sub(&V, &U, &V);
-        if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
-        if (p256_is_zero(&V)) break;  // done.
-      } else {
-        p256_sub(&U, &V, &U);
-        if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
-      }
-    }
-  }
-
-  p256_mod(MOD, &R, b);
-}
-
-void p256_mod(const p256_int* MOD,
-              const p256_int* in,
-              p256_int* out) {
-  if (out != in) *out = *in;
-  addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
-}
-
-// Verify y^2 == x^3 - 3x + b mod p
-// and 0 < x < p and 0 < y < p
-int p256_is_valid_point(const p256_int* x, const p256_int* y) {
-  p256_int y2, x3;
-
-  if (p256_cmp(&SECP256r1_p, x) <= 0 ||
-      p256_cmp(&SECP256r1_p, y) <= 0 ||
-      p256_is_zero(x) ||
-      p256_is_zero(y)) return 0;
-
-  p256_modmul(&SECP256r1_p, y, 0, y, &y2);  // y^2
-
-  p256_modmul(&SECP256r1_p, x, 0, x, &x3);  // x^2
-  p256_modmul(&SECP256r1_p, x, 0, &x3, &x3);  // x^3
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - x
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 2x
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 3x
-  if (p256_add(&x3, &SECP256r1_b, &x3))  // x^3 - 3x + b
-    p256_sub(&x3, &SECP256r1_p, &x3);
-
-  return p256_cmp(&y2, &x3) == 0;
-}
-
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
-  int i;
-  const uint8_t* p = &src[0];
-
-  for (i = P256_NDIGITS - 1; i >= 0; --i) {
-    P256_DIGIT(dst, i) =
-        (p[0] << 24) |
-        (p[1] << 16) |
-        (p[2] << 8) |
-        p[3];
-    p += 4;
-  }
-}
diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c
deleted file mode 100644
index 90262cc..0000000
--- a/libmincrypt/p256_ec.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// This is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-//          obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "mincrypt/p256.h"
-
-typedef uint8_t u8;
-typedef uint32_t u32;
-typedef int32_t s32;
-typedef uint64_t u64;
-
-/* Our field elements are represented as nine 32-bit limbs.
- *
- * The value of an felem (field element) is:
- *   x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
- *
- * That is, each limb is alternately 29 or 28-bits wide in little-endian
- * order.
- *
- * This means that an felem hits 2**257, rather than 2**256 as we would like. A
- * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
- * when multiplying as terms end up one bit short of a limb which would require
- * much bit-shifting to correct.
- *
- * Finally, the values stored in an felem are in Montgomery form. So the value
- * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
- */
-typedef u32 limb;
-#define NLIMBS 9
-typedef limb felem[NLIMBS];
-
-static const limb kBottom28Bits = 0xfffffff;
-static const limb kBottom29Bits = 0x1fffffff;
-
-/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
- * 28-bit words. */
-static const felem kOne = {
-    2, 0, 0, 0xffff800,
-    0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
-    0
-};
-static const felem kZero = {0};
-static const felem kP = {
-    0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
-    0, 0, 0x200000, 0xf000000,
-    0xfffffff
-};
-static const felem k2P = {
-    0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
-    0, 0, 0x400000, 0xe000000,
-    0x1fffffff
-};
-/* kPrecomputed contains precomputed values to aid the calculation of scalar
- * multiples of the base point, G. It's actually two, equal length, tables
- * concatenated.
- *
- * The first table contains (x,y) felem pairs for 16 multiples of the base
- * point, G.
- *
- *   Index  |  Index (binary) | Value
- *       0  |           0000  | 0G (all zeros, omitted)
- *       1  |           0001  | G
- *       2  |           0010  | 2**64G
- *       3  |           0011  | 2**64G + G
- *       4  |           0100  | 2**128G
- *       5  |           0101  | 2**128G + G
- *       6  |           0110  | 2**128G + 2**64G
- *       7  |           0111  | 2**128G + 2**64G + G
- *       8  |           1000  | 2**192G
- *       9  |           1001  | 2**192G + G
- *      10  |           1010  | 2**192G + 2**64G
- *      11  |           1011  | 2**192G + 2**64G + G
- *      12  |           1100  | 2**192G + 2**128G
- *      13  |           1101  | 2**192G + 2**128G + G
- *      14  |           1110  | 2**192G + 2**128G + 2**64G
- *      15  |           1111  | 2**192G + 2**128G + 2**64G + G
- *
- * The second table follows the same style, but the terms are 2**32G,
- * 2**96G, 2**160G, 2**224G.
- *
- * This is ~2KB of data. */
-static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
-    0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
-    0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
-    0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
-    0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
-    0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
-    0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
-    0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
-    0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
-    0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
-    0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
-    0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
-    0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
-    0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
-    0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
-    0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
-    0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
-    0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
-    0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
-    0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
-    0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
-    0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
-    0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
-    0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
-    0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
-    0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
-    0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
-    0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
-    0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
-    0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
-    0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
-    0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
-    0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
-    0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
-    0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
-    0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
-    0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
-    0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
-    0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
-    0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
-    0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
-    0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
-    0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
-    0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
-    0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
-    0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
-    0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
-    0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
-    0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
-    0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
-    0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
-    0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
-    0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
-    0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
-    0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
-    0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
-    0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
-    0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
-    0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
-    0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
-    0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
-};
-
-
-/* Field element operations: */
-
-/* NON_ZERO_TO_ALL_ONES returns:
- *   0xffffffff for 0 < x <= 2**31
- *   0 for x == 0 or x > 2**31.
- *
- * x must be a u32 or an equivalent type such as limb. */
-#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
-
-/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
- * which is a term at 2**257.
- *
- * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
- * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
-static void felem_reduce_carry(felem inout, limb carry) {
-  const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
-
-  inout[0] += carry << 1;
-  inout[3] += 0x10000000 & carry_mask;
-  /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
-   * previous line therefore this doesn't underflow. */
-  inout[3] -= carry << 11;
-  inout[4] += (0x20000000 - 1) & carry_mask;
-  inout[5] += (0x10000000 - 1) & carry_mask;
-  inout[6] += (0x20000000 - 1) & carry_mask;
-  inout[6] -= carry << 22;
-  /* This may underflow if carry is non-zero but, if so, we'll fix it in the
-   * next line. */
-  inout[7] -= 1 & carry_mask;
-  inout[7] += carry << 25;
-}
-
-/* felem_sum sets out = in+in2.
- *
- * On entry, in[i]+in2[i] must not overflow a 32-bit word.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_sum(felem out, const felem in, const felem in2) {
-  limb carry = 0;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    out[i] = in[i] + in2[i];
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] = in[i] + in2[i];
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-#define two31m3 (((limb)1) << 31) - (((limb)1) << 3)
-#define two30m2 (((limb)1) << 30) - (((limb)1) << 2)
-#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2)
-#define two31m2 (((limb)1) << 31) - (((limb)1) << 2)
-#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2)
-#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2)
-
-/* zero31 is 0 mod p. */
-static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 };
-
-/* felem_diff sets out = in-in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_diff(felem out, const felem in, const felem in2) {
-  limb carry = 0;
-  unsigned i;
-
-   for (i = 0;; i++) {
-    out[i] = in[i] - in2[i];
-    out[i] += zero31[i];
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] = in[i] - in2[i];
-    out[i] += zero31[i];
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
- * with the same 29,28,... bit positions as an felem.
- *
- * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
- * Since we just multiplied two Montgomery values together, the result is
- * x*y*R*R mod p. We wish to divide by R in order for the result also to be
- * in Montgomery form.
- *
- * On entry: tmp[i] < 2**64
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_reduce_degree(felem out, u64 tmp[17]) {
-   /* The following table may be helpful when reading this code:
-    *
-    * Limb number:   0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
-    * Width (bits):  29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
-    * Start bit:     0 | 29| 57| 86|114|143|171|200|228|257|285
-    *   (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
-  limb tmp2[18], carry, x, xMask;
-  unsigned i;
-
-  /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
-   * felem. So the top of an element of tmp might overlap with another
-   * element two positions down. The following loop eliminates this
-   * overlap. */
-  tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
-
-  /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try
-   * and hint to the compiler that it can do a single-word shift by selecting
-   * the right register rather than doing a double-word shift and truncating
-   * afterwards. */
-  tmp2[1] = ((limb) tmp[0]) >> 29;
-  tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
-  tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
-  carry = tmp2[1] >> 28;
-  tmp2[1] &= kBottom28Bits;
-
-  for (i = 2; i < 17; i++) {
-    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
-    tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
-    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
-    tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
-    tmp2[i] += carry;
-    carry = tmp2[i] >> 29;
-    tmp2[i] &= kBottom29Bits;
-
-    i++;
-    if (i == 17)
-      break;
-    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
-    tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
-    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
-    tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
-    tmp2[i] += carry;
-    carry = tmp2[i] >> 28;
-    tmp2[i] &= kBottom28Bits;
-  }
-
-  tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
-  tmp2[17] += ((limb)(tmp[16])) >> 29;
-  tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
-  tmp2[17] += carry;
-
-  /* Montgomery elimination of terms.
-   *
-   * Since R is 2**257, we can divide by R with a bitwise shift if we can
-   * ensure that the right-most 257 bits are all zero. We can make that true by
-   * adding multiplies of p without affecting the value.
-   *
-   * So we eliminate limbs from right to left. Since the bottom 29 bits of p
-   * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
-   * We can do that for 8 further limbs and then right shift to eliminate the
-   * extra factor of R. */
-  for (i = 0;; i += 2) {
-    tmp2[i + 1] += tmp2[i] >> 29;
-    x = tmp2[i] & kBottom29Bits;
-    xMask = NON_ZERO_TO_ALL_ONES(x);
-    tmp2[i] = 0;
-
-    /* The bounds calculations for this loop are tricky. Each iteration of
-     * the loop eliminates two words by adding values to words to their
-     * right.
-     *
-     * The following table contains the amounts added to each word (as an
-     * offset from the value of i at the top of the loop). The amounts are
-     * accounted for from the first and second half of the loop separately
-     * and are written as, for example, 28 to mean a value <2**28.
-     *
-     * Word:                   3   4   5   6   7   8   9   10
-     * Added in top half:     28  11      29  21  29  28
-     *                                        28  29
-     *                                            29
-     * Added in bottom half:      29  10      28  21  28   28
-     *                                            29
-     *
-     * The value that is currently offset 7 will be offset 5 for the next
-     * iteration and then offset 3 for the iteration after that. Therefore
-     * the total value added will be the values added at 7, 5 and 3.
-     *
-     * The following table accumulates these values. The sums at the bottom
-     * are written as, for example, 29+28, to mean a value < 2**29+2**28.
-     *
-     * Word:                   3   4   5   6   7   8   9  10  11  12  13
-     *                        28  11  10  29  21  29  28  28  28  28  28
-     *                            29  28  11  28  29  28  29  28  29  28
-     *                                    29  28  21  21  29  21  29  21
-     *                                        10  29  28  21  28  21  28
-     *                                        28  29  28  29  28  29  28
-     *                                            11  10  29  10  29  10
-     *                                            29  28  11  28  11
-     *                                                    29      29
-     *                        --------------------------------------------
-     *                                                30+ 31+ 30+ 31+ 30+
-     *                                                28+ 29+ 28+ 29+ 21+
-     *                                                21+ 28+ 21+ 28+ 10
-     *                                                10  21+ 10  21+
-     *                                                    11      11
-     *
-     * So the greatest amount is added to tmp2[10] and tmp2[12]. If
-     * tmp2[10/12] has an initial value of <2**29, then the maximum value
-     * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
-     * as required. */
-    tmp2[i + 3] += (x << 10) & kBottom28Bits;
-    tmp2[i + 4] += (x >> 18);
-
-    tmp2[i + 6] += (x << 21) & kBottom29Bits;
-    tmp2[i + 7] += x >> 8;
-
-    /* At position 200, which is the starting bit position for word 7, we
-     * have a factor of 0xf000000 = 2**28 - 2**24. */
-    tmp2[i + 7] += 0x10000000 & xMask;
-    /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */
-    tmp2[i + 8] += (x - 1) & xMask;
-    tmp2[i + 7] -= (x << 24) & kBottom28Bits;
-    tmp2[i + 8] -= x >> 4;
-
-    tmp2[i + 8] += 0x20000000 & xMask;
-    tmp2[i + 8] -= x;
-    tmp2[i + 8] += (x << 28) & kBottom29Bits;
-    tmp2[i + 9] += ((x >> 1) - 1) & xMask;
-
-    if (i+1 == NLIMBS)
-      break;
-    tmp2[i + 2] += tmp2[i + 1] >> 28;
-    x = tmp2[i + 1] & kBottom28Bits;
-    xMask = NON_ZERO_TO_ALL_ONES(x);
-    tmp2[i + 1] = 0;
-
-    tmp2[i + 4] += (x << 11) & kBottom29Bits;
-    tmp2[i + 5] += (x >> 18);
-
-    tmp2[i + 7] += (x << 21) & kBottom28Bits;
-    tmp2[i + 8] += x >> 7;
-
-    /* At position 199, which is the starting bit of the 8th word when
-     * dealing with a context starting on an odd word, we have a factor of
-     * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
-     * word from i+1 is i+8. */
-    tmp2[i + 8] += 0x20000000 & xMask;
-    tmp2[i + 9] += (x - 1) & xMask;
-    tmp2[i + 8] -= (x << 25) & kBottom29Bits;
-    tmp2[i + 9] -= x >> 4;
-
-    tmp2[i + 9] += 0x10000000 & xMask;
-    tmp2[i + 9] -= x;
-    tmp2[i + 10] += (x - 1) & xMask;
-  }
-
-  /* We merge the right shift with a carry chain. The words above 2**257 have
-   * widths of 28,29,... which we need to correct when copying them down.  */
-  carry = 0;
-  for (i = 0; i < 8; i++) {
-    /* The maximum value of tmp2[i + 9] occurs on the first iteration and
-     * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
-     * therefore safe. */
-    out[i] = tmp2[i + 9];
-    out[i] += carry;
-    out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    out[i] = tmp2[i + 9] >> 1;
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  out[8] = tmp2[17];
-  out[8] += carry;
-  carry = out[8] >> 29;
-  out[8] &= kBottom29Bits;
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_square sets out=in*in.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_square(felem out, const felem in) {
-  u64 tmp[17];
-
-  tmp[0] = ((u64) in[0]) * in[0];
-  tmp[1] = ((u64) in[0]) * (in[1] << 1);
-  tmp[2] = ((u64) in[0]) * (in[2] << 1) +
-           ((u64) in[1]) * (in[1] << 1);
-  tmp[3] = ((u64) in[0]) * (in[3] << 1) +
-           ((u64) in[1]) * (in[2] << 1);
-  tmp[4] = ((u64) in[0]) * (in[4] << 1) +
-           ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
-  tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
-           (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
-  tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
-           (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
-           ((u64) in[3]) * (in[3] << 1);
-  tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
-           (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
-           ((u64) in[3]) * (in[4] << 1);
-  /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
-   * which is < 2**64 as required. */
-  tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
-           (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
-           ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
-  tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
-           (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
-           ((u64) in[4]) * (in[5] << 1);
-  tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
-            (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
-            ((u64) in[5]) * (in[5] << 1);
-  tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
-            (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
-  tmp[12] = ((u64) in[4]) * (in[8] << 1) +
-            ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
-  tmp[13] = ((u64) in[5]) * (in[8] << 1) +
-            ((u64) in[6]) * (in[7] << 1);
-  tmp[14] = ((u64) in[6]) * (in[8] << 1) +
-            ((u64) in[7]) * (in[7] << 1);
-  tmp[15] = ((u64) in[7]) * (in[8] << 1);
-  tmp[16] = ((u64) in[8]) * in[8];
-
-  felem_reduce_degree(out, tmp);
-}
-
-/* felem_mul sets out=in*in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_mul(felem out, const felem in, const felem in2) {
-  u64 tmp[17];
-
-  tmp[0] = ((u64) in[0]) * in2[0];
-  tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
-           ((u64) in[1]) * (in2[0] << 0);
-  tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
-           (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
-  tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
-           (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
-           ((u64) in[3]) * (in2[0] << 0);
-  tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
-           (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
-           ((u64) in[3]) * (in2[1] << 1) +
-           ((u64) in[4]) * (in2[0] << 0);
-  tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
-           (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
-           ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
-           (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
-  tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
-           (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
-           ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
-           (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
-           ((u64) in[6]) * (in2[0] << 0);
-  tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
-           (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
-           ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
-           (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
-           ((u64) in[6]) * (in2[1] << 0) +
-           ((u64) in[7]) * (in2[0] << 0);
-  /* tmp[8] has the greatest value but doesn't overflow. See logic in
-   * felem_square. */
-  tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
-           (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
-           ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
-           (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
-           ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
-           (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
-  tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
-           (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
-           ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
-           (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
-           ((u64) in[7]) * (in2[2] << 0) +
-           ((u64) in[8]) * (in2[1] << 0);
-  tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
-            (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
-            ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
-            (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
-            ((u64) in[8]) * (in2[2] << 0);
-  tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
-            (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
-            ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
-            (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
-  tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
-            (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
-            ((u64) in[7]) * (in2[5] << 1) +
-            ((u64) in[8]) * (in2[4] << 0);
-  tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
-            (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
-            ((u64) in[8]) * (in2[5] << 0);
-  tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
-            (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
-  tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
-            ((u64) in[8]) * (in2[7] << 0);
-  tmp[16] = ((u64) in[8]) * (in2[8] << 0);
-
-  felem_reduce_degree(out, tmp);
-}
-
-static void felem_assign(felem out, const felem in) {
-  memcpy(out, in, sizeof(felem));
-}
-
-/* felem_inv calculates |out| = |in|^{-1}
- *
- * Based on Fermat's Little Theorem:
- *   a^p = a (mod p)
- *   a^{p-1} = 1 (mod p)
- *   a^{p-2} = a^{-1} (mod p)
- */
-static void felem_inv(felem out, const felem in) {
-  felem ftmp, ftmp2;
-  /* each e_I will hold |in|^{2^I - 1} */
-  felem e2, e4, e8, e16, e32, e64;
-  unsigned i;
-
-  felem_square(ftmp, in); /* 2^1 */
-  felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
-  felem_assign(e2, ftmp);
-  felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
-  felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
-  felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
-  felem_assign(e4, ftmp);
-  felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
-  felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
-  felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
-  felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
-  felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
-  felem_assign(e8, ftmp);
-  for (i = 0; i < 8; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^16 - 2^8 */
-  felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
-  felem_assign(e16, ftmp);
-  for (i = 0; i < 16; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^32 - 2^16 */
-  felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
-  felem_assign(e32, ftmp);
-  for (i = 0; i < 32; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^64 - 2^32 */
-  felem_assign(e64, ftmp);
-  felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
-  for (i = 0; i < 192; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^256 - 2^224 + 2^192 */
-
-  felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
-  for (i = 0; i < 16; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^80 - 2^16 */
-  felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
-  for (i = 0; i < 8; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^88 - 2^8 */
-  felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
-  for (i = 0; i < 4; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^92 - 2^4 */
-  felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
-  felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
-  felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
-  felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
-  felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
-  felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
-  felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
-
-  felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
-}
-
-/* felem_scalar_3 sets out=3*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_3(felem out) {
-  limb carry = 0;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    out[i] *= 3;
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] *= 3;
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_4 sets out=4*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_4(felem out) {
-  limb carry = 0, next_carry;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    next_carry = out[i] >> 27;
-    out[i] <<= 2;
-    out[i] &= kBottom29Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 29);
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    next_carry = out[i] >> 26;
-    out[i] <<= 2;
-    out[i] &= kBottom28Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 28);
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_8 sets out=8*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_8(felem out) {
-  limb carry = 0, next_carry;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    next_carry = out[i] >> 26;
-    out[i] <<= 3;
-    out[i] &= kBottom29Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 29);
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    next_carry = out[i] >> 25;
-    out[i] <<= 3;
-    out[i] &= kBottom28Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 28);
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
- * time depending on the value of |in|. */
-static char felem_is_zero_vartime(const felem in) {
-  limb carry;
-  int i;
-  limb tmp[NLIMBS];
-
-  felem_assign(tmp, in);
-
-  /* First, reduce tmp to a minimal form. */
-  do {
-    carry = 0;
-    for (i = 0;; i++) {
-      tmp[i] += carry;
-      carry = tmp[i] >> 29;
-      tmp[i] &= kBottom29Bits;
-
-      i++;
-      if (i == NLIMBS)
-        break;
-
-      tmp[i] += carry;
-      carry = tmp[i] >> 28;
-      tmp[i] &= kBottom28Bits;
-    }
-
-    felem_reduce_carry(tmp, carry);
-  } while (carry);
-
-  /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
-  return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
-         memcmp(tmp, kP, sizeof(tmp)) == 0 ||
-         memcmp(tmp, k2P, sizeof(tmp)) == 0;
-}
-
-
-/* Group operations:
- *
- * Elements of the elliptic curve group are represented in Jacobian
- * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
- * Jacobian form. */
-
-/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
-static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
-                         const felem y, const felem z) {
-  felem delta, gamma, alpha, beta, tmp, tmp2;
-
-  felem_square(delta, z);
-  felem_square(gamma, y);
-  felem_mul(beta, x, gamma);
-
-  felem_sum(tmp, x, delta);
-  felem_diff(tmp2, x, delta);
-  felem_mul(alpha, tmp, tmp2);
-  felem_scalar_3(alpha);
-
-  felem_sum(tmp, y, z);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, gamma);
-  felem_diff(z_out, tmp, delta);
-
-  felem_scalar_4(beta);
-  felem_square(x_out, alpha);
-  felem_diff(x_out, x_out, beta);
-  felem_diff(x_out, x_out, beta);
-
-  felem_diff(tmp, beta, x_out);
-  felem_mul(tmp, alpha, tmp);
-  felem_square(tmp2, gamma);
-  felem_scalar_8(tmp2);
-  felem_diff(y_out, tmp, tmp2);
-}
-
-/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
- * (i.e. the second point is affine.)
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add_mixed(felem x_out, felem y_out, felem z_out,
-                            const felem x1, const felem y1, const felem z1,
-                            const felem x2, const felem y2) {
-  felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
-
-  felem_square(z1z1, z1);
-  felem_sum(tmp, z1, z1);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, x1);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, y1);
-  felem_sum(r, r, r);
-  felem_mul(v, x1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, y1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
-                      const felem y1, const felem z1, const felem x2,
-                      const felem y2, const felem z2) {
-  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
-
-  felem_square(z1z1, z1);
-  felem_square(z2z2, z2);
-  felem_mul(u1, x1, z2z2);
-
-  felem_sum(tmp, z1, z2);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, z1z1);
-  felem_diff(tmp, tmp, z2z2);
-
-  felem_mul(z2z2z2, z2, z2z2);
-  felem_mul(s1, y1, z2z2z2);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, u1);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, s1);
-  felem_sum(r, r, r);
-  felem_mul(v, u1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, s1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
- *                                                        {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
-static void point_add_or_double_vartime(
-    felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
-    const felem z1, const felem x2, const felem y2, const felem z2) {
-  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
-  char x_equal, y_equal;
-
-  felem_square(z1z1, z1);
-  felem_square(z2z2, z2);
-  felem_mul(u1, x1, z2z2);
-
-  felem_sum(tmp, z1, z2);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, z1z1);
-  felem_diff(tmp, tmp, z2z2);
-
-  felem_mul(z2z2z2, z2, z2z2);
-  felem_mul(s1, y1, z2z2z2);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, u1);
-  x_equal = felem_is_zero_vartime(h);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, s1);
-  y_equal = felem_is_zero_vartime(r);
-  if (x_equal && y_equal) {
-    point_double(x_out, y_out, z_out, x1, y1, z1);
-    return;
-  }
-  felem_sum(r, r, r);
-  felem_mul(v, u1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, s1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
- *
- * On entry: mask is either 0 or 0xffffffff. */
-static void copy_conditional(felem out, const felem in, limb mask) {
-  int i;
-
-  for (i = 0; i < NLIMBS; i++) {
-    const limb tmp = mask & (in[i] ^ out[i]);
-    out[i] ^= tmp;
-  }
-}
-
-/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
- * On entry: index < 16, table[0] must be zero. */
-static void select_affine_point(felem out_x, felem out_y, const limb* table,
-                                limb index) {
-  limb i, j;
-
-  memset(out_x, 0, sizeof(felem));
-  memset(out_y, 0, sizeof(felem));
-
-  for (i = 1; i < 16; i++) {
-    limb mask = i ^ index;
-    mask |= mask >> 2;
-    mask |= mask >> 1;
-    mask &= 1;
-    mask--;
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_x[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_y[j] |= *table & mask;
-    }
-  }
-}
-
-/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
- * table. On entry: index < 16, table[0] must be zero. */
-static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
-                                  const limb* table, limb index) {
-  limb i, j;
-
-  memset(out_x, 0, sizeof(felem));
-  memset(out_y, 0, sizeof(felem));
-  memset(out_z, 0, sizeof(felem));
-
-  /* The implicit value at index 0 is all zero. We don't need to perform that
-   * iteration of the loop because we already set out_* to zero. */
-  table += 3 * NLIMBS;
-
-  // Hit all entries to obscure cache profiling.
-  for (i = 1; i < 16; i++) {
-    limb mask = i ^ index;
-    mask |= mask >> 2;
-    mask |= mask >> 1;
-    mask &= 1;
-    mask--;
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_x[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_y[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_z[j] |= *table & mask;
-    }
-  }
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
- * number. Note that the value of scalar must be less than the order of the
- * group. */
-static void scalar_base_mult(felem nx, felem ny, felem nz,
-                             const p256_int* scalar) {
-  int i, j;
-  limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
-  u32 table_offset;
-
-  felem px, py;
-  felem tx, ty, tz;
-
-  memset(nx, 0, sizeof(felem));
-  memset(ny, 0, sizeof(felem));
-  memset(nz, 0, sizeof(felem));
-
-  /* The loop adds bits at positions 0, 64, 128 and 192, followed by
-   * positions 32,96,160 and 224 and does this 32 times. */
-  for (i = 0; i < 32; i++) {
-    if (i) {
-      point_double(nx, ny, nz, nx, ny, nz);
-    }
-    table_offset = 0;
-    for (j = 0; j <= 32; j += 32) {
-      char bit0 = p256_get_bit(scalar, 31 - i + j);
-      char bit1 = p256_get_bit(scalar, 95 - i + j);
-      char bit2 = p256_get_bit(scalar, 159 - i + j);
-      char bit3 = p256_get_bit(scalar, 223 - i + j);
-      limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
-
-      select_affine_point(px, py, kPrecomputed + table_offset, index);
-      table_offset += 30 * NLIMBS;
-
-      /* Since scalar is less than the order of the group, we know that
-       * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle
-       * below. */
-      point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
-      /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero
-       * (a.k.a.  the point at infinity). We handle that situation by
-       * copying the point from the table. */
-      copy_conditional(nx, px, n_is_infinity_mask);
-      copy_conditional(ny, py, n_is_infinity_mask);
-      copy_conditional(nz, kOne, n_is_infinity_mask);
-
-      /* Equally, the result is also wrong if the point from the table is
-       * zero, which happens when the index is zero. We handle that by
-       * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */
-      p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
-      mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
-      copy_conditional(nx, tx, mask);
-      copy_conditional(ny, ty, mask);
-      copy_conditional(nz, tz, mask);
-      /* If p was not zero, then n is now non-zero. */
-      n_is_infinity_mask &= ~p_is_noninfinite_mask;
-    }
-  }
-}
-
-/* point_to_affine converts a Jacobian point to an affine point. If the input
- * is the point at infinity then it returns (0, 0) in constant time. */
-static void point_to_affine(felem x_out, felem y_out, const felem nx,
-                            const felem ny, const felem nz) {
-  felem z_inv, z_inv_sq;
-  felem_inv(z_inv, nz);
-  felem_square(z_inv_sq, z_inv);
-  felem_mul(x_out, nx, z_inv_sq);
-  felem_mul(z_inv, z_inv, z_inv_sq);
-  felem_mul(y_out, ny, z_inv);
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
-static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
-                        const felem y, const p256_int* scalar) {
-  int i;
-  felem px, py, pz, tx, ty, tz;
-  felem precomp[16][3];
-  limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
-
-  /* We precompute 0,1,2,... times {x,y}. */
-  memset(precomp, 0, sizeof(felem) * 3);
-  memcpy(&precomp[1][0], x, sizeof(felem));
-  memcpy(&precomp[1][1], y, sizeof(felem));
-  memcpy(&precomp[1][2], kOne, sizeof(felem));
-
-  for (i = 2; i < 16; i += 2) {
-    point_double(precomp[i][0], precomp[i][1], precomp[i][2],
-                 precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);
-
-    point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
-                    precomp[i][0], precomp[i][1], precomp[i][2], x, y);
-  }
-
-  memset(nx, 0, sizeof(felem));
-  memset(ny, 0, sizeof(felem));
-  memset(nz, 0, sizeof(felem));
-  n_is_infinity_mask = -1;
-
-  /* We add in a window of four bits each iteration and do this 64 times. */
-  for (i = 0; i < 256; i += 4) {
-    if (i) {
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-    }
-
-    index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
-            (p256_get_bit(scalar, 255 - i - 1) << 2) |
-            (p256_get_bit(scalar, 255 - i - 2) << 1) |
-            p256_get_bit(scalar, 255 - i - 3);
-
-    /* See the comments in scalar_base_mult about handling infinities. */
-    select_jacobian_point(px, py, pz, precomp[0][0], index);
-    point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
-    copy_conditional(nx, px, n_is_infinity_mask);
-    copy_conditional(ny, py, n_is_infinity_mask);
-    copy_conditional(nz, pz, n_is_infinity_mask);
-
-    p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
-    mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
-
-    copy_conditional(nx, tx, mask);
-    copy_conditional(ny, ty, mask);
-    copy_conditional(nz, tz, mask);
-    n_is_infinity_mask &= ~p_is_noninfinite_mask;
-  }
-}
-
-#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p
-
-#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff}  // 1 / 2^257 mod p256.p
-
-static const p256_int kR = { kRDigits };
-static const p256_int kRInv = { kRInvDigits };
-
-/* to_montgomery sets out = R*in. */
-static void to_montgomery(felem out, const p256_int* in) {
-  p256_int in_shifted;
-  int i;
-
-  p256_init(&in_shifted);
-  p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
-
-  for (i = 0; i < NLIMBS; i++) {
-    if ((i & 1) == 0) {
-      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
-      p256_shr(&in_shifted, 29, &in_shifted);
-    } else {
-      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
-      p256_shr(&in_shifted, 28, &in_shifted);
-    }
-  }
-
-  p256_clear(&in_shifted);
-}
-
-/* from_montgomery sets out=in/R. */
-static void from_montgomery(p256_int* out, const felem in) {
-  p256_int result, tmp;
-  int i, top;
-
-  p256_init(&result);
-  p256_init(&tmp);
-
-  p256_add_d(&tmp, in[NLIMBS - 1], &result);
-  for (i = NLIMBS - 2; i >= 0; i--) {
-    if ((i & 1) == 0) {
-      top = p256_shl(&result, 29, &tmp);
-    } else {
-      top = p256_shl(&result, 28, &tmp);
-    }
-    top |= p256_add_d(&tmp, in[i], &result);
-  }
-
-  p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
-
-  p256_clear(&result);
-  p256_clear(&tmp);
-}
-
-/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
- * order of the group. */
-void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) {
-  felem x, y, z;
-
-  scalar_base_mult(x, y, z, n);
-
-  {
-    felem x_affine, y_affine;
-
-    point_to_affine(x_affine, y_affine, x, y, z);
-    from_montgomery(out_x, x_affine);
-    from_montgomery(out_y, y_affine);
-  }
-}
-
-/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
- * n1 and n2 are < the order of the group.
- *
- * As indicated by the name, this function operates in variable time. This
- * is safe because it's used for signature validation which doesn't deal
- * with secrets. */
-void p256_points_mul_vartime(
-    const p256_int* n1, const p256_int* n2, const p256_int* in_x,
-    const p256_int* in_y, p256_int* out_x, p256_int* out_y) {
-  felem x1, y1, z1, x2, y2, z2, px, py;
-
-  /* If both scalars are zero, then the result is the point at infinity. */
-  if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
-    p256_clear(out_x);
-    p256_clear(out_y);
-    return;
-  }
-
-  to_montgomery(px, in_x);
-  to_montgomery(py, in_y);
-  scalar_base_mult(x1, y1, z1, n1);
-  scalar_mult(x2, y2, z2, px, py, n2);
-
-  if (p256_is_zero(n2) != 0) {
-    /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
-         * {x1,y1,z1}. */
-  } else if (p256_is_zero(n1) != 0) {
-    /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
-         * {x2,y2,z2}. */
-    memcpy(x1, x2, sizeof(x2));
-    memcpy(y1, y2, sizeof(y2));
-    memcpy(z1, z2, sizeof(z2));
-  } else {
-    /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */
-    point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
-  }
-
-  point_to_affine(px, py, x1, y1, z1);
-  from_montgomery(out_x, px);
-  from_montgomery(out_y, py);
-}
diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c
deleted file mode 100644
index f2264b0..0000000
--- a/libmincrypt/p256_ecdsa.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/p256.h"
-
-int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
-                      const p256_int* message,
-                      const p256_int* r, const p256_int* s) {
-  p256_int u, v;
-
-  // Check public key.
-  if (!p256_is_valid_point(key_x, key_y)) return 0;
-
-  // Check r and s are != 0 % n.
-  p256_mod(&SECP256r1_n, r, &u);
-  p256_mod(&SECP256r1_n, s, &v);
-  if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
-
-  p256_modinv_vartime(&SECP256r1_n, s, &v);
-  p256_modmul(&SECP256r1_n, message, 0, &v, &u);  // message / s % n
-  p256_modmul(&SECP256r1_n, r, 0, &v, &v);  // r / s % n
-
-  p256_points_mul_vartime(&u, &v,
-                          key_x, key_y,
-                          &u, &v);
-
-  p256_mod(&SECP256r1_n, &u, &u);  // (x coord % p) % n
-  return p256_cmp(r, &u) == 0;
-}
-
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
deleted file mode 100644
index 9061b3a..0000000
--- a/libmincrypt/rsa.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/* rsa.c
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
-
-// a[] -= mod
-static void subM(const RSAPublicKey* key,
-                 uint32_t* a) {
-    int64_t A = 0;
-    int i;
-    for (i = 0; i < key->len; ++i) {
-        A += (uint64_t)a[i] - key->n[i];
-        a[i] = (uint32_t)A;
-        A >>= 32;
-    }
-}
-
-// return a[] >= mod
-static int geM(const RSAPublicKey* key,
-               const uint32_t* a) {
-    int i;
-    for (i = key->len; i;) {
-        --i;
-        if (a[i] < key->n[i]) return 0;
-        if (a[i] > key->n[i]) return 1;
-    }
-    return 1;  // equal
-}
-
-// montgomery c[] += a * b[] / R % mod
-static void montMulAdd(const RSAPublicKey* key,
-                       uint32_t* c,
-                       const uint32_t a,
-                       const uint32_t* b) {
-    uint64_t A = (uint64_t)a * b[0] + c[0];
-    uint32_t d0 = (uint32_t)A * key->n0inv;
-    uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
-    int i;
-
-    for (i = 1; i < key->len; ++i) {
-        A = (A >> 32) + (uint64_t)a * b[i] + c[i];
-        B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
-        c[i - 1] = (uint32_t)B;
-    }
-
-    A = (A >> 32) + (B >> 32);
-
-    c[i - 1] = (uint32_t)A;
-
-    if (A >> 32) {
-        subM(key, c);
-    }
-}
-
-// montgomery c[] = a[] * b[] / R % mod
-static void montMul(const RSAPublicKey* key,
-                    uint32_t* c,
-                    const uint32_t* a,
-                    const uint32_t* b) {
-    int i;
-    for (i = 0; i < key->len; ++i) {
-        c[i] = 0;
-    }
-    for (i = 0; i < key->len; ++i) {
-        montMulAdd(key, c, a[i], b);
-    }
-}
-
-// In-place public exponentiation.
-// Input and output big-endian byte array in inout.
-static void modpow(const RSAPublicKey* key,
-                   uint8_t* inout) {
-    uint32_t a[RSANUMWORDS];
-    uint32_t aR[RSANUMWORDS];
-    uint32_t aaR[RSANUMWORDS];
-    uint32_t* aaa = 0;
-    int i;
-
-    // Convert from big endian byte array to little endian word array.
-    for (i = 0; i < key->len; ++i) {
-        uint32_t tmp =
-            (inout[((key->len - 1 - i) * 4) + 0] << 24) |
-            (inout[((key->len - 1 - i) * 4) + 1] << 16) |
-            (inout[((key->len - 1 - i) * 4) + 2] << 8) |
-            (inout[((key->len - 1 - i) * 4) + 3] << 0);
-        a[i] = tmp;
-    }
-
-    if (key->exponent == 65537) {
-        aaa = aaR;  // Re-use location.
-        montMul(key, aR, a, key->rr);  // aR = a * RR / R mod M
-        for (i = 0; i < 16; i += 2) {
-            montMul(key, aaR, aR, aR);  // aaR = aR * aR / R mod M
-            montMul(key, aR, aaR, aaR);  // aR = aaR * aaR / R mod M
-        }
-        montMul(key, aaa, aR, a);  // aaa = aR * a / R mod M
-    } else if (key->exponent == 3) {
-        aaa = aR;  // Re-use location.
-        montMul(key, aR, a, key->rr);  /* aR = a * RR / R mod M   */
-        montMul(key, aaR, aR, aR);     /* aaR = aR * aR / R mod M */
-        montMul(key, aaa, aaR, a);     /* aaa = aaR * a / R mod M */
-    }
-
-    // Make sure aaa < mod; aaa is at most 1x mod too large.
-    if (geM(key, aaa)) {
-        subM(key, aaa);
-    }
-
-    // Convert to bigendian byte array
-    for (i = key->len - 1; i >= 0; --i) {
-        uint32_t tmp = aaa[i];
-        *inout++ = tmp >> 24;
-        *inout++ = tmp >> 16;
-        *inout++ = tmp >> 8;
-        *inout++ = tmp >> 0;
-    }
-}
-
-// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
-// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
-// other flavor which omits the optional parameter entirely). This code does not
-// accept signatures without the optional parameter.
-
-/*
-static const uint8_t sha_padding[RSANUMBYTES] = {
-    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
-    0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
-    0x05, 0x00, 0x04, 0x14,
-
-    // 20 bytes of hash go here.
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-*/
-
-// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
-    0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
-    0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
-    0x7c, 0xfb, 0xf1, 0x67
-};
-
-/*
-static const uint8_t sha256_padding[RSANUMBYTES] = {
-    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
-    0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
-    0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
-
-    // 32 bytes of hash go here.
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-};
-*/
-
-// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
-    0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
-    0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
-    0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
-    0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
-};
-
-// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
-// Both e=3 and e=65537 are supported.  hash_len may be
-// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
-// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash.  No other
-// values are supported.
-//
-// Returns 1 on successful verification, 0 on failure.
-int RSA_verify(const RSAPublicKey *key,
-               const uint8_t *signature,
-               const int len,
-               const uint8_t *hash,
-               const int hash_len) {
-    uint8_t buf[RSANUMBYTES];
-    int i;
-    const uint8_t* padding_hash;
-
-    if (key->len != RSANUMWORDS) {
-        return 0;  // Wrong key passed in.
-    }
-
-    if (len != sizeof(buf)) {
-        return 0;  // Wrong input length.
-    }
-
-    if (hash_len != SHA_DIGEST_SIZE &&
-        hash_len != SHA256_DIGEST_SIZE) {
-        return 0;  // Unsupported hash.
-    }
-
-    if (key->exponent != 3 && key->exponent != 65537) {
-        return 0;  // Unsupported exponent.
-    }
-
-    for (i = 0; i < len; ++i) {  // Copy input to local workspace.
-        buf[i] = signature[i];
-    }
-
-    modpow(key, buf);  // In-place exponentiation.
-
-    // Xor sha portion, so it all becomes 00 iff equal.
-    for (i = len - hash_len; i < len; ++i) {
-        buf[i] ^= *hash++;
-    }
-
-    // Hash resulting buf, in-place.
-    switch (hash_len) {
-        case SHA_DIGEST_SIZE:
-            padding_hash = kExpectedPadShaRsa2048;
-            SHA_hash(buf, len, buf);
-            break;
-        case SHA256_DIGEST_SIZE:
-            padding_hash = kExpectedPadSha256Rsa2048;
-            SHA256_hash(buf, len, buf);
-            break;
-        default:
-            return 0;
-    }
-
-    // Compare against expected hash value.
-    for (i = 0; i < hash_len; ++i) {
-        if (buf[i] != padding_hash[i]) {
-            return 0;
-        }
-    }
-
-    return 1;  // All checked out OK.
-}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
deleted file mode 100644
index 5bef32e..0000000
--- a/libmincrypt/sha.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* sha.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-static void SHA1_Transform(SHA_CTX* ctx) {
-    uint32_t W[80];
-    uint32_t A, B, C, D, E;
-    uint8_t* p = ctx->buf;
-    int t;
-
-    for(t = 0; t < 16; ++t) {
-        uint32_t tmp =  *p++ << 24;
-        tmp |= *p++ << 16;
-        tmp |= *p++ << 8;
-        tmp |= *p++;
-        W[t] = tmp;
-    }
-
-    for(; t < 80; t++) {
-        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
-    }
-
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-
-    for(t = 0; t < 80; t++) {
-        uint32_t tmp = rol(5,A) + E + W[t];
-
-        if (t < 20)
-            tmp += (D^(B&(C^D))) + 0x5A827999;
-        else if ( t < 40)
-            tmp += (B^C^D) + 0x6ED9EBA1;
-        else if ( t < 60)
-            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
-        else
-            tmp += (B^C^D) + 0xCA62C1D6;
-
-        E = D;
-        D = C;
-        C = rol(30,B);
-        B = A;
-        A = tmp;
-    }
-
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-}
-
-static const HASH_VTAB SHA_VTAB = {
-    SHA_init,
-    SHA_update,
-    SHA_final,
-    SHA_hash,
-    SHA_DIGEST_SIZE
-};
-
-void SHA_init(SHA_CTX* ctx) {
-    ctx->f = &SHA_VTAB;
-    ctx->state[0] = 0x67452301;
-    ctx->state[1] = 0xEFCDAB89;
-    ctx->state[2] = 0x98BADCFE;
-    ctx->state[3] = 0x10325476;
-    ctx->state[4] = 0xC3D2E1F0;
-    ctx->count = 0;
-}
-
-
-void SHA_update(SHA_CTX* ctx, const void* data, int len) {
-    int i = (int) (ctx->count & 63);
-    const uint8_t* p = (const uint8_t*)data;
-
-    ctx->count += len;
-
-    while (len--) {
-        ctx->buf[i++] = *p++;
-        if (i == 64) {
-            SHA1_Transform(ctx);
-            i = 0;
-        }
-    }
-}
-
-
-const uint8_t* SHA_final(SHA_CTX* ctx) {
-    uint8_t *p = ctx->buf;
-    uint64_t cnt = ctx->count * 8;
-    int i;
-
-    SHA_update(ctx, (uint8_t*)"\x80", 1);
-    while ((ctx->count & 63) != 56) {
-        SHA_update(ctx, (uint8_t*)"\0", 1);
-    }
-    for (i = 0; i < 8; ++i) {
-        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
-        SHA_update(ctx, &tmp, 1);
-    }
-
-    for (i = 0; i < 5; i++) {
-        uint32_t tmp = ctx->state[i];
-        *p++ = tmp >> 24;
-        *p++ = tmp >> 16;
-        *p++ = tmp >> 8;
-        *p++ = tmp >> 0;
-    }
-
-    return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
-    SHA_CTX ctx;
-    SHA_init(&ctx);
-    SHA_update(&ctx, data, len);
-    memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
-    return digest;
-}
diff --git a/libmincrypt/sha256.c b/libmincrypt/sha256.c
deleted file mode 100644
index eb6e308..0000000
--- a/libmincrypt/sha256.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* sha256.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha256.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
-#define shr(value, bits) ((value) >> (bits))
-
-static const uint32_t K[64] = {
-    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
-    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
-    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
-    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
-    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
-    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
-    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
-    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
-    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
-
-static void SHA256_Transform(SHA256_CTX* ctx) {
-    uint32_t W[64];
-    uint32_t A, B, C, D, E, F, G, H;
-    uint8_t* p = ctx->buf;
-    int t;
-
-    for(t = 0; t < 16; ++t) {
-        uint32_t tmp =  *p++ << 24;
-        tmp |= *p++ << 16;
-        tmp |= *p++ << 8;
-        tmp |= *p++;
-        W[t] = tmp;
-    }
-
-    for(; t < 64; t++) {
-        uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
-        uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
-        W[t] = W[t-16] + s0 + W[t-7] + s1;
-    }
-
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-    F = ctx->state[5];
-    G = ctx->state[6];
-    H = ctx->state[7];
-
-    for(t = 0; t < 64; t++) {
-        uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
-        uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
-        uint32_t t2 = s0 + maj;
-        uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
-        uint32_t ch = (E & F) ^ ((~E) & G);
-        uint32_t t1 = H + s1 + ch + K[t] + W[t];
-
-        H = G;
-        G = F;
-        F = E;
-        E = D + t1;
-        D = C;
-        C = B;
-        B = A;
-        A = t1 + t2;
-    }
-
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-    ctx->state[5] += F;
-    ctx->state[6] += G;
-    ctx->state[7] += H;
-}
-
-static const HASH_VTAB SHA256_VTAB = {
-    SHA256_init,
-    SHA256_update,
-    SHA256_final,
-    SHA256_hash,
-    SHA256_DIGEST_SIZE
-};
-
-void SHA256_init(SHA256_CTX* ctx) {
-    ctx->f = &SHA256_VTAB;
-    ctx->state[0] = 0x6a09e667;
-    ctx->state[1] = 0xbb67ae85;
-    ctx->state[2] = 0x3c6ef372;
-    ctx->state[3] = 0xa54ff53a;
-    ctx->state[4] = 0x510e527f;
-    ctx->state[5] = 0x9b05688c;
-    ctx->state[6] = 0x1f83d9ab;
-    ctx->state[7] = 0x5be0cd19;
-    ctx->count = 0;
-}
-
-
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
-    int i = (int) (ctx->count & 63);
-    const uint8_t* p = (const uint8_t*)data;
-
-    ctx->count += len;
-
-    while (len--) {
-        ctx->buf[i++] = *p++;
-        if (i == 64) {
-            SHA256_Transform(ctx);
-            i = 0;
-        }
-    }
-}
-
-
-const uint8_t* SHA256_final(SHA256_CTX* ctx) {
-    uint8_t *p = ctx->buf;
-    uint64_t cnt = ctx->count * 8;
-    int i;
-
-    SHA256_update(ctx, (uint8_t*)"\x80", 1);
-    while ((ctx->count & 63) != 56) {
-        SHA256_update(ctx, (uint8_t*)"\0", 1);
-    }
-    for (i = 0; i < 8; ++i) {
-        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
-        SHA256_update(ctx, &tmp, 1);
-    }
-
-    for (i = 0; i < 8; i++) {
-        uint32_t tmp = ctx->state[i];
-        *p++ = tmp >> 24;
-        *p++ = tmp >> 16;
-        *p++ = tmp >> 8;
-        *p++ = tmp >> 0;
-    }
-
-    return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
-    SHA256_CTX ctx;
-    SHA256_init(&ctx);
-    SHA256_update(&ctx, data, len);
-    memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
-    return digest;
-}
diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk
deleted file mode 100644
index 73ff7d0..0000000
--- a/libmincrypt/test/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := rsa_test
-LOCAL_SRC_FILES := rsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ecdsa_test
-LOCAL_SRC_FILES := ecdsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
deleted file mode 100644
index 24ec013..0000000
--- a/libmincrypt/test/ecdsa_test.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/sha256.h"
-
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
-/**
- * Messages signed using:
- *
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49
-AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24
-6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g==
------END EC PRIVATE KEY-----
- */
-
-p256_int key_x = {
-    .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu,
-          0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u}
-};
-p256_int key_y = {
-    .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au,
-          0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u}
-};
-
-char* message_1 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_1 =
-    "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-// Same as signature 1, but with leading zeroes.
-char* message_2 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_2 =
-    "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-// Excessive zeroes on the signature
-char* message_3 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_3 =
-    "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-
-char* good_dsa_signature_1 =
-    "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01";
-p256_int good_dsa_signature_1_r = {
-    .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
-          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-p256_int good_dsa_signature_1_s = {
-    .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U,
-          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-
-
-char* bad_dsa_signature_1 =
-     "a0 06 02 01 01 02 01 01";
-
-char* bad_dsa_signature_2 =
-     "30 07 02 01 01 02 01 01";
-
-char* bad_dsa_signature_3 =
-     "30 06 82 01 01 02 01 01";
-
-char* bad_dsa_signature_4 =
-     "30 06 02 00 01 02 01 01";
-
-char* bad_dsa_signature_5 =
-     "30 06 02 01 01 82 01 01";
-
-char* bad_dsa_signature_6 =
-     "30 05 02 01 01 02 00";
-
-char* bad_dsa_signature_7 =
-     "30 06 02 01 01 02 00 01";
-
-unsigned char* parsehex(char* str, int* len) {
-    // result can't be longer than input
-    unsigned char* result = malloc(strlen(str));
-
-    unsigned char* p = result;
-    *len = 0;
-
-    while (*str) {
-        int b;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b = (*str - '0') << 4; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b = (*str - 'a' + 10) << 4; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b = (*str - 'A' + 10) << 4; break;
-            case '\0':
-                return result;
-            default:
-                return NULL;
-        }
-        str++;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b |= *str - '0'; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b |= *str - 'a' + 10; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b |= *str - 'A' + 10; break;
-            default:
-                return NULL;
-        }
-        str++;
-
-        *p++ = b;
-        ++*len;
-    }
-
-    return result;
-}
-
-int main(int arg __unused, char** argv __unused) {
-
-    unsigned char hash_buf[SHA256_DIGEST_SIZE];
-
-    unsigned char* message;
-    int mlen;
-    unsigned char* signature;
-    int slen;
-
-    p256_int hash;
-    p256_int r;
-    p256_int s;
-
-    int success = 1;
-
-#define CHECK_DSA_SIG(sig, good) do {\
-    message = parsehex(sig, &mlen); \
-    int result = dsa_sig_unpack(message, mlen, &r, &s); \
-    printf(#sig ": %s\n", result ? "good" : "bad"); \
-    success = success && !(good ^ result); \
-    free(message); \
-    } while(0)
-#define CHECK_GOOD_DSA_SIG(n) do {\
-    CHECK_DSA_SIG(good_dsa_signature_##n, 1); \
-    int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \
-                         P256_NBYTES); \
-    success = success && result; \
-    printf("    R value %s\n", result ? "good" : "bad"); \
-    result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \
-                    P256_NBYTES); \
-    success = success && result; \
-    printf("    S value %s\n", result ? "good" : "bad"); \
-    } while (0)
-#define CHECK_BAD_DSA_SIG(n) \
-    CHECK_DSA_SIG(bad_dsa_signature_##n, 0)
-
-    CHECK_GOOD_DSA_SIG(1);
-
-    CHECK_BAD_DSA_SIG(1);
-    CHECK_BAD_DSA_SIG(2);
-    CHECK_BAD_DSA_SIG(3);
-    CHECK_BAD_DSA_SIG(4);
-    CHECK_BAD_DSA_SIG(5);
-    CHECK_BAD_DSA_SIG(6);
-    CHECK_BAD_DSA_SIG(7);
-
-
-#define TEST_MESSAGE(n) do {\
-    message = parsehex(message_##n, &mlen); \
-    SHA256_hash(message, mlen, hash_buf); \
-    p256_from_bin(hash_buf, &hash); \
-    signature = parsehex(signature_##n, &slen); \
-    int result = dsa_sig_unpack(signature, slen, &r, &s); \
-    if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \
-    printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
-    success = success && result; \
-    free(signature); \
-    } while(0)
-
-    TEST_MESSAGE(1);
-    TEST_MESSAGE(2);
-    TEST_MESSAGE(3);
-
-    printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
-    return !success;
-}
diff --git a/libmincrypt/test/rsa_test.c b/libmincrypt/test/rsa_test.c
deleted file mode 100644
index 055138f..0000000
--- a/libmincrypt/test/rsa_test.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**     * Redistributions of source code must retain the above copyright
-**       notice, this list of conditions and the following disclaimer.
-**     * Redistributions in binary form must reproduce the above copyright
-**       notice, this list of conditions and the following disclaimer in the
-**       documentation and/or other materials provided with the distribution.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-
-#ifndef __unused
-#define __unused __attribute__((unused))
-#endif
-
-// RSA test data taken from:
-//
-//   ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
-
-// This is the result (reformatted) of running DumpPublicKey on:
-//
-//   # Example 15: A 2048-bit RSA key pair
-//   # -----------------------------------
-//
-//
-//   # Public key
-//   # ----------
-//
-//   # Modulus:
-//   df 27 1f d2 5f 86 44 49 6b 0c 81 be 4b d5 02 97
-//   ef 09 9b 00 2a 6f d6 77 27 eb 44 9c ea 56 6e d6
-//   a3 98 1a 71 31 2a 14 1c ab c9 81 5c 12 09 e3 20
-//   a2 5b 32 46 4e 99 99 f1 8c a1 3a 9f d3 89 25 58
-//   f9 e0 ad ef dd 36 50 dd 23 a3 f0 36 d6 0f e3 98
-//   84 37 06 a4 0b 0b 84 62 c8 be e3 bc e1 2f 1f 28
-//   60 c2 44 4c dc 6a 44 47 6a 75 ff 4a a2 42 73 cc
-//   be 3b f8 02 48 46 5f 8f f8 c3 a7 f3 36 7d fc 0d
-//   f5 b6 50 9a 4f 82 81 1c ed d8 1c da aa 73 c4 91
-//   da 41 21 70 d5 44 d4 ba 96 b9 7f 0a fc 80 65 49
-//   8d 3a 49 fd 91 09 92 a1 f0 72 5b e2 4f 46 5c fe
-//   7e 0e ab f6 78 99 6c 50 bc 5e 75 24 ab f7 3f 15
-//   e5 be f7 d5 18 39 4e 31 38 ce 49 44 50 6a aa af
-//   3f 9b 23 6d ca b8 fc 00 f8 7a f5 96 fd c3 d9 d6
-//   c7 5c d5 08 36 2f ae 2c be dd cc 4c 74 50 b1 7b
-//   77 6c 07 9e cc a1 f2 56 35 1a 43 b9 7d be 21 53
-//
-//   # Exponent:
-//   01 00 01
-
-RSAPublicKey key_15 = {
-    .len = 64,
-    .n0inv = 0xf0053525,
-    .n = {2109612371u,890913721u,3433165398u,2003568542u,
-          1951445371u,3202206796u,909094444u,3344749832u,
-          4257470934u,4168807830u,3401120768u,1067131757u,
-          1349167791u,953043268u,406408753u,3854497749u,
-          2885107477u,3160306980u,2023320656u,2114890742u,
-          1330011390u,4034026466u,2433323681u,2369407485u,
-          4236272969u,2528739082u,3578057914u,3661701488u,
-          2859713681u,3990363354u,1333952796u,4122366106u,
-          914226189u,4173572083u,1212571535u,3191601154u,
-          2722264012u,1786117962u,3697951815u,1623344204u,
-          3777961768u,3367953340u,185304162u,2218198692u,
-          3591365528u,597946422u,3711324381u,4192251375u,
-          3548980568u,2359376543u,1318689265u,2723885638u,
-          302637856u,2882109788u,824841244u,2744654449u,
-          3931533014u,669729948u,711972471u,4010384128u,
-          1272251031u,1795981758u,1602634825u,3743883218u},
-    .rr = {820482522u,2494434288u,1082168230u,731376296u,
-           1306039452u,3139792975u,2575869288u,3874938710u,
-           3198185181u,153506080u,1236489694u,1061859740u,
-           1174461268u,115279508u,1782749185u,238124145u,
-           3587596076u,2259236093u,1112265915u,4048059865u,
-           3890381098u,999426242u,794481771u,3804065613u,
-           2786019148u,461403875u,3072256692u,4079652654u,
-           3056719901u,1871565394u,212974856u,3359008174u,
-           1397773937u,3796256698u,914342841u,1097174457u,
-           3322220191u,3170814748u,2439215020u,618719336u,
-           3629353460u,496817177u,317052742u,380264245u,
-           1976007217u,2697736152u,312540864u,4291855337u,
-           697006561u,4234182488u,3904590917u,2609582216u,
-           451424084u,1805773827u,776344974u,1064489733u,
-           2633377036u,1954826648u,3202815814u,2240368662u,
-           2618582484u,2211196815u,4107362845u,3640258615u},
-    .exponent = 65537,
-};
-
-// PKCS#1 v1.5 Signature Example 15.1
-
-char* message_1 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_1 =
-    "b7 5a 54 66 b6 5d 0f 30 0e f5 38 33 f2 17 5c 8a"
-    "34 7a 38 04 fc 63 45 1d c9 02 f0 b7 1f 90 83 45"
-    "9e d3 7a 51 79 a3 b7 23 a5 3f 10 51 64 2d 77 37"
-    "4c 4c 6c 8d bb 1c a2 05 25 f5 c9 f3 2d b7 76 95"
-    "35 56 da 31 29 0e 22 19 74 82 ce b6 99 06 c4 6a"
-    "75 8f b0 e7 40 9b a8 01 07 7d 2a 0a 20 ea e7 d1"
-    "d6 d3 92 ab 49 57 e8 6b 76 f0 65 2d 68 b8 39 88"
-    "a7 8f 26 e1 11 72 ea 60 9b f8 49 fb bd 78 ad 7e"
-    "dc e2 1d e6 62 a0 81 36 8c 04 06 07 ce e2 9d b0"
-    "62 72 27 f4 49 63 ad 17 1d 22 93 b6 33 a3 92 e3"
-    "31 dc a5 4f e3 08 27 52 f4 3f 63 c1 61 b4 47 a4"
-    "c6 5a 68 75 67 0d 5f 66 00 fc c8 60 a1 ca eb 0a"
-    "88 f8 fd ec 4e 56 43 98 a5 c4 6c 87 f6 8c e0 70"
-    "01 f6 21 3a be 0a b5 62 5f 87 d1 90 25 f0 8d 81"
-    "da c7 bd 45 86 bc 93 82 19 1f 6d 28 80 f6 22 7e"
-    "5d f3 ee d2 1e 77 92 d2 49 48 04 87 f3 65 52 61";
-
-// PKCS#1 v1.5 Signature Example 15.2
-
-char *message_2 =
-    "c1 4b 4c 60 75 b2 f9 aa d6 61 de f4 ec fd 3c b9 "
-    "33 c6 23 f4 e6 3b f5 34 10 d2 f0 16 d1 ab 98 e2 "
-    "72 9e cc f8 00 6c d8 e0 80 50 73 7d 95 fd bf 29 "
-    "6b 66 f5 b9 79 2a 90 29 36 c4 f7 ac 69 f5 14 53 "
-    "ce 43 69 45 2d c2 2d 96 f0 37 74 81 14 66 20 00 "
-    "dd 9c d3 a5 e1 79 f4 e0 f8 1f a6 a0 31 1c a1 ae "
-    "e6 51 9a 0f 63 ce c7 8d 27 bb 72 63 93 fb 7f 1f "
-    "88 cd e7 c9 7f 8a 66 cd 66 30 12 81 da c3 f3 a4 "
-    "33 24 8c 75 d6 c2 dc d7 08 b6 a9 7b 0a 3f 32 5e "
-    "0b 29 64 f8 a5 81 9e 47 9b ";
-
-char* signature_2 =
-    "af a7 34 34 62 be a1 22 cc 14 9f ca 70 ab da e7"
-    "94 46 67 7d b5 37 36 66 af 7d c3 13 01 5f 4d e7"
-    "86 e6 e3 94 94 6f ad 3c c0 e2 b0 2b ed ba 50 47"
-    "fe 9e 2d 7d 09 97 05 e4 a3 9f 28 68 32 79 cf 0a"
-    "c8 5c 15 30 41 22 42 c0 e9 18 95 3b e0 00 e9 39"
-    "cf 3b f1 82 52 5e 19 93 70 fa 79 07 eb a6 9d 5d"
-    "b4 63 10 17 c0 e3 6d f7 03 79 b5 db 8d 4c 69 5a"
-    "97 9a 8e 61 73 22 40 65 d7 dc 15 13 2e f2 8c d8"
-    "22 79 51 63 06 3b 54 c6 51 14 1b e8 6d 36 e3 67"
-    "35 bc 61 f3 1f ca 57 4e 53 09 f3 a3 bb df 91 ef"
-    "f1 2b 99 e9 cc 17 44 f1 ee 9a 1b d2 2c 5b ad 96"
-    "ad 48 19 29 25 1f 03 43 fd 36 bc f0 ac de 7f 11"
-    "e5 ad 60 97 77 21 20 27 96 fe 06 1f 9a da 1f c4"
-    "c8 e0 0d 60 22 a8 35 75 85 ff e9 fd d5 93 31 a2"
-    "8c 4a a3 12 15 88 fb 6c f6 83 96 d8 ac 05 46 59"
-    "95 00 c9 70 85 00 a5 97 2b d5 4f 72 cf 8d b0 c8";
-
-// PKCS#1 v1.5 Signature Example 15.3
-
-char* message_3 =
-    "d0 23 71 ad 7e e4 8b bf db 27 63 de 7a 84 3b 94 "
-    "08 ce 5e b5 ab f8 47 ca 3d 73 59 86 df 84 e9 06 "
-    "0b db cd d3 a5 5b a5 5d de 20 d4 76 1e 1a 21 d2 "
-    "25 c1 a1 86 f4 ac 4b 30 19 d3 ad f7 8f e6 33 46 "
-    "67 f5 6f 70 c9 01 a0 a2 70 0c 6f 0d 56 ad d7 19 "
-    "59 2d c8 8f 6d 23 06 c7 00 9f 6e 7a 63 5b 4c b3 "
-    "a5 02 df e6 8d dc 58 d0 3b e1 0a 11 70 00 4f e7 "
-    "4d d3 e4 6b 82 59 1f f7 54 14 f0 c4 a0 3e 60 5e "
-    "20 52 4f 24 16 f1 2e ca 58 9f 11 1b 75 d6 39 c6 "
-    "1b aa 80 ca fd 05 cf 35 00 24 4a 21 9e d9 ce d9 "
-    "f0 b1 02 97 18 2b 65 3b 52 6f 40 0f 29 53 ba 21 "
-    "4d 5b cd 47 88 41 32 87 2a e9 0d 4d 6b 1f 42 15 "
-    "39 f9 f3 46 62 a5 6d c0 e7 b4 b9 23 b6 23 1e 30 "
-    "d2 67 67 97 81 7f 7c 33 7b 5a c8 24 ba 93 14 3b "
-    "33 81 fa 3d ce 0e 6a eb d3 8e 67 73 51 87 b1 eb "
-    "d9 5c 02 ";
-
-char* signature_3 =
-    "3b ac 63 f8 6e 3b 70 27 12 03 10 6b 9c 79 aa bd"
-    "9f 47 7c 56 e4 ee 58 a4 fc e5 ba f2 ca b4 96 0f"
-    "88 39 1c 9c 23 69 8b e7 5c 99 ae df 9e 1a bf 17"
-    "05 be 1d ac 33 14 0a db 48 eb 31 f4 50 bb 9e fe"
-    "83 b7 b9 0d b7 f1 57 6d 33 f4 0c 1c ba 4b 8d 6b"
-    "1d 33 23 56 4b 0f 17 74 11 4f a7 c0 8e 6d 1e 20"
-    "dd 8f bb a9 b6 ac 7a d4 1e 26 b4 56 8f 4a 8a ac"
-    "bf d1 78 a8 f8 d2 c9 d5 f5 b8 81 12 93 5a 8b c9"
-    "ae 32 cd a4 0b 8d 20 37 55 10 73 50 96 53 68 18"
-    "ce 2b 2d b7 1a 97 72 c9 b0 dd a0 9a e1 01 52 fa"
-    "11 46 62 18 d0 91 b5 3d 92 54 30 61 b7 29 4a 55"
-    "be 82 ff 35 d5 c3 2f a2 33 f0 5a aa c7 58 50 30"
-    "7e cf 81 38 3c 11 16 74 39 7b 1a 1b 9d 3b f7 61"
-    "2c cb e5 ba cd 2b 38 f0 a9 83 97 b2 4c 83 65 8f"
-    "b6 c0 b4 14 0e f1 19 70 c4 63 0d 44 34 4e 76 ea"
-    "ed 74 dc be e8 11 db f6 57 59 41 f0 8a 65 23 b8";
-
-// PKCS#1 v1.5 Signature Example 15.4
-
-char* message_4 =
-    "29 03 55 84 ab 7e 02 26 a9 ec 4b 02 e8 dc f1 27 "
-    "2d c9 a4 1d 73 e2 82 00 07 b0 f6 e2 1f ec cd 5b "
-    "d9 db b9 ef 88 cd 67 58 76 9e e1 f9 56 da 7a d1 "
-    "84 41 de 6f ab 83 86 db c6 93 ";
-
-char* signature_4 =
-    "28 d8 e3 fc d5 dd db 21 ff bd 8d f1 63 0d 73 77"
-    "aa 26 51 e1 4c ad 1c 0e 43 cc c5 2f 90 7f 94 6d"
-    "66 de 72 54 e2 7a 6c 19 0e b0 22 ee 89 ec f6 22"
-    "4b 09 7b 71 06 8c d6 07 28 a1 ae d6 4b 80 e5 45"
-    "7b d3 10 6d d9 17 06 c9 37 c9 79 5f 2b 36 36 7f"
-    "f1 53 dc 25 19 a8 db 9b df 2c 80 74 30 c4 51 de"
-    "17 bb cd 0c e7 82 b3 e8 f1 02 4d 90 62 4d ea 7f"
-    "1e ed c7 42 0b 7e 7c aa 65 77 ce f4 31 41 a7 26"
-    "42 06 58 0e 44 a1 67 df 5e 41 ee a0 e6 9a 80 54"
-    "54 c4 0e ef c1 3f 48 e4 23 d7 a3 2d 02 ed 42 c0"
-    "ab 03 d0 a7 cf 70 c5 86 0a c9 2e 03 ee 00 5b 60"
-    "ff 35 03 42 4b 98 cc 89 45 68 c7 c5 6a 02 33 55"
-    "1c eb e5 88 cf 8b 01 67 b7 df 13 ad ca d8 28 67"
-    "68 10 49 9c 70 4d a7 ae 23 41 4d 69 e3 c0 d2 db"
-    "5d cb c2 61 3b c1 20 42 1f 9e 36 53 c5 a8 76 72"
-    "97 64 3c 7e 07 40 de 01 63 55 45 3d 6c 95 ae 72";
-
-// PKCS#1 v1.5 Signature Example 15.5
-
-char* message_5 =
-    "bd a3 a1 c7 90 59 ea e5 98 30 8d 3d f6 09 ";
-
-char* signature_5 =
-    "a1 56 17 6c b9 67 77 c7 fb 96 10 5d bd 91 3b c4"
-    "f7 40 54 f6 80 7c 60 08 a1 a9 56 ea 92 c1 f8 1c"
-    "b8 97 dc 4b 92 ef 9f 4e 40 66 8d c7 c5 56 90 1a"
-    "cb 6c f2 69 fe 61 5b 0f b7 2b 30 a5 13 38 69 23"
-    "14 b0 e5 87 8a 88 c2 c7 77 4b d1 69 39 b5 ab d8"
-    "2b 44 29 d6 7b d7 ac 8e 5e a7 fe 92 4e 20 a6 ec"
-    "66 22 91 f2 54 8d 73 4f 66 34 86 8b 03 9a a5 f9"
-    "d4 d9 06 b2 d0 cb 85 85 bf 42 85 47 af c9 1c 6e"
-    "20 52 dd cd 00 1c 3e f8 c8 ee fc 3b 6b 2a 82 b6"
-    "f9 c8 8c 56 f2 e2 c3 cb 0b e4 b8 0d a9 5e ba 37"
-    "1d 8b 5f 60 f9 25 38 74 3d db b5 da 29 72 c7 1f"
-    "e7 b9 f1 b7 90 26 8a 0e 77 0f c5 eb 4d 5d d8 52"
-    "47 d4 8a e2 ec 3f 26 25 5a 39 85 52 02 06 a1 f2"
-    "68 e4 83 e9 db b1 d5 ca b1 90 91 76 06 de 31 e7"
-    "c5 18 2d 8f 15 1b f4 1d fe cc ae d7 cd e6 90 b2"
-    "16 47 10 6b 49 0c 72 9d 54 a8 fe 28 02 a6 d1 26";
-
-// PKCS#1 v1.5 Signature Example 15.6
-
-char* message_6 =
-    "c1 87 91 5e 4e 87 da 81 c0 8e d4 35 6a 0c ce ac "
-    "1c 4f b5 c0 46 b4 52 81 b3 87 ec 28 f1 ab fd 56 "
-    "7e 54 6b 23 6b 37 d0 1a e7 1d 3b 28 34 36 5d 3d "
-    "f3 80 b7 50 61 b7 36 b0 13 0b 07 0b e5 8a e8 a4 "
-    "6d 12 16 63 61 b6 13 db c4 7d fa eb 4c a7 46 45 "
-    "6c 2e 88 83 85 52 5c ca 9d d1 c3 c7 a9 ad a7 6d "
-    "6c ";;
-
-char* signature_6 =
-    "9c ab 74 16 36 08 66 9f 75 55 a3 33 cf 19 6f e3"
-    "a0 e9 e5 eb 1a 32 d3 4b b5 c8 5f f6 89 aa ab 0e"
-    "3e 65 66 8e d3 b1 15 3f 94 eb 3d 8b e3 79 b8 ee"
-    "f0 07 c4 a0 2c 70 71 ce 30 d8 bb 34 1e 58 c6 20"
-    "f7 3d 37 b4 ec bf 48 be 29 4f 6c 9e 0e cb 5e 63"
-    "fe c4 1f 12 0e 55 53 df a0 eb eb bb 72 64 0a 95"
-    "37 ba dc b4 51 33 02 29 d9 f7 10 f6 2e 3e d8 ec"
-    "78 4e 50 ee 1d 92 62 b4 26 71 34 00 11 d7 d0 98"
-    "c6 f2 55 7b 21 31 fa 9b d0 25 46 36 59 7e 88 ec"
-    "b3 5a 24 0e f0 fd 85 95 71 24 df 80 80 fe e1 e1"
-    "49 af 93 99 89 e8 6b 26 c8 5a 58 81 fa e8 67 3d"
-    "9f d4 08 00 dd 13 4e b9 bd b6 41 0f 42 0b 0a a9"
-    "7b 20 ef cf 2e b0 c8 07 fa eb 83 a3 cc d9 b5 1d"
-    "45 53 e4 1d fc 0d f6 ca 80 a1 e8 1d c2 34 bb 83"
-    "89 dd 19 5a 38 b4 2d e4 ed c4 9d 34 64 78 b9 f1"
-    "1f 05 57 20 5f 5b 0b d7 ff e9 c8 50 f3 96 d7 c4";;
-
-// PKCS#1 v1.5 Signature Example 15.7
-
-char* message_7 =
-    "ab fa 2e cb 7d 29 bd 5b cb 99 31 ce 2b ad 2f 74 "
-    "38 3e 95 68 3c ee 11 02 2f 08 e8 e7 d0 b8 fa 05 "
-    "8b f9 eb 7e b5 f9 88 68 b5 bb 1f b5 c3 1c ed a3 "
-    "a6 4f 1a 12 cd f2 0f cd 0e 5a 24 6d 7a 17 73 d8 "
-    "db a0 e3 b2 77 54 5b ab e5 8f 2b 96 e3 f4 ed c1 "
-    "8e ab f5 cd 2a 56 0f ca 75 fe 96 e0 7d 85 9d ef "
-    "b2 56 4f 3a 34 f1 6f 11 e9 1b 3a 71 7b 41 af 53 "
-    "f6 60 53 23 00 1a a4 06 c6 ";
-
-char* signature_7 =
-    "c4 b4 37 bc f7 03 f3 52 e1 fa f7 4e b9 62 20 39"
-    "42 6b 56 72 ca f2 a7 b3 81 c6 c4 f0 19 1e 7e 4a"
-    "98 f0 ee bc d6 f4 17 84 c2 53 7f f0 f9 9e 74 98"
-    "2c 87 20 1b fb c6 5e ae 83 2d b7 1d 16 da ca db"
-    "09 77 e5 c5 04 67 9e 40 be 0f 9d b0 6f fd 84 8d"
-    "d2 e5 c3 8a 7e c0 21 e7 f6 8c 47 df d3 8c c3 54"
-    "49 3d 53 39 b4 59 5a 5b f3 1e 3f 8f 13 81 68 07"
-    "37 3d f6 ad 0d c7 e7 31 e5 1a d1 9e b4 75 4b 13"
-    "44 85 84 2f e7 09 d3 78 44 4d 8e 36 b1 72 4a 4f"
-    "da 21 ca fe e6 53 ab 80 74 7f 79 52 ee 80 4d ea"
-    "b1 03 9d 84 13 99 45 bb f4 be 82 00 87 53 f3 c5"
-    "4c 78 21 a1 d2 41 f4 21 79 c7 94 ef 70 42 bb f9"
-    "95 56 56 22 2e 45 c3 43 69 a3 84 69 7b 6a e7 42"
-    "e1 8f a5 ca 7a ba d2 7d 9f e7 10 52 e3 31 0d 0f"
-    "52 c8 d1 2e a3 3b f0 53 a3 00 f4 af c4 f0 98 df"
-    "4e 6d 88 67 79 d6 45 94 d3 69 15 8f db c1 f6 94";
-
-// PKCS#1 v1.5 Signature Example 15.8
-
-char* message_8 =
-    "df 40 44 a8 9a 83 e9 fc bf 12 62 54 0a e3 03 8b "
-    "bc 90 f2 b2 62 8b f2 a4 46 7a c6 77 22 d8 54 6b "
-    "3a 71 cb 0e a4 16 69 d5 b4 d6 18 59 c1 b4 e4 7c "
-    "ec c5 93 3f 75 7e c8 6d b0 64 4e 31 18 12 d0 0f "
-    "b8 02 f0 34 00 63 9c 0e 36 4d ae 5a eb c5 79 1b "
-    "c6 55 76 23 61 bc 43 c5 3d 3c 78 86 76 8f 79 68 "
-    "c1 c5 44 c6 f7 9f 7b e8 20 c7 e2 bd 2f 9d 73 e6 "
-    "2d ed 6d 2e 93 7e 6a 6d ae f9 0e e3 7a 1a 52 a5 "
-    "4f 00 e3 1a dd d6 48 94 cf 4c 02 e1 60 99 e2 9f "
-    "9e b7 f1 a7 bb 7f 84 c4 7a 2b 59 48 13 be 02 a1 "
-    "7b 7f c4 3b 34 c2 2c 91 92 52 64 12 6c 89 f8 6b "
-    "b4 d8 7f 3e f1 31 29 6c 53 a3 08 e0 33 1d ac 8b "
-    "af 3b 63 42 22 66 ec ef 2b 90 78 15 35 db da 41 "
-    "cb d0 cf 22 a8 cb fb 53 2e c6 8f c6 af b2 ac 06 ";
-
-char* signature_8 =
-    "14 14 b3 85 67 ae 6d 97 3e de 4a 06 84 2d cc 0e"
-    "05 59 b1 9e 65 a4 88 9b db ab d0 fd 02 80 68 29"
-    "13 ba cd 5d c2 f0 1b 30 bb 19 eb 81 0b 7d 9d ed"
-    "32 b2 84 f1 47 bb e7 71 c9 30 c6 05 2a a7 34 13"
-    "90 a8 49 f8 1d a9 cd 11 e5 ec cf 24 6d ba e9 5f"
-    "a9 58 28 e9 ae 0c a3 55 03 25 32 6d ee f9 f4 95"
-    "30 ba 44 1b ed 4a c2 9c 02 9c 9a 27 36 b1 a4 19"
-    "0b 85 08 4a d1 50 42 6b 46 d7 f8 5b d7 02 f4 8d"
-    "ac 5f 71 33 0b c4 23 a7 66 c6 5c c1 dc ab 20 d3"
-    "d3 bb a7 2b 63 b3 ef 82 44 d4 2f 15 7c b7 e3 a8"
-    "ba 5c 05 27 2c 64 cc 1a d2 1a 13 49 3c 39 11 f6"
-    "0b 4e 9f 4e cc 99 00 eb 05 6e e5 9d 6f e4 b8 ff"
-    "6e 80 48 cc c0 f3 8f 28 36 fd 3d fe 91 bf 4a 38"
-    "6e 1e cc 2c 32 83 9f 0c a4 d1 b2 7a 56 8f a9 40"
-    "dd 64 ad 16 bd 01 25 d0 34 8e 38 30 85 f0 88 94"
-    "86 1c a1 89 87 22 7d 37 b4 2b 58 4a 83 57 cb 04";
-
-// PKCS#1 v1.5 Signature Example 15.9
-
-char* message_9 =
-    "ea 94 1f f0 6f 86 c2 26 92 7f cf 0e 3b 11 b0 87 "
-    "26 76 17 0c 1b fc 33 bd a8 e2 65 c7 77 71 f9 d0 "
-    "85 01 64 a5 ee cb cc 5c e8 27 fb fa 07 c8 52 14 "
-    "79 6d 81 27 e8 ca a8 18 94 ea 61 ce b1 44 9e 72 "
-    "fe a0 a4 c9 43 b2 da 6d 9b 10 5f e0 53 b9 03 9a "
-    "9c c5 3d 42 0b 75 39 fa b2 23 9c 6b 51 d1 7e 69 "
-    "4c 95 7d 4b 0f 09 84 46 18 79 a0 75 9c 44 01 be "
-    "ec d4 c6 06 a0 af bd 7a 07 6f 50 a2 df c2 80 7f "
-    "24 f1 91 9b aa 77 46 d3 a6 4e 26 8e d3 f5 f8 e6 "
-    "da 83 a2 a5 c9 15 2f 83 7c b0 78 12 bd 5b a7 d3 "
-    "a0 79 85 de 88 11 3c 17 96 e9 b4 66 ec 29 9c 5a "
-    "c1 05 9e 27 f0 94 15 ";
-
-char* signature_9 =
-    "ce eb 84 cc b4 e9 09 92 65 65 07 21 ee a0 e8 ec"
-    "89 ca 25 bd 35 4d 4f 64 56 49 67 be 9d 4b 08 b3"
-    "f1 c0 18 53 9c 9d 37 1c f8 96 1f 22 91 fb e0 dc"
-    "2f 2f 95 fe a4 7b 63 9f 1e 12 f4 bc 38 1c ef 0c"
-    "2b 7a 7b 95 c3 ad f2 76 05 b7 f6 39 98 c3 cb ad"
-    "54 28 08 c3 82 2e 06 4d 4a d1 40 93 67 9e 6e 01"
-    "41 8a 6d 5c 05 96 84 cd 56 e3 4e d6 5a b6 05 b8"
-    "de 4f cf a6 40 47 4a 54 a8 25 1b bb 73 26 a4 2d"
-    "08 58 5c fc fc 95 67 69 b1 5b 6d 7f df 7d a8 4f"
-    "81 97 6e aa 41 d6 92 38 0f f1 0e ae cf e0 a5 79"
-    "68 29 09 b5 52 1f ad e8 54 d7 97 b8 a0 34 5b 9a"
-    "86 4e 05 88 f6 ca dd bf 65 f1 77 99 8e 18 0d 1f"
-    "10 24 43 e6 dc a5 3a 94 82 3c aa 9c 3b 35 f3 22"
-    "58 3c 70 3a f6 74 76 15 9e c7 ec 93 d1 76 9b 30"
-    "0a f0 e7 15 7d c2 98 c6 cd 2d ee 22 62 f8 cd dc"
-    "10 f1 1e 01 74 14 71 bb fd 65 18 a1 75 73 45 75";
-
-// PKCS#1 v1.5 Signature Example 15.10
-
-char* message_10 =
-    "d8 b8 16 45 c1 3c d7 ec f5 d0 0e d2 c9 1b 9a cd "
-    "46 c1 55 68 e5 30 3c 4a 97 75 ed e7 6b 48 40 3d "
-    "6b e5 6c 05 b6 b1 cf 77 c6 e7 5d e0 96 c5 cb 35 "
-    "51 cb 6f a9 64 f3 c8 79 cf 58 9d 28 e1 da 2f 9d "
-    "ec ";
-
-char* signature_10 =
-    "27 45 07 4c a9 71 75 d9 92 e2 b4 47 91 c3 23 c5"
-    "71 67 16 5c dd 8d a5 79 cd ef 46 86 b9 bb 40 4b"
-    "d3 6a 56 50 4e b1 fd 77 0f 60 bf a1 88 a7 b2 4b"
-    "0c 91 e8 81 c2 4e 35 b0 4d c4 dd 4c e3 85 66 bc"
-    "c9 ce 54 f4 9a 17 5f c9 d0 b2 25 22 d9 57 90 47"
-    "f9 ed 42 ec a8 3f 76 4a 10 16 39 97 94 7e 7d 2b"
-    "52 ff 08 98 0e 7e 7c 22 57 93 7b 23 f3 d2 79 d4"
-    "cd 17 d6 f4 95 54 63 73 d9 83 d5 36 ef d7 d1 b6"
-    "71 81 ca 2c b5 0a c6 16 c5 c7 ab fb b9 26 0b 91"
-    "b1 a3 8e 47 24 20 01 ff 45 2f 8d e1 0c a6 ea ea"
-    "dc af 9e dc 28 95 6f 28 a7 11 29 1f c9 a8 08 78"
-    "b8 ba 4c fe 25 b8 28 1c b8 0b c9 cd 6d 2b d1 82"
-    "52 46 ee be 25 2d 99 57 ef 93 70 73 52 08 4e 6d"
-    "36 d4 23 55 1b f2 66 a8 53 40 fb 4a 6a f3 70 88"
-    "0a ab 07 15 3d 01 f4 8d 08 6d f0 bf be c0 5e 7b"
-    "44 3b 97 e7 17 18 97 0e 2f 4b f6 20 23 e9 5b 67";
-
-// PKCS#1 v1.5 Signature Example 15.11
-
-char* message_11 =
-    "e5 73 9b 6c 14 c9 2d 51 0d 95 b8 26 93 33 37 ff "
-    "0d 24 ef 72 1a c4 ef 64 c2 ba d2 64 be 8b 44 ef "
-    "a1 51 6e 08 a2 7e b6 b6 11 d3 30 1d f0 06 2d ae "
-    "fc 73 a8 c0 d9 2e 2c 52 1f ac bc 7b 26 47 38 76 "
-    "7e a6 fc 97 d5 88 a0 ba f6 ce 50 ad f7 9e 60 0b "
-    "d2 9e 34 5f cb 1d ba 71 ac 5c 02 89 02 3f e4 a8 "
-    "2b 46 a5 40 77 19 19 7d 2e 95 8e 35 31 fd 54 ae "
-    "f9 03 aa bb 43 55 f8 83 18 99 4e d3 c3 dd 62 f4 "
-    "20 a7 ";
-
-char* signature_11 =
-    "be 40 a5 fb 94 f1 13 e1 b3 ef f6 b6 a3 39 86 f2"
-    "02 e3 63 f0 74 83 b7 92 e6 8d fa 55 54 df 04 66"
-    "cc 32 15 09 50 78 3b 4d 96 8b 63 9a 04 fd 2f b9"
-    "7f 6e b9 67 02 1f 5a dc cb 9f ca 95 ac c8 f2 cd"
-    "88 5a 38 0b 0a 4e 82 bc 76 07 64 db ab 88 c1 e6"
-    "c0 25 5c aa 94 f2 32 19 9d 6f 59 7c c9 14 5b 00"
-    "e3 d4 ba 34 6b 55 9a 88 33 ad 15 16 ad 51 63 f0"
-    "16 af 6a 59 83 1c 82 ea 13 c8 22 4d 84 d0 76 5a"
-    "9d 12 38 4d a4 60 a8 53 1b 4c 40 7e 04 f4 f3 50"
-    "70 9e b9 f0 8f 5b 22 0f fb 45 ab f6 b7 5d 15 79"
-    "fd 3f 1e b5 5f c7 5b 00 af 8b a3 b0 87 82 7f e9"
-    "ae 9f b4 f6 c5 fa 63 03 1f e5 82 85 2f e2 83 4f"
-    "9c 89 bf f5 3e 25 52 21 6b c7 c1 d4 a3 d5 dc 2b"
-    "a6 95 5c d9 b1 7d 13 63 e7 fe e8 ed 76 29 75 3f"
-    "f3 12 5e dd 48 52 1a e3 b9 b0 32 17 f4 49 6d 0d"
-    "8e de 57 ac bc 5b d4 de ae 74 a5 6f 86 67 1d e2";
-
-// PKCS#1 v1.5 Signature Example 15.12
-
-char* message_12 =
-    "7a f4 28 35 91 7a 88 d6 b3 c6 71 6b a2 f5 b0 d5 "
-    "b2 0b d4 e2 e6 e5 74 e0 6a f1 ee f7 c8 11 31 be "
-    "22 bf 81 28 b9 cb c6 ec 00 27 5b a8 02 94 a5 d1 "
-    "17 2d 08 24 a7 9e 8f dd 83 01 83 e4 c0 0b 96 78 "
-    "28 67 b1 22 7f ea 24 9a ad 32 ff c5 fe 00 7b c5 "
-    "1f 21 79 2f 72 8d ed a8 b5 70 8a a9 9c ab ab 20 "
-    "a4 aa 78 3e d8 6f 0f 27 b5 d5 63 f4 2e 07 15 8c "
-    "ea 72 d0 97 aa 68 87 ec 41 1d d0 12 91 2a 5e 03 "
-    "2b bf a6 78 50 71 44 bc c9 5f 39 b5 8b e7 bf d1 "
-    "75 9a db 9a 91 fa 1d 6d 82 26 a8 34 3a 8b 84 9d "
-    "ae 76 f7 b9 82 24 d5 9e 28 f7 81 f1 3e ce 60 5f "
-    "84 f6 c9 0b ae 5f 8c f3 78 81 6f 40 20 a7 dd a1 "
-    "be d9 0c 92 a2 36 34 d2 03 fa c3 fc d8 6d 68 d3 "
-    "18 2a 7d 9c ca be 7b 07 95 f5 c6 55 e9 ac c4 e3 "
-    "ec 18 51 40 d1 0c ef 05 34 64 ab 17 5c 83 bd 83 "
-    "93 5e 3d ab af 34 62 ee be 63 d1 5f 57 3d 26 9a ";
-
-char* signature_12 =
-    "4e 78 c5 90 2b 80 79 14 d1 2f a5 37 ae 68 71 c8"
-    "6d b8 02 1e 55 d1 ad b8 eb 0c cf 1b 8f 36 ab 7d"
-    "ad 1f 68 2e 94 7a 62 70 72 f0 3e 62 73 71 78 1d"
-    "33 22 1d 17 4a be 46 0d bd 88 56 0c 22 f6 90 11"
-    "6e 2f bb e6 e9 64 36 3a 3e 52 83 bb 5d 94 6e f1"
-    "c0 04 7e ba 03 8c 75 6c 40 be 79 23 05 58 09 b0"
-    "e9 f3 4a 03 a5 88 15 eb dd e7 67 93 1f 01 8f 6f"
-    "18 78 f2 ef 4f 47 dd 37 40 51 dd 48 68 5d ed 6e"
-    "fb 3e a8 02 1f 44 be 1d 7d 14 93 98 f9 8e a9 c0"
-    "8d 62 88 8e bb 56 19 2d 17 74 7b 6b 8e 17 09 54"
-    "31 f1 25 a8 a8 e9 96 2a a3 1c 28 52 64 e0 8f b2"
-    "1a ac 33 6c e6 c3 8a a3 75 e4 2b c9 2a b0 ab 91"
-    "03 84 31 e1 f9 2c 39 d2 af 5d ed 7e 43 bc 15 1e"
-    "6e be a4 c3 e2 58 3a f3 43 7e 82 c4 3c 5e 3b 5b"
-    "07 cf 03 59 68 3d 22 98 e3 59 48 ed 80 6c 06 3c"
-    "60 6e a1 78 15 0b 1e fc 15 85 69 34 c7 25 5c fe";
-
-// PKCS#1 v1.5 Signature Example 15.13
-
-char* message_13 =
-    "eb ae f3 f9 f2 3b df e5 fa 6b 8a f4 c2 08 c1 89 "
-    "f2 25 1b f3 2f 5f 13 7b 9d e4 40 63 78 68 6b 3f "
-    "07 21 f6 2d 24 cb 86 88 d6 fc 41 a2 7c ba e2 1d "
-    "30 e4 29 fe ac c7 11 19 41 c2 77 ";
-
-char* signature_13 =
-    "c4 8d be f5 07 11 4f 03 c9 5f af be b4 df 1b fa"
-    "88 e0 18 4a 33 cc 4f 8a 9a 10 35 ff 7f 82 2a 5e"
-    "38 cd a1 87 23 91 5f f0 78 24 44 29 e0 f6 08 1c"
-    "14 fd 83 33 1f a6 5c 6b a7 bb 9a 12 db f6 62 23"
-    "74 cd 0c a5 7d e3 77 4e 2b d7 ae 82 36 77 d0 61"
-    "d5 3a e9 c4 04 0d 2d a7 ef 70 14 f3 bb dc 95 a3"
-    "61 a4 38 55 c8 ce 9b 97 ec ab ce 17 4d 92 62 85"
-    "14 2b 53 4a 30 87 f9 f4 ef 74 51 1e c7 42 b0 d5"
-    "68 56 03 fa f4 03 b5 07 2b 98 5d f4 6a df 2d 25"
-    "29 a0 2d 40 71 1e 21 90 91 70 52 37 1b 79 b7 49"
-    "b8 3a bf 0a e2 94 86 c3 f2 f6 24 77 b2 bd 36 2b"
-    "03 9c 01 3c 0c 50 76 ef 52 0d bb 40 5f 42 ce e9"
-    "54 25 c3 73 a9 75 e1 cd d0 32 c4 96 22 c8 50 79"
-    "b0 9e 88 da b2 b1 39 69 ef 7a 72 39 73 78 10 40"
-    "45 9f 57 d5 01 36 38 48 3d e2 d9 1c b3 c4 90 da"
-    "81 c4 6d e6 cd 76 ea 8a 0c 8f 6f e3 31 71 2d 24";
-
-// PKCS#1 v1.5 Signature Example 15.14
-
-char* message_14 =
-    "c5 a2 71 12 78 76 1d fc dd 4f 0c 99 e6 f5 61 9d "
-    "6c 48 b5 d4 c1 a8 09 82 fa a6 b4 cf 1c f7 a6 0f "
-    "f3 27 ab ef 93 c8 01 42 9e fd e0 86 40 85 81 46 "
-    "10 56 ac c3 3f 3d 04 f5 ad a2 12 16 ca cd 5f d1 "
-    "f9 ed 83 20 3e 0e 2f e6 13 8e 3e ae 84 24 e5 91 "
-    "5a 08 3f 3f 7a b7 60 52 c8 be 55 ae 88 2d 6e c1 "
-    "48 2b 1e 45 c5 da e9 f4 10 15 40 53 27 02 2e c3 "
-    "2f 0e a2 42 97 63 b2 55 04 3b 19 58 ee 3c f6 d6 "
-    "39 83 59 6e b3 85 84 4f 85 28 cc 9a 98 65 83 5d "
-    "c5 11 3c 02 b8 0d 0f ca 68 aa 25 e7 2b ca ae b3 "
-    "cf 9d 79 d8 4f 98 4f d4 17 ";
-
-char* signature_14 =
-    "6b d5 25 7a a0 66 11 fb 46 60 08 7c b4 bc 4a 9e"
-    "44 91 59 d3 16 52 bd 98 08 44 da f3 b1 c7 b3 53"
-    "f8 e5 61 42 f7 ea 98 57 43 3b 18 57 3b 4d ee de"
-    "81 8a 93 b0 29 02 97 78 3f 1a 2f 23 cb c7 27 97"
-    "a6 72 53 7f 01 f6 24 84 cd 41 62 c3 21 4b 9a c6"
-    "28 22 4c 5d e0 1f 32 bb 9b 76 b2 73 54 f2 b1 51"
-    "d0 e8 c4 21 3e 46 15 ad 0b c7 1f 51 5e 30 0d 6a"
-    "64 c6 74 34 11 ff fd e8 e5 ff 19 0e 54 92 30 43"
-    "12 6e cf c4 c4 53 90 22 66 8f b6 75 f2 5c 07 e2"
-    "00 99 ee 31 5b 98 d6 af ec 4b 1a 9a 93 dc 33 49"
-    "6a 15 bd 6f de 16 63 a7 d4 9b 9f 1e 63 9d 38 66"
-    "4b 37 a0 10 b1 f3 5e 65 86 82 d9 cd 63 e5 7d e0"
-    "f1 5e 8b dd 09 65 58 f0 7e c0 ca a2 18 a8 c0 6f"
-    "47 88 45 39 40 28 7c 9d 34 b6 d4 0a 3f 09 bf 77"
-    "99 fe 98 ae 4e b4 9f 3f f4 1c 50 40 a5 0c ef c9"
-    "bd f2 39 4b 74 9c f1 64 48 0d f1 ab 68 80 27 3b";
-
-// PKCS#1 v1.5 Signature Example 15.15
-
-char* message_15 =
-    "9b f8 aa 25 3b 87 2e a7 7a 7e 23 47 6b e2 6b 23 "
-    "29 57 8c f6 ac 9e a2 80 5b 35 7f 6f c3 ad 13 0d "
-    "ba eb 3d 86 9a 13 cc e7 a8 08 bb bb c9 69 85 7e "
-    "03 94 5c 7b b6 1d f1 b5 c2 58 9b 8e 04 6c 2a 5d "
-    "7e 40 57 b1 a7 4f 24 c7 11 21 63 64 28 85 29 ec "
-    "95 70 f2 51 97 21 3b e1 f5 c2 e5 96 f8 bf 8b 2c "
-    "f3 cb 38 aa 56 ff e5 e3 1d f7 39 58 20 e9 4e cf "
-    "3b 11 89 a9 65 dc f9 a9 cb 42 98 d3 c8 8b 29 23 "
-    "c1 9f c6 bc 34 aa ce ca d4 e0 93 1a 7c 4e 5d 73 "
-    "dc 86 df a7 98 a8 47 6d 82 46 3e ef aa 90 a8 a9 "
-    "19 2a b0 8b 23 08 8d d5 8e 12 80 f7 d7 2e 45 48 "
-    "39 6b aa c1 12 25 2d d5 c5 34 6a db 20 04 a2 f7 "
-    "10 1c cc 89 9c c7 fa fa e8 bb e2 95 73 88 96 a5 "
-    "b2 01 22 85 01 4e f6 ";
-
-char* signature_15 =
-    "27 f7 f4 da 9b d6 10 10 6e f5 7d 32 38 3a 44 8a"
-    "8a 62 45 c8 3d c1 30 9c 6d 77 0d 35 7b a8 9e 73"
-    "f2 ad 08 32 06 2e b0 fe 0a c9 15 57 5b cd 6b 8b"
-    "ca db 4e 2b a6 fa 9d a7 3a 59 17 51 52 b2 d4 fe"
-    "72 b0 70 c9 b7 37 9e 50 00 0e 55 e6 c2 69 f6 65"
-    "8c 93 79 72 79 7d 3a dd 69 f1 30 e3 4b 85 bd ec"
-    "9f 3a 9b 39 22 02 d6 f3 e4 30 d0 9c ac a8 22 77"
-    "59 ab 82 5f 70 12 d2 ff 4b 5b 62 c8 50 4d ba d8"
-    "55 c0 5e dd 5c ab 5a 4c cc dc 67 f0 1d d6 51 7c"
-    "7d 41 c4 3e 2a 49 57 af f1 9d b6 f1 8b 17 85 9a"
-    "f0 bc 84 ab 67 14 6e c1 a4 a6 0a 17 d7 e0 5f 8b"
-    "4f 9c ed 6a d1 09 08 d8 d7 8f 7f c8 8b 76 ad c8"
-    "29 0f 87 da f2 a7 be 10 ae 40 85 21 39 5d 54 ed"
-    "25 56 fb 76 61 85 4a 73 0c e3 d8 2c 71 a8 d4 93"
-    "ec 49 a3 78 ac 8a 3c 74 43 9f 7c c5 55 ba 13 f8"
-    "59 07 08 90 ee 18 ff 65 8f a4 d7 41 96 9d 70 a5";
-
-// PKCS#1 v1.5 Signature Example 15.16
-
-char* message_16 =
-    "32 47 48 30 e2 20 37 54 c8 bf 06 81 dc 4f 84 2a "
-    "fe 36 09 30 37 86 16 c1 08 e8 33 65 6e 56 40 c8 "
-    "68 56 88 5b b0 5d 1e b9 43 8e fe de 67 92 63 de "
-    "07 cb 39 55 3f 6a 25 e0 06 b0 a5 23 11 a0 63 ca "
-    "08 82 66 d2 56 4f f6 49 0c 46 b5 60 98 18 54 8f "
-    "88 76 4d ad 34 a2 5e 3a 85 d5 75 02 3f 0b 9e 66 "
-    "50 48 a0 3c 35 05 79 a9 d3 24 46 c7 bb 96 cc 92 "
-    "e0 65 ab 94 d3 c8 95 2e 8d f6 8e f0 d9 fa 45 6b "
-    "3a 06 bb 80 e3 bb c4 b2 8e 6a 94 b6 d0 ff 76 96 "
-    "a6 4e fe 05 e7 35 fe a0 25 d7 bd bc 41 39 f3 a3 "
-    "b5 46 07 5c ba 7e fa 94 73 74 d3 f0 ac 80 a6 8d "
-    "76 5f 5d f6 21 0b ca 06 9a 2d 88 64 7a f7 ea 04 "
-    "2d ac 69 0c b5 73 78 ec 07 77 61 4f b8 b6 5f f4 "
-    "53 ca 6b 7d ce 60 98 45 1a 2f 8c 0d a9 bf ec f1 "
-    "fd f3 91 bb aa 4e 2a 91 ca 18 a1 12 1a 75 23 a2 "
-    "ab d4 25 14 f4 89 e8 ";
-
-char* signature_16 =
-    "69 17 43 72 57 c2 2c cb 54 03 29 0c 3d ee 82 d9"
-    "cf 75 50 b3 1b d3 1c 51 bd 57 bf d3 5d 45 2a b4"
-    "db 7c 4b e6 b2 e2 5a c9 a5 9a 1d 2a 7f eb 62 7f"
-    "0a fd 49 76 b3 00 3c c9 cf fd 88 96 50 5e c3 82"
-    "f2 65 10 4d 4c f8 c9 32 fa 9f e8 6e 00 87 07 95"
-    "99 12 38 9d a4 b2 d6 b3 69 b3 6a 5e 72 e2 9d 24"
-    "c9 a9 8c 9d 31 a3 ab 44 e6 43 e6 94 12 66 a4 7a"
-    "45 e3 44 6c e8 77 6a be 24 1a 8f 5f c6 42 3b 24"
-    "b1 ff 25 0d c2 c3 a8 17 23 53 56 10 77 e8 50 a7"
-    "69 b2 5f 03 25 da c8 89 65 a3 b9 b4 72 c4 94 e9"
-    "5f 71 9b 4e ac 33 2c aa 7a 65 c7 df e4 6d 9a a7"
-    "e6 e0 0f 52 5f 30 3d d6 3a b7 91 92 18 90 18 68"
-    "f9 33 7f 8c d2 6a af e6 f3 3b 7f b2 c9 88 10 af"
-    "19 f7 fc b2 82 ba 15 77 91 2c 1d 36 89 75 fd 5d"
-    "44 0b 86 e1 0c 19 97 15 fa 0b 6f 42 50 b5 33 73"
-    "2d 0b ef e1 54 51 50 fc 47 b8 76 de 09 b0 0a 94";
-
-// PKCS#1 v1.5 Signature Example 15.17
-
-char* message_17 =
-    "00 8e 59 50 5e af b5 50 aa e5 e8 45 58 4c eb b0 "
-    "0b 6d e1 73 3e 9f 95 d4 2c 88 2a 5b be b5 ce 1c "
-    "57 e1 19 e7 c0 d4 da ca 9f 1f f7 87 02 17 f7 cf "
-    "d8 a6 b3 73 97 7c ac 9c ab 8e 71 e4 20 ";
-
-char* signature_17 =
-    "92 25 03 b6 73 ee 5f 3e 69 1e 1c a8 5e 9f f4 17"
-    "3c f7 2b 05 ac 2c 13 1d a5 60 35 93 e3 bc 25 9c"
-    "94 c1 f7 d3 a0 6a 5b 98 91 bf 11 3f a3 9e 59 ff"
-    "7c 1e d6 46 5e 90 80 49 cb 89 e4 e1 25 cd 37 d2"
-    "ff d9 22 7a 41 b4 a0 a1 9c 0a 44 fb bf 3d e5 5b"
-    "ab 80 20 87 a3 bb 8d 4f f6 68 ee 6b bb 8a d8 9e"
-    "68 57 a7 9a 9c 72 78 19 90 df cf 92 cd 51 94 04"
-    "c9 50 f1 3d 11 43 c3 18 4f 1d 25 0c 90 e1 7a c6"
-    "ce 36 16 3b 98 95 62 7a d6 ff ec 14 22 44 1f 55"
-    "e4 49 9d ba 9b e8 95 46 ae 8b c6 3c ca 01 dd 08"
-    "46 3a e7 f1 fc e3 d8 93 99 69 38 77 8c 18 12 e6"
-    "74 ad 9c 30 9c 5a cc a3 fd e4 4e 7d d8 69 59 93"
-    "e9 c1 fa 87 ac da 99 ec e5 c8 49 9e 46 89 57 ad"
-    "66 35 9b f1 2a 51 ad be 78 d3 a2 13 b4 49 bf 0b"
-    "5f 8d 4d 49 6a cf 03 d3 03 3b 7c cd 19 6b c2 2f"
-    "68 fb 7b ef 4f 69 7c 5e a2 b3 50 62 f4 8a 36 dd";
-
-// PKCS#1 v1.5 Signature Example 15.18
-
-char* message_18 =
-    "6a bc 54 cf 8d 1d ff 1f 53 b1 7d 81 60 36 88 78 "
-    "a8 78 8c c6 d2 2f a5 c2 25 8c 88 e6 60 b0 9a 89 "
-    "33 f9 f2 c0 50 4d da dc 21 f6 e7 5e 0b 83 3b eb "
-    "55 52 29 de e6 56 b9 04 7b 92 f6 2e 76 b8 ff cc "
-    "60 da b0 6b 80 ";
-
-char* signature_18 =
-    "0b 6d af 42 f7 a8 62 14 7e 41 74 93 c2 c4 01 ef"
-    "ae 32 63 6a b4 cb d4 41 92 bb f5 f1 95 b5 0a e0"
-    "96 a4 75 a1 61 4f 0a 9f a8 f7 a0 26 cb 46 c6 50"
-    "6e 51 8e 33 d8 3e 56 47 7a 87 5a ca 8c 7e 71 4c"
-    "e1 bd bd 61 ef 5d 53 52 39 b3 3f 2b fd d6 17 71"
-    "ba b6 27 76 d7 81 71 a1 42 3c ea 87 31 f8 2e 60"
-    "76 6d 64 54 26 56 20 b1 5f 5c 5a 58 4f 55 f9 5b"
-    "80 2f e7 8c 57 4e d5 da cf c8 31 f3 cf 2b 05 02"
-    "c0 b2 98 f2 5c cf 11 f9 73 b3 1f 85 e4 74 42 19"
-    "85 f3 cf f7 02 df 39 46 ef 0a 66 05 68 21 11 b2"
-    "f5 5b 1f 8a b0 d2 ea 3a 68 3c 69 98 5e ad 93 ed"
-    "44 9e a4 8f 03 58 dd f7 08 02 cb 41 de 2f d8 3f"
-    "3c 80 80 82 d8 49 36 94 8e 0c 84 a1 31 b4 92 78"
-    "27 46 05 27 bb 5c d2 4b fa b7 b4 8e 07 1b 24 17"
-    "19 30 f9 97 63 27 2f 97 97 bc b7 6f 1d 24 81 57"
-    "55 58 fc f2 60 b1 f0 e5 54 eb b3 df 3c fc b9 58";
-
-// PKCS#1 v1.5 Signature Example 15.19
-
-char* message_19 =
-    "af 2d 78 15 2c f1 0e fe 01 d2 74 f2 17 b1 77 f6 "
-    "b0 1b 5e 74 9f 15 67 71 5d a3 24 85 9c d3 dd 88 "
-    "db 84 8e c7 9f 48 db ba 7b 6f 1d 33 11 1e f3 1b "
-    "64 89 9e 73 91 c2 bf fd 69 f4 90 25 cf 20 1f c5 "
-    "85 db d1 54 2c 1c 77 8a 2c e7 a7 ee 10 8a 30 9f "
-    "ec a2 6d 13 3a 5f fe dc 4e 86 9d cd 76 56 59 6a "
-    "c8 42 7e a3 ef 6e 3f d7 8f e9 9d 8d dc 71 d8 39 "
-    "f6 78 6e 0d a6 e7 86 bd 62 b3 a4 f1 9b 89 1a 56 "
-    "15 7a 55 4e c2 a2 b3 9e 25 a1 d7 c7 d3 73 21 c7 "
-    "a1 d9 46 cf 4f be 75 8d 92 76 f0 85 63 44 9d 67 "
-    "41 4a 2c 03 0f 42 51 cf e2 21 3d 04 a5 41 06 37 "
-    "87 ";
-
-char* signature_19 =
-    "20 9c 61 15 78 57 38 7b 71 e2 4b f3 dd 56 41 45"
-    "50 50 3b ec 18 0f f5 3b dd 9b ac 06 2a 2d 49 95"
-    "09 bf 99 12 81 b7 95 27 df 91 36 61 5b 7a 6d 9d"
-    "b3 a1 03 b5 35 e0 20 2a 2c ac a1 97 a7 b7 4e 53"
-    "56 f3 dd 59 5b 49 ac fd 9d 30 04 9a 98 ca 88 f6"
-    "25 bc a1 d5 f2 2a 39 2d 8a 74 9e fb 6e ed 9b 78"
-    "21 d3 11 0a c0 d2 44 19 9e cb 4a a3 d7 35 a8 3a"
-    "2e 88 93 c6 bf 85 81 38 3c ca ee 83 46 35 b7 fa"
-    "1f af fa 45 b1 3d 15 c1 da 33 af 71 e8 93 03 d6"
-    "80 90 ff 62 ee 61 5f df 5a 84 d1 20 71 1d a5 3c"
-    "28 89 19 8a b3 83 17 a9 73 4a b2 7d 67 92 4c ea"
-    "74 15 6f f9 9b ef 98 76 bb 5c 33 9e 93 74 52 83"
-    "e1 b3 4e 07 22 26 b8 80 45 e0 17 e9 f0 5b 2a 8c"
-    "41 67 40 25 8e 22 3b 26 90 02 74 91 73 22 73 f3"
-    "22 9d 9e f2 b1 b3 80 7e 32 10 18 92 0a d3 e5 3d"
-    "ae 47 e6 d9 39 5c 18 4b 93 a3 74 c6 71 fa a2 ce";
-
-// PKCS#1 v1.5 Signature Example 15.20
-
-char* message_20 =
-    "40 ee 99 24 58 d6 f6 14 86 d2 56 76 a9 6d d2 cb "
-    "93 a3 7f 04 b1 78 48 2f 2b 18 6c f8 82 15 27 0d "
-    "ba 29 d7 86 d7 74 b0 c5 e7 8c 7f 6e 56 a9 56 e7 "
-    "f7 39 50 a2 b0 c0 c1 0a 08 db cd 67 e5 b2 10 bb "
-    "21 c5 8e 27 67 d4 4f 7d d4 01 4e 39 66 14 3b f7 "
-    "e3 d6 6f f0 c0 9b e4 c5 5f 93 b3 99 94 b8 51 8d "
-    "9c 1d 76 d5 b4 73 74 de a0 8f 15 7d 57 d7 06 34 "
-    "97 8f 38 56 e0 e5 b4 81 af bb db 5a 3a c4 8d 48 "
-    "4b e9 2c 93 de 22 91 78 35 4c 2d e5 26 e9 c6 5a "
-    "31 ed e1 ef 68 cb 63 98 d7 91 16 84 fe c0 ba bc "
-    "3a 78 1a 66 66 07 83 50 69 74 d0 e1 48 25 10 1c "
-    "3b fa ea ";
-
-char* signature_20 =
-    "92 75 02 b8 24 af c4 25 13 ca 65 70 de 33 8b 8a"
-    "64 c3 a8 5e b8 28 d3 19 36 24 f2 7e 8b 10 29 c5"
-    "5c 11 9c 97 33 b1 8f 58 49 b3 50 09 18 bc c0 05"
-    "51 d9 a8 fd f5 3a 97 74 9f a8 dc 48 0d 6f e9 74"
-    "2a 58 71 f9 73 92 65 28 97 2a 1a f4 9e 39 25 b0"
-    "ad f1 4a 84 27 19 b4 a5 a2 d8 9f a9 c0 b6 60 5d"
-    "21 2b ed 1e 67 23 b9 34 06 ad 30 e8 68 29 a5 c7"
-    "19 b8 90 b3 89 30 6d c5 50 64 86 ee 2f 36 a8 df"
-    "e0 a9 6a f6 78 c9 cb d6 af f3 97 ca 20 0e 3e dc"
-    "1e 36 bd 2f 08 b3 1d 54 0c 0c b2 82 a9 55 9e 4a"
-    "dd 4f c9 e6 49 2e ed 0c cb d3 a6 98 2e 5f aa 2d"
-    "dd 17 be 47 41 7c 80 b4 e5 45 2d 31 f7 24 01 a0"
-    "42 32 51 09 54 4d 95 4c 01 93 90 79 d4 09 a5 c3"
-    "78 d7 51 2d fc 2d 2a 71 ef cc 34 32 a7 65 d1 c6"
-    "a5 2c fc e8 99 cd 79 b1 5b 4f c3 72 36 41 ef 6b"
-    "d0 0a cc 10 40 7e 5d f5 8d d1 c3 c5 c5 59 a5 06";
-
-
-unsigned char* parsehex(char* str, int* len) {
-    // result can't be longer than input
-    unsigned char* result = malloc(strlen(str));
-
-    unsigned char* p = result;
-    *len = 0;
-
-    while (*str) {
-        int b;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b = (*str - '0') << 4; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b = (*str - 'a' + 10) << 4; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b = (*str - 'A' + 10) << 4; break;
-            case '\0':
-                return result;
-            default:
-                return NULL;
-        }
-        str++;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b |= *str - '0'; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b |= *str - 'a' + 10; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b |= *str - 'A' + 10; break;
-            default:
-                return NULL;
-        }
-        str++;
-
-        *p++ = b;
-        ++*len;
-    }
-
-    return result;
-}
-
-
-int main(int arg __unused, char** argv __unused) {
-
-    unsigned char hash[SHA_DIGEST_SIZE];
-
-    unsigned char* message;
-    int mlen;
-    unsigned char* signature;
-    int slen;
-
-#define TEST_MESSAGE(n) do {\
-    message = parsehex(message_##n, &mlen); \
-    SHA_hash(message, mlen, hash); \
-    signature = parsehex(signature_##n, &slen); \
-    int result = RSA_verify(&key_15, signature, slen, hash, sizeof(hash)); \
-    printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
-    success = success && result; \
-    } while(0)
-
-    int success = 1;
-
-    TEST_MESSAGE(1);
-    TEST_MESSAGE(2);
-    TEST_MESSAGE(3);
-    TEST_MESSAGE(4);
-    TEST_MESSAGE(5);
-    TEST_MESSAGE(6);
-    TEST_MESSAGE(7);
-    TEST_MESSAGE(8);
-    TEST_MESSAGE(9);
-    TEST_MESSAGE(10);
-    TEST_MESSAGE(11);
-    TEST_MESSAGE(12);
-    TEST_MESSAGE(13);
-    TEST_MESSAGE(14);
-    TEST_MESSAGE(15);
-    TEST_MESSAGE(16);
-    TEST_MESSAGE(17);
-    TEST_MESSAGE(18);
-    TEST_MESSAGE(19);
-    TEST_MESSAGE(20);
-
-    printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
-    return !success;
-}
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
index 6c064c7..632c6c8 100644
--- a/libnativeloader/Android.mk
+++ b/libnativeloader/Android.mk
@@ -1,19 +1,21 @@
 LOCAL_PATH:= $(call my-dir)
 
-NATIVE_LOADER_COMMON_SRC_FILES := \
+native_loader_common_src_files := \
   native_loader.cpp
 
+native_loader_common_cflags := -Werror -Wall
+
 # Shared library for target
 # ========================================================
 include $(CLEAR_VARS)
 
 LOCAL_MODULE:= libnativeloader
 
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
 LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
 LOCAL_STATIC_LIBRARIES := libbase
 LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
@@ -27,11 +29,11 @@
 
 LOCAL_MODULE:= libnativeloader
 
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
 LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
 LOCAL_STATIC_LIBRARIES := libbase
 LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
@@ -45,10 +47,10 @@
 
 LOCAL_MODULE:= libnativeloader
 
-LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SRC_FILES:= $(native_loader_common_src_files)
 LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
 LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := $(native_loader_common_cflags)
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
diff --git a/libnativeloader/dlext_namespaces.h b/libnativeloader/dlext_namespaces.h
new file mode 100644
index 0000000..ca9e619
--- /dev/null
+++ b/libnativeloader/dlext_namespaces.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_DLEXT_NAMESPACES_H__
+#define __ANDROID_DLEXT_NAMESPACES_H__
+
+#include <android/dlext.h>
+
+__BEGIN_DECLS
+
+/*
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
+ * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
+ */
+extern bool android_init_namespaces(const char* public_ns_sonames,
+                                    const char* anon_ns_library_path);
+
+
+enum {
+  /* A regular namespace is the namespace with a custom search path that does
+   * not impose any restrictions on the location of native libraries.
+   */
+  ANDROID_NAMESPACE_TYPE_REGULAR = 0,
+
+  /* An isolated namespace requires all the libraries to be on the search path
+   * or under permitted_when_isolated_path. The search path is the union of
+   * ld_library_path and default_library_path.
+   */
+  ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+
+  /* The shared namespace clones the list of libraries of the caller namespace upon creation
+   * which means that they are shared between namespaces - the caller namespace and the new one
+   * will use the same copy of a library if it was loaded prior to android_create_namespace call.
+   *
+   * Note that libraries loaded after the namespace is created will not be shared.
+   *
+   * Shared namespaces can be isolated or regular. Note that they do not inherit the search path nor
+   * permitted_path from the caller's namespace.
+   */
+  ANDROID_NAMESPACE_TYPE_SHARED = 2,
+  ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
+                                           ANDROID_NAMESPACE_TYPE_ISOLATED,
+};
+
+/*
+ * Creates new linker namespace.
+ * ld_library_path and default_library_path represent the search path
+ * for the libraries in the namespace.
+ *
+ * The libraries in the namespace are searched by folowing order:
+ * 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+ * 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+ * 3. deault_library_path (This of this as namespace-local default library path)
+ *
+ * When type is ANDROID_NAMESPACE_TYPE_ISOLATED the resulting namespace requires all of
+ * the libraries to be on the search path or under the permitted_when_isolated_path;
+ * the search_path is ld_library_path:default_library_path. Note that the
+ * permitted_when_isolated_path path is not part of the search_path and
+ * does not affect the search order. It is a way to allow loading libraries from specific
+ * locations when using absolute path.
+ * If a library or any of its dependencies are outside of the permitted_when_isolated_path
+ * and search_path, and it is not part of the public namespace dlopen will fail.
+ */
+extern struct android_namespace_t* android_create_namespace(const char* name,
+                                                            const char* ld_library_path,
+                                                            const char* default_library_path,
+                                                            uint64_t type,
+                                                            const char* permitted_when_isolated_path);
+
+__END_DECLS
+
+#endif /* __ANDROID_DLEXT_NAMESPACES_H__ */
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 1bd3b8f..2a6aaec 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -43,6 +43,9 @@
                         jobject class_loader,
                         jstring library_path);
 
+__attribute__((visibility("default")))
+bool CloseNativeLibrary(void* handle);
+
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
 // there is no namespace associated with the class_loader.
@@ -50,6 +53,9 @@
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
 #endif
 
+__attribute__((visibility("default")))
+void ResetNativeLoader();
+
 };  // namespace android
 
 #endif  // NATIVE_BRIDGE_H_
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 899c98c..927cbec 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -19,7 +19,7 @@
 
 #include <dlfcn.h>
 #ifdef __ANDROID__
-#include <android/dlext.h>
+#include "dlext_namespaces.h"
 #include "cutils/properties.h"
 #include "log/log.h"
 #endif
@@ -36,7 +36,19 @@
 namespace android {
 
 #if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesConfig = "/system/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+
+// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
+// System.load() with an absolute path which is outside of the classloader library search path.
+// This list includes all directories app is allowed to access this way.
+static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+
+static bool is_debuggable() {
+  char debuggable[PROP_VALUE_MAX];
+  property_get("ro.debuggable", debuggable, "0");
+  return std::string(debuggable) == "1";
+}
 
 class LibraryNamespaces {
  public:
@@ -47,12 +59,26 @@
                               bool is_shared,
                               jstring java_library_path,
                               jstring java_permitted_path) {
-    ScopedUtfChars library_path(env, java_library_path);
+    std::string library_path; // empty string by default.
 
-    std::string permitted_path;
+    if (java_library_path != nullptr) {
+      ScopedUtfChars library_path_utf_chars(env, java_library_path);
+      library_path = library_path_utf_chars.c_str();
+    }
+
+    // (http://b/27588281) This is a workaround for apps using custom
+    // classloaders and calling System.load() with an absolute path which
+    // is outside of the classloader library search path.
+    //
+    // This part effectively allows such a classloader to access anything
+    // under /data and /mnt/expand
+    std::string permitted_path = kWhitelistedDirectories;
+
     if (java_permitted_path != nullptr) {
       ScopedUtfChars path(env, java_permitted_path);
-      permitted_path = path.c_str();
+      if (path.c_str() != nullptr && path.size() > 0) {
+        permitted_path = permitted_path + ":" + path.c_str();
+      }
     }
 
     if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
@@ -93,15 +119,66 @@
   }
 
   void Initialize() {
-    // Read list of public native libraries from the config file.
-    std::string file_content;
-    LOG_ALWAYS_FATAL_IF(!base::ReadFileToString(kPublicNativeLibrariesConfig, &file_content),
-                        "Error reading public native library list from \"%s\": %s",
-                        kPublicNativeLibrariesConfig, strerror(errno));
-
-    std::vector<std::string> lines = base::Split(file_content, "\n");
+    // Once public namespace is initialized there is no
+    // point in running this code - it will have no effect
+    // on the current list of public libraries.
+    if (initialized_) {
+      return;
+    }
 
     std::vector<std::string> sonames;
+    const char* android_root_env = getenv("ANDROID_ROOT");
+    std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
+    std::string public_native_libraries_system_config =
+            root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
+
+    LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
+                        "Error reading public native library list from \"%s\": %s",
+                        public_native_libraries_system_config.c_str(), strerror(errno));
+
+    // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+    // variable to add libraries to the list. This is intended for platform tests only.
+    if (is_debuggable()) {
+      const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+      if (additional_libs != nullptr && additional_libs[0] != '\0') {
+        std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+        std::copy(additional_libs_vector.begin(),
+                  additional_libs_vector.end(),
+                  std::back_inserter(sonames));
+      }
+    }
+
+    // This file is optional, quietly ignore if the file does not exist.
+    ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
+
+    // android_init_namespaces() expects all the public libraries
+    // to be loaded so that they can be found by soname alone.
+    //
+    // TODO(dimitry): this is a bit misleading since we do not know
+    // if the vendor public library is going to be opened from /vendor/lib
+    // we might as well end up loading them from /system/lib
+    // For now we rely on CTS test to catch things like this but
+    // it should probably be addressed in the future.
+    for (const auto& soname : sonames) {
+      dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
+    }
+
+    public_libraries_ = base::Join(sonames, ':');
+  }
+
+  void Reset() {
+    namespaces_.clear();
+  }
+
+ private:
+  bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames) {
+    // Read list of public native libraries from the config file.
+    std::string file_content;
+    if(!base::ReadFileToString(configFile, &file_content)) {
+      return false;
+    }
+
+    std::vector<std::string> lines = base::Split(file_content, "\n");
 
     for (const auto& line : lines) {
       auto trimmed_line = base::Trim(line);
@@ -109,19 +186,12 @@
         continue;
       }
 
-      sonames.push_back(trimmed_line);
+      sonames->push_back(trimmed_line);
     }
 
-    public_libraries_ = base::Join(sonames, ':');
-
-    // android_init_namespaces() expects all the public libraries
-    // to be loaded so that they can be found by soname alone.
-    for (const auto& soname : sonames) {
-      dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
-    }
+    return true;
   }
 
- private:
   bool InitPublicNamespace(const char* library_path) {
     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
     // code is one example) unknown to linker in which  case linker uses anonymous
@@ -142,10 +212,6 @@
 
 static std::mutex g_namespaces_mutex;
 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
-
-static bool namespaces_enabled(uint32_t target_sdk_version) {
-  return target_sdk_version > 0;
-}
 #endif
 
 void InitializeNativeLoader() {
@@ -155,6 +221,12 @@
 #endif
 }
 
+void ResetNativeLoader() {
+#if defined(__ANDROID__)
+  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
+  g_namespaces->Reset();
+#endif
+}
 
 jstring CreateClassLoaderNamespace(JNIEnv* env,
                                    int32_t target_sdk_version,
@@ -163,10 +235,7 @@
                                    jstring library_path,
                                    jstring permitted_path) {
 #if defined(__ANDROID__)
-  if (!namespaces_enabled(target_sdk_version)) {
-    return nullptr;
-  }
-
+  UNUSED(target_sdk_version);
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
   android_namespace_t* ns = g_namespaces->Create(env,
                                                  class_loader,
@@ -189,7 +258,8 @@
                         jobject class_loader,
                         jstring library_path) {
 #if defined(__ANDROID__)
-  if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) {
+  UNUSED(target_sdk_version);
+  if (class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
@@ -216,6 +286,10 @@
 #endif
 }
 
+bool CloseNativeLibrary(void* handle) {
+  return dlclose(handle) == 0;
+}
+
 #if defined(__ANDROID__)
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index a718b02..f48e1d0 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -965,7 +965,7 @@
  * Use only for one-to-one texture mapping.
  */
 struct horz_iterator32 {
-    horz_iterator32(context_t* c) {
+    explicit horz_iterator32(context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         texture_t& tx = c->state.texture[0];
@@ -982,7 +982,7 @@
 
 /* A variant for 16-bit source textures. */
 struct horz_iterator16 {
-    horz_iterator16(context_t* c) {
+    explicit horz_iterator16(context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         texture_t& tx = c->state.texture[0];
@@ -1002,7 +1002,7 @@
  * texture pixel value.
  */
 struct clamp_iterator {
-    clamp_iterator(context_t* c) {
+    explicit clamp_iterator(context_t* c) {
         const int xs = c->iterators.xl;
         texture_t& tx = c->state.texture[0];
         texture_iterators_t& ti = tx.iterators;
@@ -1112,13 +1112,13 @@
 }
 
 struct horz_clamp_iterator16 : horz_clamp_iterator {
-    horz_clamp_iterator16(const context_t* c) {
+    explicit horz_clamp_iterator16(const context_t* c) {
         init(c,1);
     };
 };
 
 struct horz_clamp_iterator32 : horz_clamp_iterator {
-    horz_clamp_iterator32(context_t* c) {
+    explicit horz_clamp_iterator32(context_t* c) {
         init(c,2);
     };
 };
@@ -1126,7 +1126,7 @@
 /* This is used to perform dithering operations.
  */
 struct ditherer {
-    ditherer(const context_t* c) {
+    explicit ditherer(const context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
@@ -1172,7 +1172,7 @@
  *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
  */
 struct blender_32to16 {
-    blender_32to16(context_t* /*c*/) { }
+    explicit blender_32to16(context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (s == 0)
             return;
@@ -1229,7 +1229,7 @@
  * where dstFactor=srcA*(1-srcA) srcFactor=srcA
  */
 struct blender_32to16_srcA {
-    blender_32to16_srcA(const context_t* /*c*/) { }
+    explicit blender_32to16_srcA(const context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (!s) {
             return;
@@ -1271,7 +1271,7 @@
 /* This blender does a normal blend after modulation.
  */
 struct blender_32to16_modulate : blender_modulate {
-    blender_32to16_modulate(const context_t* c) {
+    explicit blender_32to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint32_t s, uint16_t* dst) {
@@ -1343,7 +1343,7 @@
 
 /* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
 struct blender_x32to16_modulate : blender_modulate {
-    blender_x32to16_modulate(const context_t* c) {
+    explicit blender_x32to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint32_t s, uint16_t* dst) {
@@ -1398,7 +1398,7 @@
 
 /* Same as above, but source is 16bit rgb565 */
 struct blender_16to16_modulate : blender_modulate {
-    blender_16to16_modulate(const context_t* c) {
+    explicit blender_16to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint16_t s16, uint16_t* dst) {
@@ -1434,7 +1434,7 @@
  *   }
  */
 struct dst_iterator16 {
-    dst_iterator16(const context_t* c) {
+    explicit dst_iterator16(const context_t* c) {
         const int x = c->iterators.xl;
         const int width = c->iterators.xr - x;
         const int32_t y = c->iterators.y;
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
index cca8dc4..c2d2d27 100644
--- a/libprocessgroup/cleanup.cpp
+++ b/libprocessgroup/cleanup.cpp
@@ -15,7 +15,6 @@
  */
 #include <string.h>
 #include <unistd.h>
-#include <sys/syslimits.h>
 
 #include "processgroup_priv.h"
 
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ea1e4db..22162fa 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -71,7 +71,7 @@
 
 #if !DEBUG_REFS
 
-    weakref_impl(RefBase* base)
+    explicit weakref_impl(RefBase* base)
         : mStrong(INITIAL_STRONG_VALUE)
         , mWeak(0)
         , mBase(base)
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 1fca2b2..965e32c 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,18 +19,13 @@
  * System clock functions.
  */
 
-#if defined(__ANDROID__)
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
 #include <sys/time.h>
 #include <limits.h>
 #include <fcntl.h>
 #include <string.h>
+#include <errno.h>
 
+#include <cutils/compiler.h>
 #include <utils/SystemClock.h>
 #include <utils/Timers.h>
 
@@ -56,100 +51,21 @@
 	return nanoseconds_to_milliseconds(elapsedRealtimeNano());
 }
 
-#define METHOD_CLOCK_GETTIME    0
-#define METHOD_IOCTL            1
-#define METHOD_SYSTEMTIME       2
-
-/*
- * To debug/verify the timestamps returned by the kernel, change
- * DEBUG_TIMESTAMP to 1 and call the timestamp routine from a single thread
- * in the test program. b/10899829
- */
-#define DEBUG_TIMESTAMP         0
-
-#if DEBUG_TIMESTAMP && defined(__arm__)
-static inline void checkTimeStamps(int64_t timestamp,
-                                   int64_t volatile *prevTimestampPtr,
-                                   int volatile *prevMethodPtr,
-                                   int curMethod)
-{
-    /*
-     * Disable the check for SDK since the prebuilt toolchain doesn't contain
-     * gettid, and int64_t is different on the ARM platform
-     * (ie long vs long long).
-     */
-    int64_t prevTimestamp = *prevTimestampPtr;
-    int prevMethod = *prevMethodPtr;
-
-    if (timestamp < prevTimestamp) {
-        static const char *gettime_method_names[] = {
-            "clock_gettime",
-            "ioctl",
-            "systemTime",
-        };
-
-        ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
-              prevTimestamp, gettime_method_names[prevMethod],
-              timestamp, gettime_method_names[curMethod],
-              gettid());
-    }
-    // NOTE - not atomic and may generate spurious warnings if the 64-bit
-    // write is interrupted or not observed as a whole.
-    *prevTimestampPtr = timestamp;
-    *prevMethodPtr = curMethod;
-}
-#else
-#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
-#endif
-
 /*
  * native public static long elapsedRealtimeNano();
  */
 int64_t elapsedRealtimeNano()
 {
-#if defined(__ANDROID__)
+#if defined(__linux__)
     struct timespec ts;
-    int result;
-    int64_t timestamp;
-#if DEBUG_TIMESTAMP
-    static volatile int64_t prevTimestamp;
-    static volatile int prevMethod;
-#endif
-
-    static int s_fd = -1;
-
-    if (s_fd == -1) {
-        int fd = open("/dev/alarm", O_RDONLY);
-        if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
-            close(fd);
-        }
+    int err = clock_gettime(CLOCK_BOOTTIME, &ts);
+    if (CC_UNLIKELY(err)) {
+        // This should never happen, but just in case ...
+        ALOGE("clock_gettime(CLOCK_BOOTTIME) failed: %s", strerror(errno));
+        return 0;
     }
 
-    result = ioctl(s_fd,
-            ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
-
-    if (result == 0) {
-        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
-        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
-        return timestamp;
-    }
-
-    // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
-    result = clock_gettime(CLOCK_BOOTTIME, &ts);
-    if (result == 0) {
-        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
-        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
-                        METHOD_CLOCK_GETTIME);
-        return timestamp;
-    }
-
-    // XXX: there was an error, probably because the driver didn't
-    // exist ... this should return
-    // a real error, like an exception!
-    timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
-                    METHOD_SYSTEMTIME);
-    return timestamp;
+    return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
 #else
     return systemTime(SYSTEM_TIME_MONOTONIC);
 #endif
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index 8f07f1a..21fe19c 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -28,6 +28,7 @@
     LruCache_test.cpp \
     String8_test.cpp \
     StrongPointer_test.cpp \
+    SystemClock_test.cpp \
     Unicode_test.cpp \
     Vector_test.cpp \
 
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/tests/SystemClock_test.cpp
new file mode 100644
index 0000000..5ad060b
--- /dev/null
+++ b/libutils/tests/SystemClock_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+static const auto MS_IN_NS = 1000000;
+
+static const int64_t SLEEP_MS = 500;
+static const int64_t SLEEP_NS = SLEEP_MS * MS_IN_NS;
+// Conservatively assume that we might be descheduled for up to 50 ms
+static const int64_t SLACK_MS = 50;
+static const int64_t SLACK_NS = SLACK_MS * MS_IN_NS;
+
+TEST(SystemClock, SystemClock) {
+    auto startUptimeMs = android::uptimeMillis();
+    auto startRealtimeMs = android::elapsedRealtime();
+    auto startRealtimeNs = android::elapsedRealtimeNano();
+
+    ASSERT_GT(startUptimeMs, 0)
+            << "uptimeMillis() reported an impossible uptime";
+    ASSERT_GE(startRealtimeMs, startUptimeMs)
+            << "elapsedRealtime() thinks we've suspended for negative time";
+    ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+            << "elapsedRealtimeNano() thinks we've suspended for negative time";
+
+    ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+    ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+
+    timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = SLEEP_MS * MS_IN_NS;
+    auto nanosleepErr = TEMP_FAILURE_RETRY(nanosleep(&ts, nullptr));
+    ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
+
+    auto endUptimeMs = android::uptimeMillis();
+    auto endRealtimeMs = android::elapsedRealtime();
+    auto endRealtimeNs = android::elapsedRealtimeNano();
+
+    EXPECT_GE(endUptimeMs - startUptimeMs, SLEEP_MS)
+            << "uptimeMillis() advanced too little after nanosleep()";
+    EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
+            << "uptimeMillis() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
+            << "elapsedRealtime() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
+            << "elapsedRealtime() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeNs - startRealtimeNs, SLEEP_NS)
+            << "elapsedRealtimeNano() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
+            << "elapsedRealtimeNano() advanced too much after nanosleep()";
+
+    EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+    EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+}
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index f618835..4b205a7 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -48,7 +48,8 @@
 
 class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
  public:
-  ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+  explicit ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)
+      : ZipArchiveStreamEntry(handle) {}
   virtual ~ZipArchiveStreamEntryUncompressed() {}
 
   const std::vector<uint8_t>* Read() override;
@@ -110,7 +111,8 @@
 
 class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
  public:
-  ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+  explicit ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)
+      : ZipArchiveStreamEntry(handle) {}
   virtual ~ZipArchiveStreamEntryCompressed();
 
   const std::vector<uint8_t>* Read() override;
@@ -249,7 +251,7 @@
 
 class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
  public:
-  ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
+  explicit ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
       : ZipArchiveStreamEntryUncompressed(handle) {}
   virtual ~ZipArchiveStreamEntryRawCompressed() {}
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index e65469a..52f49cc 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -27,6 +27,7 @@
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
+#include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
@@ -278,66 +279,68 @@
     fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
 
     fprintf(stderr, "options include:\n"
-                    "  -s              Set default filter to silent.\n"
-                    "                  Like specifying filterspec '*:S'\n"
-                    "  -f <filename>   Log to file. Default is stdout\n"
-                    "  --file=<filename>\n"
-                    "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
-                    "  --rotate-kbytes=<kbytes>\n"
-                    "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
-                    "  --rotate-count=<count>\n"
-                    "  -v <format>     Sets the log print format, where <format> is:\n"
-                    "  --format=<format>\n"
-                    "                      brief color epoch long monotonic printable process raw\n"
-                    "                      tag thread threadtime time uid usec UTC year zone\n\n"
-                    "  -D              print dividers between each log buffer\n"
-                    "  --dividers\n"
-                    "  -c              clear (flush) the entire log and exit\n"
-                    "  --clear\n"
-                    "  -d              dump the log and then exit (don't block)\n"
-                    "  -e <expr>       only print lines where the log message matches <expr>\n"
-                    "  --regex <expr>  where <expr> is a regular expression\n"
-                    "  -m <count>      quit after printing <count> lines. This is meant to be\n"
-                    "  --max-count=<count> paired with --regex, but will work on its own.\n"
-                    "  --print         paired with --regex and --max-count to let content bypass\n"
+                    "  -s              Set default filter to silent. Equivalent to filterspec '*:S'\n"
+                    "  -f <file>, --file=<file>               Log to file. Default is stdout\n"
+                    "  -r <kbytes>, --rotate-kbytes=<kbytes>  Rotate log every kbytes. Requires -f\n"
+                    "                  option. Permits property expansion.\n"
+                    "  -n <count>, --rotate-count=<count>     Sets max number of rotated logs to\n"
+                    "                  <count>, default 4. Permits property expansion.\n"
+                    "  -v <format>, --format=<format>\n"
+                    "                  Sets the log print format, where <format> is:\n"
+                    "                    brief color epoch long monotonic printable process raw\n"
+                    "                    tag thread threadtime time uid usec UTC year zone\n"
+                    "  -D, --dividers  Print dividers between each log buffer\n"
+                    "  -c, --clear     Clear (flush) the entire log and exit\n"
+                    "  -d              Dump the log and then exit (don't block)\n"
+                    "  -e <expr>, --regex=<expr>\n"
+                    "                  Only print lines where the log message matches <expr>\n"
+                    "                  where <expr> is a regular expression\n"
+                    // Leave --head undocumented as alias for -m
+                    "  -m <count>, --max-count=<count>\n"
+                    "                  Quit after printing <count> lines. This is meant to be\n"
+                    "                  paired with --regex, but will work on its own.\n"
+                    "  --print         Paired with --regex and --max-count to let content bypass\n"
                     "                  regex filter but still stop at number of matches.\n"
-                    "  -t <count>      print only the most recent <count> lines (implies -d)\n"
-                    "  -t '<time>'     print most recent lines since specified time (implies -d)\n"
-                    "  -T <count>      print only the most recent <count> lines (does not imply -d)\n"
-                    "  -T '<time>'     print most recent lines since specified time (not imply -d)\n"
+                    // Leave --tail undocumented as alias for -t
+                    "  -t <count>      Print only the most recent <count> lines (implies -d)\n"
+                    "  -t '<time>'     Print most recent lines since specified time (implies -d)\n"
+                    "  -T <count>      Print only the most recent <count> lines (does not imply -d)\n"
+                    "  -T '<time>'     Print most recent lines since specified time (not imply -d)\n"
                     "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
                     "                  'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
-                    "  -g              get the size of the log's ring buffer and exit\n"
-                    "  --buffer-size\n"
-                    "  -G <size>       set size of log ring buffer, may suffix with K or M.\n"
-                    "  --buffer-size=<size>\n"
-                    "  -L              dump logs from prior to last reboot\n"
-                    "  --last\n"
+                    "  -g, --buffer-size                      Get the size of the ring buffer.\n"
+                    "  -G <size>, --buffer-size=<size>\n"
+                    "                  Set size of log ring buffer, may suffix with K or M.\n"
+                    "  -L, -last       Dump logs from prior to last reboot\n"
                     // Leave security (Device Owner only installations) and
                     // kernel (userdebug and eng) buffers undocumented.
-                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
-                    "  --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
-                    "                  parameters are allowed and results are interleaved. The\n"
-                    "                  default is -b main -b system -b crash.\n"
-                    "  -B              output the log in binary.\n"
-                    "  --binary\n"
-                    "  -S              output statistics.\n"
-                    "  --statistics\n"
-                    "  -p              print prune white and ~black list. Service is specified as\n"
-                    "  --prune         UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
+                    "  -b <buffer>, --buffer=<buffer>         Request alternate ring buffer, 'main',\n"
+                    "                  'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
+                    "                  Multiple -b parameters or comma separated list of buffers are\n"
+                    "                  allowed. Buffers interleaved. Default -b main,system,crash.\n"
+                    "                  Permits property expansion.\n"
+                    "  -B, --binary    Output the log in binary.\n"
+                    "  -S, --statistics                       Output statistics.\n"
+                    "  -p, --prune     Print prune white and ~black list. Service is specified as\n"
+                    "                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
                     "                  with ~, otherwise weighed for longevity if unadorned. All\n"
                     "                  other pruning activity is oldest first. Special case ~!\n"
                     "                  represents an automatic quicker pruning for the noisiest\n"
                     "                  UID as determined by the current statistics.\n"
-                    "  -P '<list> ...' set prune white and ~black list, using same format as\n"
-                    "  --prune='<list> ...'  printed above. Must be quoted.\n"
+                    "  -P '<list> ...', --prune='<list> ...'\n"
+                    "                  Set prune white and ~black list, using same format as\n"
+                    "                  listed above. Must be quoted.\n"
                     "  --pid=<pid>     Only prints logs from the given pid.\n"
-                    // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
+                    // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
                     "  --wrap          Sleep for 2 hours or when buffer about to wrap whichever\n"
                     "                  comes first. Improves efficiency of polling by providing\n"
                     "                  an about-to-wrap wakeup.\n");
 
-    fprintf(stderr,"\nfilterspecs are a series of \n"
+    fprintf(stderr,"\nProperty expansion where available, may need to be single quoted to prevent\n"
+                   "shell expansion:\n"
+                   "  ${key}          - Expand string with property value associated with key\n"
+                   "  ${key:-default} - Expand, if property key value clear, use default\n"
+                   "\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
                    "where <tag> is a log component tag (or * for all) and priority is:\n"
                    "  V    Verbose (default for <tag>)\n"
@@ -394,7 +397,7 @@
 }
 
 /*String to unsigned int, returns -1 if it fails*/
-static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+static bool getSizeTArg(const char *ptr, size_t *val, size_t min = 0,
                         size_t max = SIZE_MAX)
 {
     if (!ptr) {
@@ -535,6 +538,49 @@
     return retval;
 }
 
+// Expand multiple flat property references ${<tag>:-default} or ${tag}.
+//
+// ToDo: Do we permit nesting?
+//   ${persist.logcat.something:-${ro.logcat.something:-maybesomething}}
+// For now this will result in a syntax error for caller and is acceptable.
+//
+std::string expand(const char *str)
+{
+  std::string retval(str);
+
+  // Caller has no use for ${, } or :- as literals so no use for escape
+  // character. Result expectations are a number or a string, with validity
+  // checking for both in caller. Recursive expansion or other syntax errors
+  // will result in content caller can not obviously tolerate, error must
+  // report substring if applicable, expanded and original content (if
+  // different) so that it will be clear to user what they did wrong.
+  for (size_t pos; (pos = retval.find("${")) != std::string::npos; ) {
+    size_t epos = retval.find("}", pos + 2);
+    if (epos == std::string::npos) {
+      break; // Caller will error out, showing this unexpanded.
+    }
+    size_t def = retval.find(":-", pos + 2);
+    if (def >= epos) {
+      def = std::string::npos;
+    }
+    std::string default_value("");
+    std::string key;
+    if (def == std::string::npos) {
+      key = retval.substr(pos + 2, epos - (pos + 2));
+    } else {
+      key = retval.substr(pos + 2, def - (pos + 2));
+      default_value = retval.substr(def + 2, epos - (def + 2));
+    }
+    char value[PROPERTY_VALUE_MAX];
+    property_get(key.c_str(), value, default_value.c_str());
+    // Caller will error out, syntactically empty content at this point
+    // will not be tolerated as expected.
+    retval.replace(pos, epos - pos + 1, value);
+  }
+
+  return retval;
+}
+
 } /* namespace android */
 
 
@@ -765,111 +811,75 @@
             break;
 
             case 'b': {
-                if (strcmp(optarg, "default") == 0) {
-                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
-                        switch (i) {
-                        case LOG_ID_SECURITY:
-                        case LOG_ID_EVENTS:
-                            continue;
-                        case LOG_ID_MAIN:
-                        case LOG_ID_SYSTEM:
-                        case LOG_ID_CRASH:
-                            break;
-                        default:
-                            continue;
-                        }
+                unsigned idMask = 0;
+                std::string expanded = expand(optarg);
+                std::istringstream copy(expanded);
+                std::string token;
+                // wish for strtok and ",:; \t\n\r\f" for hidden flexibility
+                while (std::getline(copy, token, ',')) { // settle for ","
+                    if (token.compare("default") == 0) {
+                        idMask |= (1 << LOG_ID_MAIN) |
+                                  (1 << LOG_ID_SYSTEM) |
+                                  (1 << LOG_ID_CRASH);
+                    } else if (token.compare("all") == 0) {
+                        idMask = (unsigned)-1;
+                    } else {
+                        log_id_t log_id = android_name_to_log_id(token.c_str());
+                        const char *name = android_log_id_to_name(log_id);
 
-                        const char *name = android_log_id_to_name((log_id_t)i);
-                        log_id_t log_id = android_name_to_log_id(name);
-
-                        if (log_id != (log_id_t)i) {
-                            continue;
-                        }
-
-                        bool found = false;
-                        for (dev = devices; dev; dev = dev->next) {
-                            if (!strcmp(optarg, dev->device)) {
-                                found = true;
-                                break;
+                        if (token.compare(name) != 0) {
+                            bool strDifferent = expanded.compare(token);
+                            if (expanded.compare(optarg)) {
+                                expanded += " expanded from ";
+                                expanded += optarg;
                             }
-                            if (!dev->next) {
-                                break;
+                            if (strDifferent) {
+                                expanded = token + " within " + expanded;
                             }
+                            logcat_panic(true, "unknown buffer -b %s\n",
+                                         expanded.c_str());
                         }
-                        if (found) {
-                            break;
-                        }
-
-                        log_device_t* d = new log_device_t(name, false);
-
-                        if (dev) {
-                            dev->next = d;
-                            dev = d;
-                        } else {
-                            devices = dev = d;
-                        }
-                        g_devCount++;
+                        idMask |= (1 << log_id);
                     }
-                    break;
                 }
 
-                if (strcmp(optarg, "all") == 0) {
-                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
-                        const char *name = android_log_id_to_name((log_id_t)i);
-                        log_id_t log_id = android_name_to_log_id(name);
+                for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                    const char *name = android_log_id_to_name((log_id_t)i);
+                    log_id_t log_id = android_name_to_log_id(name);
 
-                        if (log_id != (log_id_t)i) {
-                            continue;
-                        }
+                    if (log_id != (log_id_t)i) {
+                        continue;
+                    }
+                    if ((idMask & (1 << i)) == 0) {
+                        continue;
+                    }
 
-                        bool found = false;
-                        for (dev = devices; dev; dev = dev->next) {
-                            if (!strcmp(optarg, dev->device)) {
-                                found = true;
-                                break;
-                            }
-                            if (!dev->next) {
-                                break;
-                            }
-                        }
-                        if (found) {
+                    bool found = false;
+                    for (dev = devices; dev; dev = dev->next) {
+                        if (!strcmp(name, dev->device)) {
+                            found = true;
                             break;
                         }
-
-                        bool binary = !strcmp(name, "events") ||
-                                      !strcmp(name, "security");
-                        log_device_t* d = new log_device_t(name, binary);
-
-                        if (dev) {
-                            dev->next = d;
-                            dev = d;
-                        } else {
-                            devices = dev = d;
-                        }
-                        g_devCount++;
-                    }
-                    break;
-                }
-
-                bool binary = !(strcmp(optarg, "events") &&
-                                strcmp(optarg, "security"));
-
-                if (devices) {
-                    dev = devices;
-                    while (dev->next) {
-                        if (!strcmp(optarg, dev->device)) {
-                            dev = NULL;
+                        if (!dev->next) {
                             break;
                         }
-                        dev = dev->next;
                     }
+                    if (found) {
+                        continue;
+                    }
+
+                    bool binary = !strcmp(name, "events") ||
+                                  !strcmp(name, "security");
+                    log_device_t* d = new log_device_t(name, binary);
+
                     if (dev) {
-                        dev->next = new log_device_t(optarg, binary);
+                        dev->next = d;
+                        dev = d;
+                    } else {
+                        devices = dev = d;
                     }
-                } else {
-                    devices = new log_device_t(optarg, binary);
+                    g_devCount++;
                 }
-                g_devCount++;
             }
             break;
 
@@ -885,22 +895,36 @@
                 g_outputFileName = optarg;
             break;
 
-            case 'r':
-                if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+            case 'r': {
+                std::string expanded = expand(optarg);
+                if (!getSizeTArg(expanded.c_str(), &g_logRotateSizeKBytes, 1)) {
+                    if (expanded.compare(optarg)) {
+                        expanded += " expanded from ";
+                        expanded += optarg;
+                    }
+                    logcat_panic(true, "Invalid parameter -r %s\n",
+                                 expanded.c_str());
                 }
+            }
             break;
 
-            case 'n':
-                if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+            case 'n': {
+                std::string expanded = expand(optarg);
+                if (!getSizeTArg(expanded.c_str(), &g_maxRotatedLogs, 1)) {
+                    if (expanded.compare(optarg)) {
+                        expanded += " expanded from ";
+                        expanded += optarg;
+                    }
+                    logcat_panic(true, "Invalid parameter -n %s\n",
+                                 expanded.c_str());
                 }
+            }
             break;
 
             case 'v':
                 err = setLogFormat (optarg);
                 if (err < 0) {
-                    logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+                    logcat_panic(true, "Invalid parameter -v %s\n", optarg);
                 }
                 hasSetLogFormat |= err;
             break;
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index cf0e0d2..70d1dd4 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -2,10 +2,10 @@
     # all exec/services are called with umask(077), so no gain beyond 0700
     mkdir /data/misc/logd 0700 logd log
     # logd for write to /data/misc/logd, log group for read from pstore (-L)
-    exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n 256
+    exec - logd log -- /system/bin/logcat -L -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
     start logcatd
 
-service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n 256
+service logcatd /system/bin/logcat -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
     class late_start
     disabled
     # logd for write to /data/misc/logd, log group for read from log daemon
diff --git a/logcat/logpersist b/logcat/logpersist
index 8762ff1..e448456 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -1,5 +1,5 @@
 #! /system/bin/sh
-# logpersist cat start and stop handlers
+# logpersist cat, start and stop handlers
 progname="${0##*/}"
 case `getprop ro.debuggable` in
 1) ;;
@@ -7,36 +7,134 @@
    exit 1
    ;;
 esac
+
 data=/data/misc/logd
 property=persist.logd.logpersistd
 service=logcatd
-if [ X"${1}" = X"-h" -o X"${1}" = X"--help" ]; then
-  echo "${progname%.*}.cat            - dump current ${service%d} logs"
-  echo "${progname%.*}.start          - start ${service} service"
-  echo "${progname%.*}.stop [--clear] - stop ${service} service"
-  exit 0
+size_default=256
+buffer_default=all
+args="${@}"
+
+size=${size_default}
+buffer=${buffer_default}
+clear=false
+while [ ${#} -gt 0 ]; do
+  case ${1} in
+    -c|--clear) clear=true ;;
+    --size=*) size="${1#--size=}" ;;
+    --rotate-count=*) size="${1#--rotate-count=}" ;;
+    -n|--size|--rotate-count) size="${2}" ; shift ;;
+    --buffer=*) buffer="${1#--buffer=}" ;;
+    -b|--buffer) buffer="${2}" ; shift ;;
+    -h|--help|*)
+      LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
+      echo "${progname%.*}.cat             - dump current ${service%d} logs"
+      echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
+      echo "${LEAD_SPACE_}                 - start ${service} service"
+      echo "${progname%.*}.stop [--clear]  - stop ${service} service"
+      case ${1} in
+        -h|--help) exit 0 ;;
+        *) echo ERROR: bad argument ${@} >&2 ; exit 1 ;;
+      esac
+      ;;
+  esac
+  shift
+done
+
+if [ -z "${size}" -o "${size_default}" = "${size}" ]; then
+  unset size
 fi
+if [ -n "${size}" ] &&
+  ! ( [ 0 -lt "${size}" ] && [ 2048 -ge "${size}" ] ) >/dev/null 2>&1; then
+  echo ERROR: Invalid --size ${size} >&2
+  exit 1
+fi
+if [ -z "${buffer}" -o "${buffer_default}" = "${buffer}" ]; then
+  unset buffer
+fi
+if [ -n "${buffer}" ] && ! logcat -b ${buffer} -g >/dev/null 2>&1; then
+  echo ERROR: Invalid --buffer ${buffer} >&2
+  exit 1
+fi
+
 case ${progname} in
 *.cat)
-  su 1036 ls "${data}" |
+  if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
+    echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
+  fi
+  su logd ls "${data}" |
   tr -d '\r' |
   sort -ru |
   sed "s#^#${data}/#" |
-  su 1036 xargs cat
+  su logd xargs cat
   ;;
 *.start)
-  su 0 setprop ${property} ${service}
+  current_buffer="`getprop ${property}.buffer`"
+  current_size="`getprop ${property}.size`"
+  if [ "${service}" = "`getprop ${property}`" ]; then
+    if [ "true" = "${clear}" ]; then
+      su root stop ${service}
+      su root setprop ${property} ""
+      # 20ms done, guarantees content stop before rm
+      sleep 1
+    elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
+      echo   "ERROR: Changing existing collection parameters from" >&2
+      if [ "${buffer}" != "${current_buffer}" ]; then
+        a=${current_buffer}
+        b=${buffer}
+        if [ -z "${a}" ]; then a="${default_buffer}"; fi
+        if [ -z "${b}" ]; then b="${default_buffer}"; fi
+        echo "           --buffer ${a} to ${b}" >&2
+      fi
+      if [ "${size}" != "${current_size}" ]; then
+        a=${current_size}
+        b=${size}
+        if [ -z "${a}" ]; then a="${default_size}"; fi
+        if [ -z "${b}" ]; then b="${default_size}"; fi
+        echo "           --size ${a} to ${b}" >&2
+      fi
+      echo   "       Are you sure you want to do this?" >&2
+      echo   "       Suggest add --clear to erase data and restart with new settings." >&2
+      echo   "       To blindly override and retain data, ${progname%.*}.stop first." >&2
+      exit 1
+    fi
+  fi
+  if [ "true" = "${clear}" ]; then
+    su logd,misc rm -rf "${data}"
+  fi
+  if [ -n "${buffer}${current_buffer}" ]; then
+    su root setprop ${property}.buffer "${buffer}"
+  fi
+  if [ -n "${size}${current_size}" ]; then
+    su root setprop ${property}.size "${size}"
+  fi
+  # ${service}.rc does the heavy lifting with the following trigger
+  su root setprop ${property} ${service}
   getprop ${property}
+  # 20ms done, to permit process feedback check
   sleep 1
+  # also generate an error return code if not found running, bonus
   ps -t | grep "${data##*/}.*${service%d}"
   ;;
 *.stop)
-  su 0 stop ${service}
-  su 0 setprop ${property} ""
-  [ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
-  ( sleep 1 ; su 1036,9998 rm -rf "${data}" )
+  if [ -n "${size}${buffer}" ]; then
+    echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
+  fi
+  su root stop ${service}
+  su root setprop ${property} ""
+  if [ -n "`getprop ${property}.buffer`" ]; then
+    su root setprop ${property}.buffer ""
+  fi
+  if [ -n "`getprop ${property}.size`" ]; then
+    su root setprop ${property}.size ""
+  fi
+  if [ "true" = "${clear}" ]; then
+    # 20ms done, guarantees content stop before rm
+    sleep 1
+    su logd,misc rm -rf "${data}"
+  fi
   ;;
 *)
-  echo "Unexpected command ${0##*/} ${@}" >&2
+  echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
   exit 1
 esac
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index a28664e..3bf8a0b 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -56,6 +56,6 @@
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libcutils
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index be815be..dd85164 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -49,7 +49,7 @@
             }
         }
 
-        timestamp(const char *buffer)
+        explicit timestamp(const char *buffer)
         {
             init(buffer);
         }
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 5b3d77f..920d504 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,11 +25,14 @@
 
 #include <memory>
 
+#include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/logger.h>
 #include <log/log_read.h>
 
+#define BIG_BUFFER (5 * 1024)
+
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
 // a signal to stuff a terminating code into the logs, we will spin rather
@@ -54,7 +57,7 @@
       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int ids = 0;
     int count = 0;
@@ -102,7 +105,7 @@
       "logcat -v long -v year -b all -t 3 2>/dev/null",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -155,23 +158,29 @@
         return;
     }
 
-    FILE *fp;
+    int tries = 3; // in case run too soon after system start or buffer clear
+    int count;
 
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
-      "r")));
+    do {
+        FILE *fp;
 
-    char buffer[5120];
+        ASSERT_TRUE(NULL != (fp = popen(
+          "logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
+          "r")));
 
-    int count = 0;
+        char buffer[BIG_BUFFER];
 
-    while (fgetLongTime(buffer, sizeof(buffer), fp)) {
-        if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
-            ++count;
+        count = 0;
+
+        while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+            if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
+                ++count;
+            }
         }
-    }
 
-    pclose(fp);
+        pclose(fp);
+
+    } while ((count < 3) && --tries && (sleep(1), true));
 
     ASSERT_EQ(3, count);
 }
@@ -183,7 +192,7 @@
       "logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -198,84 +207,47 @@
     ASSERT_EQ(0, count);
 }
 
+void do_tail(int num) {
+    int tries = 3; // in case run too soon after system start or buffer clear
+    int count;
+
+    do {
+        char buffer[BIG_BUFFER];
+
+        snprintf(buffer, sizeof(buffer),
+          "logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
+          num);
+
+        FILE *fp;
+        ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+
+        count = 0;
+
+        while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+            ++count;
+        }
+
+        pclose(fp);
+
+    } while ((count < num) && --tries && (sleep(1), true));
+
+    ASSERT_EQ(num, count);
+}
+
 TEST(logcat, tail_3) {
-    FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null",
-      "r")));
-
-    char buffer[5120];
-
-    int count = 0;
-
-    while (fgetLongTime(buffer, sizeof(buffer), fp)) {
-        ++count;
-    }
-
-    pclose(fp);
-
-    ASSERT_EQ(3, count);
+    do_tail(3);
 }
 
 TEST(logcat, tail_10) {
-    FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null",
-      "r")));
-
-    char buffer[5120];
-
-    int count = 0;
-
-    while (fgetLongTime(buffer, sizeof(buffer), fp)) {
-        ++count;
-    }
-
-    pclose(fp);
-
-    ASSERT_EQ(10, count);
+    do_tail(10);
 }
 
 TEST(logcat, tail_100) {
-    FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null",
-      "r")));
-
-    char buffer[5120];
-
-    int count = 0;
-
-    while (fgetLongTime(buffer, sizeof(buffer), fp)) {
-        ++count;
-    }
-
-    pclose(fp);
-
-    ASSERT_EQ(100, count);
+    do_tail(100);
 }
 
 TEST(logcat, tail_1000) {
-    FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null",
-      "r")));
-
-    char buffer[5120];
-
-    int count = 0;
-
-    while (fgetLongTime(buffer, sizeof(buffer), fp)) {
-        ++count;
-    }
-
-    pclose(fp);
-
-    ASSERT_EQ(1000, count);
+    do_tail(1000);
 }
 
 TEST(logcat, tail_time) {
@@ -283,7 +255,7 @@
 
     ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
     char *last_timestamp = NULL;
     char *first_timestamp = NULL;
     int count = 0;
@@ -346,7 +318,7 @@
       "logcat -v brief -b events -t 100 2>/dev/null",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -370,15 +342,17 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(logcat, get_size) {
+int get_groups(const char *cmd) {
     FILE *fp;
 
     // NB: crash log only available in user space
-    ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null",
-      "r")));
+    EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
 
-    char buffer[5120];
+    if (fp == NULL) {
+        return 0;
+    }
+
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -438,7 +412,31 @@
 
     pclose(fp);
 
-    ASSERT_EQ(4, count);
+    return count;
+}
+
+TEST(logcat, get_size) {
+    ASSERT_EQ(4, get_groups(
+      "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null"));
+}
+
+// duplicate test for get_size, but use comma-separated list of buffers
+TEST(logcat, multiple_buffer) {
+    ASSERT_EQ(4, get_groups(
+      "logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
+}
+
+// duplicate test for get_size, but use test.logcat.buffer property
+TEST(logcat, property_expand) {
+    property_set("test.logcat.buffer", "radio,events");
+    EXPECT_EQ(4, get_groups(
+      "logcat -v brief -b 'system,${test.logcat.buffer:-bogo},main' -g 2>/dev/null"));
+    property_set("test.logcat.buffer", "");
+}
+
+TEST(logcat, bad_buffer) {
+    ASSERT_EQ(0, get_groups(
+      "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
 }
 
 static void caught_blocking(int /*signum*/)
@@ -467,7 +465,7 @@
       " logcat -v brief -b events 2>&1",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -536,7 +534,7 @@
       " logcat -v brief -b events -T 5 2>&1",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
 
@@ -599,7 +597,7 @@
         FILE *fp;
         EXPECT_TRUE(NULL != (fp = popen(command, "r")));
         if (fp) {
-            char buffer[5120];
+            char buffer[BIG_BUFFER];
             int count = 0;
 
             while (fgets(buffer, sizeof(buffer), fp)) {
@@ -642,7 +640,7 @@
 
         FILE *fp;
         EXPECT_TRUE(NULL != (fp = popen(command, "r")));
-        char buffer[5120];
+        char buffer[BIG_BUFFER];
         int log_file_count = 0;
 
         while (fgets(buffer, sizeof(buffer), fp)) {
@@ -812,12 +810,14 @@
     ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events -c 2>&1 ;"
+      " logcat -b events -g 2>&1 ;"
       " logcat -v brief -b events 2>&1",
       "r")));
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     int count = 0;
+    int minus_g = 0;
 
     int signals = 0;
 
@@ -835,6 +835,50 @@
             break;
         }
 
+        int size, consumed, max, payload;
+        char size_mult[3], consumed_mult[3];
+        size = consumed = max = payload = 0;
+        if (6 == sscanf(buffer, "events: ring buffer is %d%2s (%d%2s consumed),"
+                                " max entry is %db, max payload is %db",
+                                &size, size_mult, &consumed, consumed_mult,
+                                &max, &payload)) {
+            long full_size = size, full_consumed = consumed;
+
+            switch(size_mult[0]) {
+            case 'G':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'M':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'K':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'b':
+                break;
+            }
+            switch(consumed_mult[0]) {
+            case 'G':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'M':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'K':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'b':
+                break;
+            }
+            EXPECT_GT(full_size, full_consumed);
+            EXPECT_GT(full_size, max);
+            EXPECT_GT(max, payload);
+            EXPECT_GT(max, full_consumed);
+
+            ++minus_g;
+            continue;
+        }
+
         ++count;
 
         int p;
@@ -863,6 +907,7 @@
     pclose(fp);
 
     EXPECT_LE(1, count);
+    EXPECT_EQ(1, minus_g);
 
     EXPECT_EQ(1, signals);
 }
@@ -876,7 +921,7 @@
         return false;
     }
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *hold = *list;
@@ -905,7 +950,7 @@
 static bool set_white_black(const char *list) {
     FILE *fp;
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
     fp = popen(buffer, "r");
@@ -967,7 +1012,7 @@
     FILE *fp;
     int count = 0;
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid());
 
@@ -1000,7 +1045,7 @@
     FILE *fp;
     int count = 0;
 
-    char buffer[5120];
+    char buffer[BIG_BUFFER];
 
     snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 8c30f79..db65978 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -380,7 +380,7 @@
             tid(tid),
             padding(0) {
     }
-    LogBufferElementKey(uint64_t key):value(key) { }
+    explicit LogBufferElementKey(uint64_t key):value(key) { }
 
     uint64_t getKey() { return value; }
 };
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 2b02bc1..02a4a75 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -15,8 +15,10 @@
  */
 
 #include <fcntl.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <log/logger.h>
@@ -159,14 +161,13 @@
         return strdup("auditd");
     }
 
-    // Android hard coded
-    const struct android_id_info *info = android_ids;
-
-    for (size_t i = 0; i < android_id_count; ++i) {
-        if (info->aid == uid) {
-            return strdup(info->name);
+    // Android system
+    if (uid < AID_APP) {
+        // in bionic, thread safe as long as we copy the results
+        struct passwd *pwd = getpwuid(uid);
+        if (pwd) {
+            return strdup(pwd->pw_name);
         }
-        ++info;
     }
 
     // Parse /data/system/packages.list
@@ -179,6 +180,14 @@
         return name;
     }
 
+    // Android application
+    if (uid >= AID_APP) {
+        struct passwd *pwd = getpwuid(uid);
+        if (pwd) {
+            return strdup(pwd->pw_name);
+        }
+    }
+
     // report uid -> pid(s) -> pidToName if unique
     for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
         const PidEntry &entry = it->second;
diff --git a/metricsd/timer_test.cc b/metricsd/timer_test.cc
index 7a67e11..cfbcd8a 100644
--- a/metricsd/timer_test.cc
+++ b/metricsd/timer_test.cc
@@ -69,7 +69,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -88,7 +88,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   timer_.Start();
   base::TimeTicks buffer = timer_.start_time_;
   timer_.Start();
@@ -98,7 +98,7 @@
 TEST_F(TimerTest, Reset) {
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   timer_.Start();
   ASSERT_TRUE(timer_.Reset());
   ASSERT_FALSE(timer_.HasStarted());
@@ -110,7 +110,7 @@
       .WillOnce(Return(etime))
       .WillOnce(Return(stime2))
       .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.Stop());
   ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
@@ -130,7 +130,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_FALSE(timer_.Stop());
   // Now we try it again, but after a valid start/stop.
   timer_.Start();
@@ -152,7 +152,7 @@
       .WillOnce(Return(etime2))
       .WillOnce(Return(stime3))
       .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Pause());  // Starts timer paused.
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -181,7 +181,7 @@
       .WillOnce(Return(stime2))
       .WillOnce(Return(etime2))
       .WillOnce(Return(stime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Resume());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -208,7 +208,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -230,7 +230,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -257,7 +257,7 @@
       .WillOnce(Return(etime))
       .WillOnce(Return(stime2))
       .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -284,7 +284,7 @@
 TEST_F(TimerTest, PauseStop) {
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Pause());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -304,7 +304,7 @@
       .WillOnce(Return(stime))
       .WillOnce(Return(stime2))
       .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Pause());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -328,7 +328,7 @@
       .WillOnce(Return(stime2))
       .WillOnce(Return(stime3))
       .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -373,7 +373,7 @@
       .WillOnce(Return(etime2))
       .WillOnce(Return(stime3))
       .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   ASSERT_TRUE(timer_.Start());
   ASSERT_TRUE(timer_.start_time_ == stime);
   ASSERT_TRUE(timer_.HasStarted());
@@ -444,7 +444,7 @@
   EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
       .WillOnce(Return(stime))
       .WillOnce(Return(etime));
-  timer_reporter_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+  timer_reporter_.clock_wrapper_ = std::move(clock_wrapper_mock_);
   EXPECT_CALL(lib_, SendToUMA(kMetricName, kDelta1MSec, kMinSample, kMaxSample,
                               kNumBuckets)).WillOnce(Return(true));
   ASSERT_TRUE(timer_reporter_.Start());
diff --git a/rootdir/init.rc b/rootdir/init.rc
index aa32343..ef70bf2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -140,7 +140,6 @@
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0666 /dev/cpuctl/tasks
-    write /dev/cpuctl/cpu.shares 1024
     write /dev/cpuctl/cpu.rt_runtime_us 800000
     write /dev/cpuctl/cpu.rt_period_us 1000000
 
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 2d04a7f..ac5faa7 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -7,4 +7,7 @@
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
 LOCAL_SHARED_LIBRARIES := liblog libcutils libpackagelistparser
 
+LOCAL_SANITIZE := integer
+LOCAL_CLANG := true
+
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index f862561..f08c9d8 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -822,7 +822,8 @@
             hdr->nodeid, node ? node->name : "?");
     if (node) {
         __u64 n = req->nlookup;
-        while (n--) {
+        while (n) {
+            n--;
             release_node_locked(node);
         }
     }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index b1cdb60..d151ad6 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -32,12 +32,10 @@
 
 OUR_TOOLS := \
     getevent \
-    iftop \
     ioctl \
     log \
     nandread \
     newfs_msdos \
-    ps \
     sendevent \
     start \
     stop \
@@ -72,7 +70,7 @@
 $(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
 
 TOOLS_H := $(intermediates)/tools.h
-$(TOOLS_H): PRIVATE_TOOLS := $(ALL_TOOLS)
+$(TOOLS_H): PRIVATE_TOOLS := toolbox $(ALL_TOOLS)
 $(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
 $(TOOLS_H): $(LOCAL_PATH)/Android.mk
 $(TOOLS_H):
diff --git a/toolbox/iftop.c b/toolbox/iftop.c
deleted file mode 100644
index 800c0f0..0000000
--- a/toolbox/iftop.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#define PROC_NET_DEV    "/proc/net/dev"
-
-#define MAX_IF           8   /* max interfaces we can handle */
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-#define _STR(s) #s
-#define STR(s) _STR(s)
-
-struct if_stats {
-    char name[IFNAMSIZ];
-
-    unsigned int mtu;
-
-    unsigned int rx_bytes;
-    unsigned int rx_packets;
-    unsigned int rx_errors;
-    unsigned int rx_dropped;
-
-    unsigned int tx_bytes;
-    unsigned int tx_packets;
-    unsigned int tx_errors;
-    unsigned int tx_dropped;
-};
-
-static int get_mtu(const char *if_name)
-{
-    struct ifreq ifr;
-    int s, ret;
-
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-        perror("socket");
-        exit(EXIT_FAILURE);
-    }
-
-    memset(&ifr, 0, sizeof(struct ifreq));
-    ifr.ifr_addr.sa_family = AF_INET;
-    strcpy(ifr.ifr_name, if_name);
-
-    ret = ioctl(s, SIOCGIFMTU, &ifr);
-    if (ret < 0) {
-        perror("ioctl");
-        exit(EXIT_FAILURE);
-    }
-
-    ret = close(s);
-    if (ret < 0) {
-        perror("close");
-        exit(EXIT_FAILURE);
-    }
-
-    return ifr.ifr_mtu;
-}
-
-static int get_interfaces(struct if_stats *ifs)
-{
-    char buf[PAGE_SIZE];
-    char *p;
-    int ret, nr, fd;
-
-    fd = open(PROC_NET_DEV, O_RDONLY);
-    if (fd < 0) {
-        perror("open");
-        exit(EXIT_FAILURE);
-    }
-
-    ret = read(fd, buf, sizeof(buf) - 1);
-    if (ret < 0) {
-        perror("read");
-        exit(EXIT_FAILURE);
-    } else if (!ret) {
-        fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
-        exit(EXIT_FAILURE);
-    }
-    buf[ret] = '\0';
-
-    /* skip down to the third line */
-    p = strchr(buf, '\n');
-    if (!p) {
-        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-        exit(EXIT_FAILURE);
-    }
-    p = strchr(p + 1, '\n');
-    if (!p) {
-        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-        exit(EXIT_FAILURE);
-    }
-    p += 1;
-
-    /*
-     * Key:
-     * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
-     *     (Tx) bytes packets errs drop fifo colls carrier compressed
-     */
-    for (nr = 0; nr < MAX_IF; nr++) {
-        char *c;
-
-        ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
-        if (ret != 1) {
-            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-            exit(EXIT_FAILURE);
-        }
-
-        /*
-         * This works around a bug in the proc file where large interface names
-         * or Rx byte counts eat the delimiter, breaking sscanf.
-         */
-        c = strchr(ifs->name, ':');
-        if (c)
-            *c = '\0';
-
-        p = strchr(p, ':') + 1;
-
-        ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
-                     "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
-                     &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
-                     &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
-        if (ret != 8) {
-            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-            exit(EXIT_FAILURE);
-        }
-
-        ifs->mtu = get_mtu(ifs->name);
-
-        p = strchr(p, '\n') + 1;
-        if (*p == '\0') {
-            nr++;
-            break;
-        }
-
-        ifs++;
-    }
-
-    ret = close(fd);
-    if (ret) {
-        perror("close");
-        exit(EXIT_FAILURE);
-    }
-
-    return nr;
-}
-
-static void print_header(void)
-{
-    printf("               Rx                              Tx\n");
-    printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
-           "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
-           "packets", "errs", "drpd");
-}
-
-static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
-{
-    int i = 0;
-
-    while (nr--) {
-        if (old->rx_packets || old->tx_packets) {
-            printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
-                   new->name, new->mtu,
-                   new->rx_bytes - old->rx_bytes,
-                   new->rx_packets - old->rx_packets,
-                   new->rx_errors - old->rx_errors,
-                   new->rx_dropped - old->rx_dropped,
-                   new->tx_bytes - old->tx_bytes,
-                   new->tx_packets - old->tx_packets,
-                   new->tx_errors - old->tx_errors,
-                   new->tx_dropped - old->tx_dropped);
-            i++;
-        }
-        old++;
-        new++;
-    }
-
-    return i;
-}
-
-static void usage(const char *cmd)
-{
-    fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
-}
-
-int iftop_main(int argc, char *argv[])
-{
-    struct if_stats ifs[2][MAX_IF];
-    int count = 0, header_interval = 22, delay = 1, i;
-    unsigned int toggle = 0;
-
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-d")) {
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -d requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            delay = atoi(argv[i++]);
-            if (!delay)
-                delay = 1;
-            continue;
-        }
-        if (!strcmp(argv[i], "-r")) {
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -r requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            header_interval = atoi(argv[i++]);
-            if (header_interval < MAX_IF)
-                header_interval = MAX_IF;
-            continue;
-        }
-        if (!strcmp(argv[i], "-h")) {
-            usage(argv[0]);
-            exit(EXIT_SUCCESS);
-        }
-        usage(argv[0]);
-        exit(EXIT_FAILURE);
-    }
-
-    get_interfaces(ifs[!toggle]);
-    if (header_interval)
-        print_header();
-    while (1) {
-        int nr;
-
-        sleep(delay);
-        nr = get_interfaces(ifs[toggle]);
-        if (header_interval && count + nr > header_interval) {
-            print_header();
-            count = 0;
-        }
-        count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
-        toggle = !toggle;
-    }
-
-    return 0;
-}
diff --git a/toolbox/ps.c b/toolbox/ps.c
deleted file mode 100644
index d366f3e..0000000
--- a/toolbox/ps.c
+++ /dev/null
@@ -1,334 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-static char *nexttoksep(char **strp, char *sep)
-{
-    char *p = strsep(strp,sep);
-    return (p == 0) ? "" : p;
-}
-static char *nexttok(char **strp)
-{
-    return nexttoksep(strp, " ");
-}
-
-#define SHOW_PRIO 1
-#define SHOW_TIME 2
-#define SHOW_POLICY 4
-#define SHOW_CPU  8
-#define SHOW_MACLABEL 16
-#define SHOW_NUMERIC_UID 32
-#define SHOW_ABI 64
-
-#if __LP64__
-#define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */
-#else
-#define PC_WIDTH (2*sizeof(uintptr_t))
-#endif
-
-static int display_flags = 0;
-static int ppid_filter = 0;
-
-static void print_exe_abi(int pid);
-
-static int ps_line(int pid, int tid)
-{
-    char statline[1024];
-    char cmdline[1024];
-    char macline[1024];
-    char user[32];
-    struct stat stats;
-    int r;
-    char *ptr, *name, *state;
-    int ppid;
-    unsigned rss, vss;
-    uintptr_t eip;
-    unsigned utime, stime;
-    int prio, nice, rtprio, sched, psr;
-    struct passwd *pw;
-
-    snprintf(statline, sizeof(statline), "/proc/%d", tid ? tid : pid);
-    stat(statline, &stats);
-
-    if(tid) {
-        snprintf(statline, sizeof(statline), "/proc/%d/task/%d/stat", pid, tid);
-        cmdline[0] = 0;
-        snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
-    } else {
-        snprintf(statline, sizeof(statline), "/proc/%d/stat", pid);
-        snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
-        snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
-        int fd = open(cmdline, O_RDONLY);
-        if(fd == 0) {
-            r = 0;
-        } else {
-            r = read(fd, cmdline, 1023);
-            close(fd);
-            if(r < 0) r = 0;
-        }
-        cmdline[r] = 0;
-    }
-
-    int fd = open(statline, O_RDONLY);
-    if(fd == 0) return -1;
-    r = read(fd, statline, 1023);
-    close(fd);
-    if(r < 0) return -1;
-    statline[r] = 0;
-
-    ptr = statline;
-    nexttok(&ptr); // skip pid
-    ptr++;          // skip "("
-
-    name = ptr;
-    ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
-    *ptr++ = '\0';           // and null-terminate name.
-
-    ptr++;          // skip " "
-    state = nexttok(&ptr);
-    ppid = atoi(nexttok(&ptr));
-    nexttok(&ptr); // pgrp
-    nexttok(&ptr); // sid
-    nexttok(&ptr); // tty
-    nexttok(&ptr); // tpgid
-    nexttok(&ptr); // flags
-    nexttok(&ptr); // minflt
-    nexttok(&ptr); // cminflt
-    nexttok(&ptr); // majflt
-    nexttok(&ptr); // cmajflt
-#if 1
-    utime = atoi(nexttok(&ptr));
-    stime = atoi(nexttok(&ptr));
-#else
-    nexttok(&ptr); // utime
-    nexttok(&ptr); // stime
-#endif
-    nexttok(&ptr); // cutime
-    nexttok(&ptr); // cstime
-    prio = atoi(nexttok(&ptr));
-    nice = atoi(nexttok(&ptr));
-    nexttok(&ptr); // threads
-    nexttok(&ptr); // itrealvalue
-    nexttok(&ptr); // starttime
-    vss = strtoul(nexttok(&ptr), 0, 10); // vsize
-    rss = strtoul(nexttok(&ptr), 0, 10); // rss
-    nexttok(&ptr); // rlim
-    nexttok(&ptr); // startcode
-    nexttok(&ptr); // endcode
-    nexttok(&ptr); // startstack
-    nexttok(&ptr); // kstkesp
-    eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
-    nexttok(&ptr); // signal
-    nexttok(&ptr); // blocked
-    nexttok(&ptr); // sigignore
-    nexttok(&ptr); // sigcatch
-    nexttok(&ptr); // wchan
-    nexttok(&ptr); // nswap
-    nexttok(&ptr); // cnswap
-    nexttok(&ptr); // exit signal
-    psr = atoi(nexttok(&ptr)); // processor
-    rtprio = atoi(nexttok(&ptr)); // rt_priority
-    sched = atoi(nexttok(&ptr)); // scheduling policy
-
-    nexttok(&ptr); // tty
-
-    if(tid != 0) {
-        ppid = pid;
-        pid = tid;
-    }
-
-    pw = getpwuid(stats.st_uid);
-    if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
-        snprintf(user,sizeof(user),"%d",(int)stats.st_uid);
-    } else {
-        strcpy(user,pw->pw_name);
-    }
-
-    if(ppid_filter != 0 && ppid != ppid_filter) {
-        return 0;
-    }
-
-    if (display_flags & SHOW_MACLABEL) {
-        fd = open(macline, O_RDONLY);
-        strcpy(macline, "-");
-        if (fd >= 0) {
-            r = read(fd, macline, sizeof(macline)-1);
-            close(fd);
-            if (r > 0)
-                macline[r] = 0;
-        }
-        printf("%-30s ", macline);
-    }
-
-    printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
-    if (display_flags & SHOW_CPU)
-        printf(" %-2d", psr);
-    if (display_flags & SHOW_PRIO)
-        printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
-    if (display_flags & SHOW_POLICY) {
-        SchedPolicy p;
-        if (get_sched_policy(pid, &p) < 0)
-            printf(" un ");
-        else
-            printf(" %.2s ", get_sched_policy_name(p));
-    }
-    char path[PATH_MAX];
-    snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
-    char wchan[10];
-    fd = open(path, O_RDONLY);
-    ssize_t wchan_len = read(fd, wchan, sizeof(wchan));
-    if (wchan_len == -1) {
-        wchan[wchan_len = 0] = '\0';
-    }
-    close(fd);
-    printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state);
-    if (display_flags & SHOW_ABI) {
-        print_exe_abi(pid);
-    }
-    printf("%s", cmdline[0] ? cmdline : name);
-    if(display_flags&SHOW_TIME)
-        printf(" (u:%d, s:%d)", utime, stime);
-
-    printf("\n");
-    return 0;
-}
-
-static void print_exe_abi(int pid)
-{
-    int fd, r;
-    char exeline[1024];
-
-    snprintf(exeline, sizeof(exeline), "/proc/%d/exe", pid);
-    fd = open(exeline, O_RDONLY);
-    if(fd == 0) {
-        printf("    ");
-        return;
-    }
-    r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
-    close(fd);
-    if(r < 0) {
-        printf("    ");
-        return;
-    }
-    if (memcmp("\177ELF", exeline, 4) != 0) {
-        printf("??  ");
-        return;
-    }
-    switch (exeline[4]) {
-        case 1:
-            printf("32  ");
-            return;
-        case 2:
-            printf("64  ");
-            return;
-        default:
-            printf("??  ");
-            return;
-    }
-}
-
-void ps_threads(int pid)
-{
-    char tmp[128];
-    DIR *d;
-    struct dirent *de;
-
-    snprintf(tmp,sizeof(tmp),"/proc/%d/task",pid);
-    d = opendir(tmp);
-    if(d == 0) return;
-
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int tid = atoi(de->d_name);
-            if(tid == pid) continue;
-            ps_line(pid, tid);
-        }
-    }
-    closedir(d);
-}
-
-int ps_main(int argc, char **argv)
-{
-    DIR *d;
-    struct dirent *de;
-    int pidfilter = 0;
-    int threads = 0;
-
-    while(argc > 1){
-        if(!strcmp(argv[1],"-t")) {
-            threads = 1;
-        } else if(!strcmp(argv[1],"-n")) {
-            display_flags |= SHOW_NUMERIC_UID;
-        } else if(!strcmp(argv[1],"-x")) {
-            display_flags |= SHOW_TIME;
-        } else if(!strcmp(argv[1], "-Z")) {
-            display_flags |= SHOW_MACLABEL;
-        } else if(!strcmp(argv[1],"-P")) {
-            display_flags |= SHOW_POLICY;
-        } else if(!strcmp(argv[1],"-p")) {
-            display_flags |= SHOW_PRIO;
-        } else if(!strcmp(argv[1],"-c")) {
-            display_flags |= SHOW_CPU;
-        } else if(!strcmp(argv[1],"--abi")) {
-            display_flags |= SHOW_ABI;
-        } else if(!strcmp(argv[1],"--ppid")) {
-            ppid_filter = atoi(argv[2]);
-            if (ppid_filter == 0) {
-                /* Bug 26554285: Use printf because some apps require at least
-                 * one line of output to stdout even for errors.
-                 */
-                printf("bad ppid '%s'\n", argv[2]);
-                return 1;
-            }
-            argc--;
-            argv++;
-        } else {
-            pidfilter = atoi(argv[1]);
-            if (pidfilter == 0) {
-                /* Bug 26554285: Use printf because some apps require at least
-                 * one line of output to stdout even for errors.
-                 */
-                printf("bad pid '%s'\n", argv[1]);
-                return 1;
-            }
-        }
-        argc--;
-        argv++;
-    }
-
-    if (display_flags & SHOW_MACLABEL) {
-        printf("LABEL                          ");
-    }
-    printf("USER      PID   PPID  VSIZE  RSS  %s%s %sWCHAN      %*s  %sNAME\n",
-           (display_flags&SHOW_CPU)?"CPU ":"",
-           (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
-           (display_flags&SHOW_POLICY)?"PCY " : "",
-           (int) PC_WIDTH, "PC",
-           (display_flags&SHOW_ABI)?"ABI " : "");
-
-    d = opendir("/proc");
-    if(d == 0) return -1;
-
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int pid = atoi(de->d_name);
-            if(!pidfilter || (pidfilter == pid)) {
-                ps_line(pid, 0);
-                if(threads) ps_threads(pid);
-            }
-        }
-    }
-    closedir(d);
-    return 0;
-}
-
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 915da44..b5a942c 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -4,29 +4,14 @@
 #include <string.h>
 #include <unistd.h>
 
-int main(int, char **);
-
-static int toolbox_main(int argc, char **argv)
-{
-    // "toolbox foo ..." is equivalent to "foo ..."
-    if (argc > 1) {
-        return main(argc - 1, argv + 1);
-    } else {
-        printf("Toolbox!\n");
-        return 0;
-    }
-}
-
 #define TOOL(name) int name##_main(int, char**);
 #include "tools.h"
 #undef TOOL
 
-static struct 
-{
-    const char *name;
+static struct {
+    const char* name;
     int (*func)(int, char**);
 } tools[] = {
-    { "toolbox", toolbox_main },
 #define TOOL(name) { #name, name##_main },
 #include "tools.h"
 #undef TOOL
@@ -40,33 +25,35 @@
     _exit(0);
 }
 
-int main(int argc, char **argv)
-{
-    int i;
-    char *name = argv[0];
-
+int main(int argc, char** argv) {
     // Let's assume that none of this code handles broken pipes. At least ls,
     // ps, and top were broken (though I'd previously added this fix locally
     // to top). We exit rather than use SIG_IGN because tools like top will
     // just keep on writing to nowhere forever if we don't stop them.
     signal(SIGPIPE, SIGPIPE_handler);
 
-    if((argc > 1) && (argv[1][0] == '@')) {
-        name = argv[1] + 1;
-        argc--;
-        argv++;
-    } else {
-        char *cmd = strrchr(argv[0], '/');
-        if (cmd)
-            name = cmd + 1;
-    }
+    char* cmd = strrchr(argv[0], '/');
+    char* name = cmd ? (cmd + 1) : argv[0];
 
-    for(i = 0; tools[i].name; i++){
-        if(!strcmp(tools[i].name, name)){
+    for (size_t i = 0; tools[i].name; i++) {
+        if (!strcmp(tools[i].name, name)) {
             return tools[i].func(argc, argv);
         }
     }
 
     printf("%s: no such tool\n", argv[0]);
-    return -1;
+    return 127;
+}
+
+int toolbox_main(int argc, char** argv) {
+    // "toolbox foo ..." is equivalent to "foo ..."
+    if (argc > 1) {
+        return main(argc - 1, argv + 1);
+    }
+
+    // Plain "toolbox" lists the tools.
+    for (size_t i = 1; tools[i].name; i++) {
+        printf("%s%c", tools[i].name, tools[i+1].name ? ' ' : '\n');
+    }
+    return 0;
 }
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/util.h
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
new file mode 100644
index 0000000..3982c8f
--- /dev/null
+++ b/trusty/gatekeeper/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK.  Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := gatekeeper.trusty
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+	module.cpp \
+	trusty_gatekeeper_ipc.c \
+	trusty_gatekeeper.cpp
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+	libgatekeeper \
+	liblog \
+	libcutils \
+	libtrusty
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/gatekeeper_ipc.h b/trusty/gatekeeper/gatekeeper_ipc.h
new file mode 100644
index 0000000..b05dcd8
--- /dev/null
+++ b/trusty/gatekeeper/gatekeeper_ipc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
+#define GATEKEEPER_MAX_BUFFER_LENGTH 1024
+
+enum gatekeeper_command {
+	GK_REQ_SHIFT = 1,
+	GK_RESP_BIT  = 1,
+
+	GK_ENROLL       = (0 << GK_REQ_SHIFT),
+	GK_VERIFY       = (1 << GK_REQ_SHIFT),
+};
+
+/**
+ * gatekeeper_message - Serial header for communicating with GK server
+ * @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized
+ *       buffer of the corresponding request object.
+ * @payload: start of the serialized command specific payload
+ */
+struct gatekeeper_message {
+    uint32_t cmd;
+    uint8_t payload[0];
+};
+
diff --git a/trusty/gatekeeper/module.cpp b/trusty/gatekeeper/module.cpp
new file mode 100644
index 0000000..0ee3c2f
--- /dev/null
+++ b/trusty/gatekeeper/module.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hardware.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "trusty_gatekeeper.h"
+
+using gatekeeper::TrustyGateKeeperDevice;
+
+static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
+        hw_device_t **device) {
+
+    if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
+        return -EINVAL;
+    }
+
+    TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
+    if (gatekeeper == NULL) return -ENOMEM;
+    *device = gatekeeper->hw_device();
+
+    return 0;
+}
+
+static struct hw_module_methods_t gatekeeper_module_methods = {
+    .open = trusty_gatekeeper_open,
+};
+
+struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = GATEKEEPER_HARDWARE_MODULE_ID,
+        .name = "Trusty GateKeeper HAL",
+        .author = "The Android Open Source Project",
+        .methods = &gatekeeper_module_methods,
+        .dso = 0,
+        .reserved = {}
+    },
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
new file mode 100644
index 0000000..d24f44f
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <type_traits>
+
+#include "trusty_gatekeeper.h"
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+
+namespace gatekeeper {
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+    static_assert(std::is_standard_layout<TrustyGateKeeperDevice>::value,
+                  "TrustyGateKeeperDevice must be standard layout");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0,
+                  "device_ must be the first member of TrustyGateKeeperDevice");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0,
+                  "common must be the first member of gatekeeper_device");
+#else
+    assert(reinterpret_cast<gatekeeper_device_t *>(this) == &device_);
+    assert(reinterpret_cast<hw_device_t *>(this) == &(device_.common));
+#endif
+
+    memset(&device_, 0, sizeof(device_));
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = const_cast<hw_module_t *>(module);
+    device_.common.close = close_device;
+
+    device_.enroll = enroll;
+    device_.verify = verify;
+    device_.delete_user = nullptr;
+    device_.delete_all_users = nullptr;
+
+    int rc = trusty_gatekeeper_connect();
+    if (rc < 0) {
+        ALOGE("Error initializing trusty session: %d", rc);
+    }
+
+    error_ = rc;
+
+}
+
+hw_device_t* TrustyGateKeeperDevice::hw_device() {
+    return &device_.common;
+}
+
+int TrustyGateKeeperDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<TrustyGateKeeperDevice *>(dev);
+    return 0;
+}
+
+TrustyGateKeeperDevice::~TrustyGateKeeperDevice() {
+    trusty_gatekeeper_disconnect();
+}
+
+int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle,
+        uint32_t current_password_handle_length, const uint8_t *current_password,
+        uint32_t current_password_length, const uint8_t *desired_password,
+        uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+        uint32_t *enrolled_password_handle_length) {
+
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+
+
+    return 0;
+}
+
+int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge,
+        const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+        const uint8_t *provided_password, uint32_t provided_password_length,
+        uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    if (request_reenroll != NULL) {
+        *request_reenroll = response.request_reenroll;
+    }
+
+    return 0;
+}
+
+gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
+        GateKeeperMessage *response) {
+    uint32_t request_size = request.GetSerializedSize();
+    if (request_size > SEND_BUF_SIZE)
+        return ERROR_INVALID;
+    uint8_t send_buf[SEND_BUF_SIZE];
+    request.Serialize(send_buf, send_buf + request_size);
+
+    // Send it
+    uint8_t recv_buf[RECV_BUF_SIZE];
+    uint32_t response_size = RECV_BUF_SIZE;
+    int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size);
+    if (rc < 0) {
+        ALOGE("error (%d) calling gatekeeper TA", rc);
+        return ERROR_INVALID;
+    }
+
+    const gatekeeper_message *msg = reinterpret_cast<gatekeeper_message *>(recv_buf);
+    const uint8_t *payload = msg->payload;
+
+    return response->Deserialize(payload, payload + response_size);
+}
+
+static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) {
+    return reinterpret_cast<TrustyGateKeeperDevice *>(const_cast<gatekeeper_device *>(dev));
+}
+
+/* static */
+int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (dev == NULL ||
+            enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length,
+            current_password, current_password_length, desired_password, desired_password_length,
+            enrolled_password_handle, enrolled_password_handle_length);
+
+}
+
+/* static */
+int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+        bool *request_reenroll) {
+
+    if (dev == NULL || enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle,
+            enrolled_password_handle_length, provided_password, provided_password_length,
+            auth_token, auth_token_length, request_reenroll);
+}
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
new file mode 100644
index 0000000..82108dc
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TRUSTY_GATEKEEPER_H
+#define TRUSTY_GATEKEEPER_H
+
+#include <hardware/gatekeeper.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+#include "gatekeeper_ipc.h"
+
+namespace gatekeeper {
+
+class TrustyGateKeeperDevice {
+    public:
+
+    TrustyGateKeeperDevice(const hw_module_t* module);
+    ~TrustyGateKeeperDevice();
+
+    hw_device_t* hw_device();
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password will not be allocated.
+     */
+    int Enroll(uint32_t uid, const uint8_t *current_password_handle,
+            uint32_t current_password_handle_length, const uint8_t *current_password,
+            uint32_t current_password_length, const uint8_t *desired_password,
+            uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+            uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches expected_password after enrolling
+     * with the authentication factor private key.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to verification_token,
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle,
+            uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+            uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+            bool *request_reenroll);
+
+    private:
+
+    gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
+                           GateKeeperMessage* response);
+
+    gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
+        return Send(GK_ENROLL, request, response);
+    }
+
+    gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
+        return Send(GK_VERIFY, request, response);
+    }
+
+    // Static methods interfacing the HAL API with the TrustyGateKeeper device
+
+    /**
+     * Enrolls desired_password, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * If there was already a password enrolled, it should be provided in
+     * current_password_handle, along with the current password in current_password
+     * that should validate against current_password_handle.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+
+    static int close_device(hw_device_t* dev);
+
+    gatekeeper_device device_;
+    int error_;
+
+};
+}
+
+#endif
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
new file mode 100644
index 0000000..a1c319e
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+#include <trusty/tipc.h>
+
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_gatekeeper_connect() {
+    int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
+    if (rc < 0) {
+        return rc;
+    }
+
+    handle_ = rc;
+    return 0;
+}
+
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size) {
+    if (handle_ == 0) {
+        ALOGE("not connected\n");
+        return -EINVAL;
+    }
+
+    size_t msg_size = in_size + sizeof(struct gatekeeper_message);
+    struct gatekeeper_message *msg = malloc(msg_size);
+    msg->cmd = cmd;
+    memcpy(msg->payload, in, in_size);
+
+    ssize_t rc = write(handle_, msg, msg_size);
+    free(msg);
+
+    if (rc < 0) {
+        ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+                GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    rc = read(handle_, out, *out_size);
+    if (rc < 0) {
+        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+                cmd, GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    if ((size_t) rc < sizeof(struct gatekeeper_message)) {
+        ALOGE("invalid response size (%d)\n", (int) rc);
+        return -EINVAL;
+    }
+
+    msg = (struct gatekeeper_message *) out;
+
+    if ((cmd | GK_RESP_BIT) != msg->cmd) {
+        ALOGE("invalid command (%d)\n", msg->cmd);
+        return -EINVAL;
+    }
+
+    *out_size = ((size_t) rc) - sizeof(struct gatekeeper_message);
+    return rc;
+}
+
+void trusty_gatekeeper_disconnect() {
+    if (handle_ != 0) {
+        tipc_close(handle_);
+    }
+}
+
diff --git a/libcutils/atomic.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
similarity index 62%
copy from libcutils/atomic.c
copy to trusty/gatekeeper/trusty_gatekeeper_ipc.h
index d34aa00..f8de7f8 100644
--- a/libcutils/atomic.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+__BEGIN_DECLS
 
-#define ANDROID_ATOMIC_INLINE
+int trusty_gatekeeper_connect();
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size);
+void trusty_gatekeeper_disconnect();
 
-#include <cutils/atomic.h>
+__END_DECLS
diff --git a/trusty/keymaster/Android.mk b/trusty/keymaster/Android.mk
new file mode 100644
index 0000000..0ebf52d
--- /dev/null
+++ b/trusty/keymaster/Android.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK.  Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+###
+# trusty_keymaster is a binary used only for on-device testing.  It
+# runs Trusty Keymaster through a basic set of operations with RSA
+# and ECDSA keys.
+###
+LOCAL_MODULE := trusty_keymaster_tipc
+LOCAL_SRC_FILES := \
+	trusty_keymaster_device.cpp \
+	trusty_keymaster_ipc.c \
+	trusty_keymaster_main.cpp
+LOCAL_SHARED_LIBRARIES := \
+	libcrypto \
+	libcutils \
+	libkeymaster1 \
+	libtrusty \
+	libkeymaster_messages \
+	liblog
+
+include $(BUILD_EXECUTABLE)
+
+###
+# keystore.trusty is the HAL used by keystore on Trusty devices.
+##
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := keystore.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := module.cpp \
+	trusty_keymaster_ipc.c \
+	trusty_keymaster_device.cpp
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+	libcrypto \
+	libkeymaster_messages \
+	libtrusty \
+	liblog \
+	libcutils
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/keymaster/Makefile b/trusty/keymaster/Makefile
new file mode 100644
index 0000000..f575381
--- /dev/null
+++ b/trusty/keymaster/Makefile
@@ -0,0 +1,199 @@
+#####
+# Local unit test Makefile
+#
+# This makefile builds and runs the trusty_keymaster unit tests locally on the development
+# machine, not on an Android device.
+#
+# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
+# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
+# To get and build it, first install the Ninja build tool (e.g. apt-get install
+# ninja-build), then do:
+#
+# cd $ANDROID_BUILD_TOP/..
+# git clone https://boringssl.googlesource.com/boringssl
+# cd boringssl
+# mdkir build
+# cd build
+# cmake -GNinja ..
+# ninja
+#
+# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
+#####
+
+BASE=../../../..
+SUBS=system/core \
+	system/keymaster \
+	hardware/libhardware \
+	external/gtest
+GTEST=$(BASE)/external/gtest
+KM=$(BASE)/system/keymaster
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+	-I $(BASE)/libnativehelper/include/nativehelper \
+	-I ../tipc/include \
+	-I $(BASE)/system/keymaster \
+	-I $(GTEST) \
+	-I$(BASE)/../boringssl/include
+
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
+COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
+else
+COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
+endif
+
+CPPFLAGS=$(INCLUDES) -g -O0 -MD
+CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith	-Wunused-parameter \
+	-Wmissing-declarations -ftest-coverage \
+	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
+	$(COMPILER_SPECIFIC_ARGS)
+LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++
+
+CPPSRCS=\
+	$(KM)/aead_mode_operation.cpp \
+	$(KM)/aes_key.cpp \
+	$(KM)/aes_operation.cpp \
+	$(KM)/android_keymaster.cpp \
+	$(KM)/android_keymaster_messages.cpp \
+	$(KM)/android_keymaster_messages_test.cpp \
+	$(KM)/android_keymaster_test.cpp \
+	$(KM)/android_keymaster_test_utils.cpp \
+	$(KM)/android_keymaster_utils.cpp \
+	$(KM)/asymmetric_key.cpp \
+	$(KM)/auth_encrypted_key_blob.cpp \
+	$(KM)/auth_encrypted_key_blob.cpp \
+	$(KM)/authorization_set.cpp \
+	$(KM)/authorization_set_test.cpp \
+	$(KM)/ec_key.cpp \
+	$(KM)/ec_keymaster0_key.cpp \
+	$(KM)/ecdsa_operation.cpp \
+	$(KM)/hmac_key.cpp \
+	$(KM)/hmac_operation.cpp \
+	$(KM)/integrity_assured_key_blob.cpp \
+	$(KM)/key.cpp \
+	$(KM)/key_blob_test.cpp \
+	$(KM)/keymaster0_engine.cpp \
+	$(KM)/logger.cpp \
+	$(KM)/ocb_utils.cpp \
+	$(KM)/openssl_err.cpp \
+	$(KM)/openssl_utils.cpp \
+	$(KM)/operation.cpp \
+	$(KM)/operation_table.cpp \
+	$(KM)/rsa_key.cpp \
+	$(KM)/rsa_keymaster0_key.cpp \
+	$(KM)/rsa_operation.cpp \
+	$(KM)/serializable.cpp \
+	$(KM)/soft_keymaster_context.cpp \
+	$(KM)/symmetric_key.cpp \
+	$(KM)/unencrypted_key_blob.cpp \
+	trusty_keymaster_device.cpp \
+	trusty_keymaster_device_test.cpp
+CCSRCS=$(GTEST)/src/gtest-all.cc
+CSRCS=ocb.c
+
+OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
+DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
+GCDA=$(CPPSRCS:.cpp=.gcda) $(CCSRCS:.cc=.gcda) $(CSRCS:.c=.gcda)
+GCNO=$(CPPSRCS:.cpp=.gcno) $(CCSRCS:.cc=.gcno) $(CSRCS:.c=.gcno)
+
+LINK.o=$(LINK.cc)
+
+BINARIES=trusty_keymaster_device_test
+
+ifdef TRUSTY
+BINARIES += trusty_keymaster_device_test
+endif # TRUSTY
+
+.PHONY: coverage memcheck massif clean run
+
+%.run: %
+	./$<
+	touch $@
+
+run: $(BINARIES:=.run)
+
+coverage: coverage.info
+	genhtml coverage.info --output-directory coverage
+
+coverage.info: run
+	lcov --capture --directory=. --output-file coverage.info
+
+%.coverage : %
+	$(MAKE) clean && $(MAKE) $<
+	./$<
+	lcov --capture --directory=. --output-file coverage.info
+	genhtml coverage.info --output-directory coverage
+
+#UNINIT_OPTS=--track-origins=yes
+UNINIT_OPTS=--undef-value-errors=no
+
+MEMCHECK_OPTS=--leak-check=full \
+	--show-reachable=yes \
+	--vgdb=full \
+	$(UNINIT_OPTS) \
+	--error-exitcode=1
+
+MASSIF_OPTS=--tool=massif \
+	--stacks=yes
+
+%.memcheck : %
+	valgrind $(MEMCHECK_OPTS) ./$< && \
+	touch $@
+
+%.massif : %
+	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
+
+memcheck: $(BINARIES:=.memcheck)
+
+massif: $(BINARIES:=.massif)
+
+trusty_keymaster_device_test: trusty_keymaster_device_test.o \
+	trusty_keymaster_device.o \
+	$(KM)/aead_mode_operation.o \
+	$(KM)/aes_key.o \
+	$(KM)/aes_operation.o \
+	$(KM)/android_keymaster.o \
+	$(KM)/android_keymaster_messages.o \
+	$(KM)/android_keymaster_test_utils.o \
+	$(KM)/android_keymaster_utils.o \
+	$(KM)/asymmetric_key.o \
+	$(KM)/auth_encrypted_key_blob.o \
+	$(KM)/auth_encrypted_key_blob.o \
+	$(KM)/authorization_set.o \
+	$(KM)/ec_key.o \
+	$(KM)/ec_keymaster0_key.cpp \
+	$(KM)/ecdsa_operation.o \
+	$(KM)/hmac_key.o \
+	$(KM)/hmac_operation.o \
+	$(KM)/integrity_assured_key_blob.o \
+	$(KM)/key.o \
+	$(KM)/keymaster0_engine.o \
+	$(KM)/logger.o \
+	$(KM)/ocb.o \
+	$(KM)/ocb_utils.o \
+	$(KM)/openssl_err.o \
+	$(KM)/openssl_utils.o \
+	$(KM)/operation.o \
+	$(KM)/operation_table.o \
+	$(KM)/rsa_key.o \
+	$(KM)/rsa_keymaster0_key.o \
+	$(KM)/rsa_operation.o \
+	$(KM)/serializable.o \
+	$(KM)/soft_keymaster_context.o \
+	$(KM)/symmetric_key.o \
+	$(GTEST)/src/gtest-all.o
+
+$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
+ocb.o: CFLAGS=$(CLANG_TEST_DEFINE)
+
+clean:
+	rm -f $(OBJS) $(DEPS) $(GCDA) $(GCNO) $(BINARIES) \
+		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
+		coverage.info
+	rm -rf coverage
+
+-include $(CPPSRCS:.cpp=.d)
+-include $(CCSRCS:.cc=.d)
+
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/keymaster_ipc.h
new file mode 100644
index 0000000..48fa53d
--- /dev/null
+++ b/trusty/keymaster/keymaster_ipc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define KEYMASTER_PORT "com.android.trusty.keymaster"
+#define KEYMASTER_MAX_BUFFER_LENGTH 4096
+
+// Commands
+enum keymaster_command {
+	KEYMASTER_RESP_BIT              = 1,
+	KEYMASTER_REQ_SHIFT             = 1,
+
+    KM_GENERATE_KEY                 = (0 << KEYMASTER_REQ_SHIFT),
+    KM_BEGIN_OPERATION              = (1 << KEYMASTER_REQ_SHIFT),
+    KM_UPDATE_OPERATION             = (2 << KEYMASTER_REQ_SHIFT),
+    KM_FINISH_OPERATION             = (3 << KEYMASTER_REQ_SHIFT),
+    KM_ABORT_OPERATION              = (4 << KEYMASTER_REQ_SHIFT),
+    KM_IMPORT_KEY                   = (5 << KEYMASTER_REQ_SHIFT),
+    KM_EXPORT_KEY                   = (6 << KEYMASTER_REQ_SHIFT),
+    KM_GET_VERSION                  = (7 << KEYMASTER_REQ_SHIFT),
+    KM_ADD_RNG_ENTROPY              = (8 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_ALGORITHMS     = (9 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_BLOCK_MODES    = (10 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_PADDING_MODES  = (11 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_DIGESTS        = (12 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT),
+    KM_GET_KEY_CHARACTERISTICS      = (15 << KEYMASTER_REQ_SHIFT),
+};
+
+#ifdef __ANDROID__
+
+/**
+ * keymaster_message - Serial header for communicating with KM server
+ * @cmd: the command, one of keymaster_command.
+ * @payload: start of the serialized command specific payload
+ */
+struct keymaster_message {
+	uint32_t cmd;
+	uint8_t payload[0];
+};
+
+#endif
diff --git a/trusty/keymaster/module.cpp b/trusty/keymaster/module.cpp
new file mode 100644
index 0000000..81597d9
--- /dev/null
+++ b/trusty/keymaster/module.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <string.h>
+
+#include <hardware/hardware.h>
+#include <hardware/keymaster0.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+/*
+ * Generic device handling
+ */
+static int trusty_keymaster_open(const hw_module_t* module, const char* name,
+                                 hw_device_t** device) {
+    if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
+        return -EINVAL;
+
+    TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
+    if (dev == NULL)
+        return -ENOMEM;
+    *device = dev->hw_device();
+    // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
+    // exist until then.
+    return 0;
+}
+
+static struct hw_module_methods_t keystore_module_methods = {
+    .open = trusty_keymaster_open,
+};
+
+struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+    .common =
+        {
+         .tag = HARDWARE_MODULE_TAG,
+         .module_api_version = KEYMASTER_MODULE_API_VERSION_0_3,
+         .hal_api_version = HARDWARE_HAL_API_VERSION,
+         .id = KEYSTORE_HARDWARE_MODULE_ID,
+         .name = "Trusty Keymaster HAL",
+         .author = "The Android Open Source Project",
+         .methods = &keystore_module_methods,
+         .dso = 0,
+         .reserved = {},
+        },
+};
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
new file mode 100644
index 0000000..069b4fe
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "trusty_keymaster_device.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+
+#include <type_traits>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#define LOG_TAG "TrustyKeymaster"
+#include <cutils/log.h>
+#include <hardware/keymaster0.h>
+
+#include <keymaster/authorization_set.h>
+
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+namespace keymaster {
+
+static keymaster_error_t translate_error(int err) {
+    switch (err) {
+    case 0:
+        return KM_ERROR_OK;
+    case -EPERM:
+    case -EACCES:
+        return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+
+    case -ECANCELED:
+        return KM_ERROR_OPERATION_CANCELLED;
+
+    case -ENODEV:
+        return KM_ERROR_UNIMPLEMENTED;
+
+    case -ENOMEM:
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    case -EBUSY:
+        return KM_ERROR_SECURE_HW_BUSY;
+
+    case -EIO:
+        return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+
+    case -EOVERFLOW:
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
+    static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
+                  "TrustyKeymasterDevice must be standard layout");
+    static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
+                  "device_ must be the first member of KeymasterOpenSsl");
+    static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
+                  "common must be the first member of keymaster_device");
+
+    ALOGI("Creating device");
+    ALOGD("Device address: %p", this);
+
+    memset(&device_, 0, sizeof(device_));
+
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = const_cast<hw_module_t*>(module);
+    device_.common.close = close_device;
+
+    device_.flags = KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
+
+    device_.generate_keypair = generate_keypair;
+    device_.import_keypair = import_keypair;
+    device_.get_keypair_public = get_keypair_public;
+    device_.delete_keypair = NULL;
+    device_.delete_all = NULL;
+    device_.sign_data = sign_data;
+    device_.verify_data = verify_data;
+
+    device_.context = NULL;
+
+    int rc = trusty_keymaster_connect();
+    error_ = translate_error(rc);
+    if (rc < 0) {
+        ALOGE("failed to connect to keymaster (%d)", rc);
+        return;
+    }
+
+    GetVersionRequest version_request;
+    GetVersionResponse version_response;
+    error_ = Send(version_request, &version_response);
+    if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
+        ALOGI("\"Bad parameters\" error on GetVersion call.  Assuming version 0.");
+        message_version_ = 0;
+        error_ = KM_ERROR_OK;
+    }
+    message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
+                                      version_response.subminor_ver);
+    if (message_version_ < 0) {
+        // Can't translate version?  Keymaster implementation must be newer.
+        ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
+              version_response.minor_ver, version_response.subminor_ver);
+        error_ = KM_ERROR_VERSION_MISMATCH;
+    }
+}
+
+TrustyKeymasterDevice::~TrustyKeymasterDevice() {
+    trusty_keymaster_disconnect();
+}
+
+const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
+
+int TrustyKeymasterDevice::generate_keypair(const keymaster_keypair_t key_type,
+                                            const void* key_params, uint8_t** key_blob,
+                                            size_t* key_blob_length) {
+    ALOGD("Device received generate_keypair");
+
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    GenerateKeyRequest req(message_version_);
+    StoreNewKeyParams(&req.key_description);
+
+    switch (key_type) {
+    case TYPE_RSA: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        const keymaster_rsa_keygen_params_t* rsa_params =
+            static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
+        ALOGD("Generating RSA pair, modulus size: %u, public exponent: %lu",
+              rsa_params->modulus_size, rsa_params->public_exponent);
+        req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
+        req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
+        break;
+    }
+
+    case TYPE_EC: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+        const keymaster_ec_keygen_params_t* ec_params =
+            static_cast<const keymaster_ec_keygen_params_t*>(key_params);
+        ALOGD("Generating ECDSA pair, key size: %u", ec_params->field_size);
+        req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
+        break;
+    }
+    default:
+        ALOGD("Received request for unsuported key type %d", key_type);
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    GenerateKeyResponse rsp(message_version_);
+    ALOGD("Sending generate request");
+    keymaster_error_t err = Send(req, &rsp);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Got error %d from send", err);
+        return err;
+    }
+
+    *key_blob_length = rsp.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
+    ALOGD("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+struct EVP_PKEY_Delete {
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct PKCS8_PRIV_KEY_INFO_Delete {
+    void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
+};
+
+int TrustyKeymasterDevice::import_keypair(const uint8_t* key, const size_t key_length,
+                                          uint8_t** key_blob, size_t* key_blob_length) {
+    ALOGD("Device received import_keypair");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    if (!key)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob || !key_blob_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    ImportKeyRequest request(message_version_);
+    StoreNewKeyParams(&request.key_description);
+    keymaster_algorithm_t algorithm;
+    keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
+    if (err != KM_ERROR_OK)
+        return err;
+    request.key_description.push_back(TAG_ALGORITHM, algorithm);
+
+    request.SetKeyMaterial(key, key_length);
+    request.key_format = KM_KEY_FORMAT_PKCS8;
+    ImportKeyResponse response(message_version_);
+    err = Send(request, &response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    *key_blob_length = response.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
+    printf("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+                                                              keymaster_algorithm_t* algorithm) {
+    if (key == NULL) {
+        ALOGE("No key specified for import");
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    }
+
+    UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
+        d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
+    if (pkcs8.get() == NULL) {
+        ALOGE("Could not parse PKCS8 key blob");
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
+    if (pkey.get() == NULL) {
+        ALOGE("Could not extract key from PKCS8 key blob");
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    switch (EVP_PKEY_type(pkey->type)) {
+    case EVP_PKEY_RSA:
+        *algorithm = KM_ALGORITHM_RSA;
+        break;
+    case EVP_PKEY_EC:
+        *algorithm = KM_ALGORITHM_EC;
+        break;
+    default:
+        ALOGE("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+                                              uint8_t** x509_data, size_t* x509_data_length) {
+    ALOGD("Device received get_keypair_public");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    ExportKeyRequest request(message_version_);
+    request.SetKeyMaterial(key_blob, key_blob_length);
+    request.key_format = KM_KEY_FORMAT_X509;
+    ExportKeyResponse response(message_version_);
+    keymaster_error_t err = Send(request, &response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    *x509_data_length = response.key_data_length;
+    *x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
+    memcpy(*x509_data, response.key_data, *x509_data_length);
+    printf("Returning %d bytes in x509 key\n", (int)*x509_data_length);
+
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::sign_data(const void* signing_params, const uint8_t* key_blob,
+                                     const size_t key_blob_length, const uint8_t* data,
+                                     const size_t data_length, uint8_t** signed_data,
+                                     size_t* signed_data_length) {
+    ALOGD("Device received sign_data, %d", error_);
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    BeginOperationRequest begin_request(message_version_);
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+                                               &begin_request.additional_params);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error extracting signing params: %d", err);
+        return err;
+    }
+
+    BeginOperationResponse begin_response(message_version_);
+    ALOGD("Sending signing request begin");
+    err = Send(begin_request, &begin_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign begin: %d", err);
+        return err;
+    }
+
+    UpdateOperationRequest update_request(message_version_);
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(data, data_length);
+    UpdateOperationResponse update_response(message_version_);
+    ALOGD("Sending signing request update");
+    err = Send(update_request, &update_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign update: %d", err);
+        return err;
+    }
+
+    FinishOperationRequest finish_request(message_version_);
+    finish_request.op_handle = begin_response.op_handle;
+    FinishOperationResponse finish_response(message_version_);
+    ALOGD("Sending signing request finish");
+    err = Send(finish_request, &finish_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign finish: %d", err);
+        return err;
+    }
+
+    *signed_data_length = finish_response.output.available_read();
+    *signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
+    if (!finish_response.output.read(*signed_data, *signed_data_length)) {
+        ALOGE("Error reading response data: %d", err);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::verify_data(const void* signing_params, const uint8_t* key_blob,
+                                       const size_t key_blob_length, const uint8_t* signed_data,
+                                       const size_t signed_data_length, const uint8_t* signature,
+                                       const size_t signature_length) {
+    ALOGD("Device received verify_data");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    BeginOperationRequest begin_request(message_version_);
+    begin_request.purpose = KM_PURPOSE_VERIFY;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+                                               &begin_request.additional_params);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    BeginOperationResponse begin_response(message_version_);
+    err = Send(begin_request, &begin_response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    UpdateOperationRequest update_request(message_version_);
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(signed_data, signed_data_length);
+    UpdateOperationResponse update_response(message_version_);
+    err = Send(update_request, &update_response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    FinishOperationRequest finish_request(message_version_);
+    finish_request.op_handle = begin_response.op_handle;
+    finish_request.signature.Reinitialize(signature, signature_length);
+    FinishOperationResponse finish_response(message_version_);
+    err = Send(finish_request, &finish_response);
+    if (err != KM_ERROR_OK)
+        return err;
+    return KM_ERROR_OK;
+}
+
+hw_device_t* TrustyKeymasterDevice::hw_device() {
+    return &device_.common;
+}
+
+static inline TrustyKeymasterDevice* convert_device(const keymaster0_device_t* dev) {
+    return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster0_device_t*>(dev));
+}
+
+/* static */
+int TrustyKeymasterDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<TrustyKeymasterDevice*>(dev);
+    return 0;
+}
+
+/* static */
+int TrustyKeymasterDevice::generate_keypair(const keymaster0_device_t* dev,
+                                            const keymaster_keypair_t key_type,
+                                            const void* key_params, uint8_t** keyBlob,
+                                            size_t* keyBlobLength) {
+    ALOGD("Generate keypair, sending to device: %p", convert_device(dev));
+    return convert_device(dev)->generate_keypair(key_type, key_params, keyBlob, keyBlobLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+                                          const size_t key_length, uint8_t** key_blob,
+                                          size_t* key_blob_length) {
+    return convert_device(dev)->import_keypair(key, key_length, key_blob, key_blob_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::get_keypair_public(const keymaster0_device_t* dev,
+                                              const uint8_t* key_blob, const size_t key_blob_length,
+                                              uint8_t** x509_data, size_t* x509_data_length) {
+    return convert_device(dev)
+        ->get_keypair_public(key_blob, key_blob_length, x509_data, x509_data_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::sign_data(const keymaster0_device_t* dev, const void* params,
+                                     const uint8_t* keyBlob, const size_t keyBlobLength,
+                                     const uint8_t* data, const size_t dataLength,
+                                     uint8_t** signedData, size_t* signedDataLength) {
+    return convert_device(dev)
+        ->sign_data(params, keyBlob, keyBlobLength, data, dataLength, signedData, signedDataLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::verify_data(const keymaster0_device_t* dev, const void* params,
+                                       const uint8_t* keyBlob, const size_t keyBlobLength,
+                                       const uint8_t* signedData, const size_t signedDataLength,
+                                       const uint8_t* signature, const size_t signatureLength) {
+    return convert_device(dev)->verify_data(params, keyBlob, keyBlobLength, signedData,
+                                            signedDataLength, signature, signatureLength);
+}
+
+keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
+                                              KeymasterResponse* rsp) {
+    uint32_t req_size = req.SerializedSize();
+    if (req_size > SEND_BUF_SIZE)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    uint8_t send_buf[SEND_BUF_SIZE];
+    Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
+    req.Serialize(send_buf, send_buf + req_size);
+
+    // Send it
+    uint8_t recv_buf[RECV_BUF_SIZE];
+    Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
+    uint32_t rsp_size = RECV_BUF_SIZE;
+    printf("Sending %d byte request\n", (int)req.SerializedSize());
+    int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
+    if (rc < 0) {
+        ALOGE("tipc error: %d\n", rc);
+        // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+        return translate_error(rc);
+    } else {
+        ALOGV("Received %d byte response\n", rsp_size);
+    }
+
+    const keymaster_message* msg = (keymaster_message *) recv_buf;
+    const uint8_t *p = msg->payload;
+    if (!rsp->Deserialize(&p, p + rsp_size)) {
+        ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+        return KM_ERROR_UNKNOWN_ERROR;
+    } else if (rsp->error != KM_ERROR_OK) {
+        ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+        return rsp->error;
+    }
+    return rsp->error;
+}
+
+keymaster_error_t TrustyKeymasterDevice::StoreSigningParams(const void* signing_params,
+                                                            const uint8_t* key_blob,
+                                                            size_t key_blob_length,
+                                                            AuthorizationSet* auth_set) {
+    uint8_t* pub_key_data;
+    size_t pub_key_data_length;
+    int err = get_keypair_public(&device_, key_blob, key_blob_length, &pub_key_data,
+                                 &pub_key_data_length);
+    if (err < 0) {
+        ALOGE("Error %d extracting public key to determine algorithm", err);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+    UniquePtr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
+
+    const uint8_t* p = pub_key_data;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length));
+
+    switch (EVP_PKEY_type(pkey->type)) {
+    case EVP_PKEY_RSA: {
+        const keymaster_rsa_sign_params_t* rsa_params =
+            reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
+        if (rsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (rsa_params->padding_type != PADDING_NONE)
+            return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+        if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE) ||
+            !auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    case EVP_PKEY_EC: {
+        const keymaster_ec_sign_params_t* ecdsa_params =
+            reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
+        if (ecdsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    default:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+    return KM_ERROR_OK;
+}
+
+void TrustyKeymasterDevice::StoreNewKeyParams(AuthorizationSet* auth_set) {
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+    auth_set->push_back(TAG_ALL_USERS);
+    auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+    uint64_t now = java_time(time(NULL));
+    auth_set->push_back(TAG_CREATION_DATETIME, now);
+    auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
+    if (message_version_ == 0) {
+        auth_set->push_back(TAG_DIGEST_OLD, KM_DIGEST_NONE);
+        auth_set->push_back(TAG_PADDING_OLD, KM_PAD_NONE);
+    } else {
+        auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+        auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+    }
+}
+
+}  // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_device.h b/trusty/keymaster/trusty_keymaster_device.h
new file mode 100644
index 0000000..cb74386
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#define EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "keymaster_ipc.h"
+
+namespace keymaster {
+
+/**
+ * Software OpenSSL-based Keymaster device.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class TrustyKeymasterDevice {
+  public:
+    /*
+     * These are the only symbols that will be exported by libtrustykeymaster.  All functionality
+     * can be reached via the function pointers in device_.
+     */
+    __attribute__((visibility("default"))) TrustyKeymasterDevice(const hw_module_t* module);
+    __attribute__((visibility("default"))) hw_device_t* hw_device();
+
+    ~TrustyKeymasterDevice();
+
+    keymaster_error_t session_error() { return error_; }
+
+    int generate_keypair(const keymaster_keypair_t key_type, const void* key_params,
+                         uint8_t** key_blob, size_t* key_blob_length);
+    int import_keypair(const uint8_t* key, const size_t key_length, uint8_t** key_blob,
+                       size_t* key_blob_length);
+    int get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+                           uint8_t** x509_data, size_t* x509_data_length);
+    int sign_data(const void* signing_params, const uint8_t* key_blob, const size_t key_blob_length,
+                  const uint8_t* data, const size_t data_length, uint8_t** signed_data,
+                  size_t* signed_data_length);
+    int verify_data(const void* signing_params, const uint8_t* key_blob,
+                    const size_t key_blob_length, const uint8_t* signed_data,
+                    const size_t signed_data_length, const uint8_t* signature,
+                    const size_t signature_length);
+
+  private:
+    keymaster_error_t Send(uint32_t command, const Serializable& request,
+                           KeymasterResponse* response);
+    keymaster_error_t Send(const GenerateKeyRequest& request, GenerateKeyResponse* response) {
+        return Send(KM_GENERATE_KEY, request, response);
+    }
+    keymaster_error_t Send(const BeginOperationRequest& request, BeginOperationResponse* response) {
+        return Send(KM_BEGIN_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const UpdateOperationRequest& request,
+                           UpdateOperationResponse* response) {
+        return Send(KM_UPDATE_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const FinishOperationRequest& request,
+                           FinishOperationResponse* response) {
+        return Send(KM_FINISH_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const ImportKeyRequest& request, ImportKeyResponse* response) {
+        return Send(KM_IMPORT_KEY, request, response);
+    }
+    keymaster_error_t Send(const ExportKeyRequest& request, ExportKeyResponse* response) {
+        return Send(KM_EXPORT_KEY, request, response);
+    }
+    keymaster_error_t Send(const GetVersionRequest& request, GetVersionResponse* response) {
+        return Send(KM_GET_VERSION, request, response);
+    }
+
+    keymaster_error_t StoreSigningParams(const void* signing_params, const uint8_t* key_blob,
+                                         size_t key_blob_length, AuthorizationSet* auth_set);
+    void StoreNewKeyParams(AuthorizationSet* auth_set);
+    keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+                                           keymaster_algorithm_t* algorithm);
+
+    /*
+     * These static methods are the functions referenced through the function pointers in
+     * keymaster_device.  They're all trivial wrappers.
+     */
+    static int close_device(hw_device_t* dev);
+    static int generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
+                                const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
+    static int import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+                              const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
+    static int get_keypair_public(const keymaster0_device_t* dev, const uint8_t* key_blob,
+                                  const size_t key_blob_length, uint8_t** x509_data,
+                                  size_t* x509_data_length);
+    static int sign_data(const keymaster0_device_t* dev, const void* signing_params,
+                         const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
+                         const size_t data_length, uint8_t** signed_data,
+                         size_t* signed_data_length);
+    static int verify_data(const keymaster0_device_t* dev, const void* signing_params,
+                           const uint8_t* key_blob, const size_t key_blob_length,
+                           const uint8_t* signed_data, const size_t signed_data_length,
+                           const uint8_t* signature, const size_t signature_length);
+
+    keymaster0_device_t device_;
+    keymaster_error_t error_;
+    int32_t message_version_;
+};
+
+}  // namespace keymaster
+
+#endif  // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
new file mode 100644
index 0000000..3bb5430
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <algorithm>
+#include <fstream>
+
+#include <UniquePtr.h>
+#include <gtest/gtest.h>
+#include <openssl/engine.h>
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "android_keymaster_test_utils.h"
+#include "trusty_keymaster_device.h"
+#include "openssl_utils.h"
+
+using std::string;
+using std::ifstream;
+using std::istreambuf_iterator;
+
+static keymaster::AndroidKeymaster *impl_ =  nullptr;
+
+extern "C" {
+int __android_log_print();
+}
+
+int __android_log_print() {
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+    // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+    CRYPTO_cleanup_all_ex_data();
+    ERR_free_strings();
+    return result;
+}
+
+int trusty_keymaster_connect() {
+    impl_ = new keymaster::AndroidKeymaster(new keymaster::SoftKeymasterContext(nullptr), 16);
+}
+
+void trusty_keymaster_disconnect() {
+    delete static_cast<keymaster::AndroidKeymaster*>(priv_);
+}
+
+template <typename Req, typename Rsp>
+static int fake_call(keymaster::AndroidKeymaster* device,
+                       void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
+                       uint32_t in_size, void* out_buf, uint32_t* out_size) {
+    Req req;
+    const uint8_t* in = static_cast<uint8_t*>(in_buf);
+    req.Deserialize(&in, in + in_size);
+    Rsp rsp;
+    (device->*method)(req, &rsp);
+
+    *out_size = rsp.SerializedSize();
+    uint8_t* out = static_cast<uint8_t*>(out_buf);
+    rsp.Serialize(out, out + *out_size);
+    return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
+                       uint32_t* out_size) {
+    switch (cmd) {
+    case KM_GENERATE_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_BEGIN_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_UPDATE_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_FINISH_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_IMPORT_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size, out_buf,
+                           out_size);
+    case KM_EXPORT_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size, out_buf,
+                           out_size);
+    }
+    return -EINVAL;
+
+}
+
+namespace keymaster {
+namespace test {
+
+class TrustyKeymasterTest : public testing::Test {
+  protected:
+    TrustyKeymasterTest() : device(NULL) {}
+
+    keymaster_rsa_keygen_params_t build_rsa_params() {
+        keymaster_rsa_keygen_params_t rsa_params;
+        rsa_params.public_exponent = 65537;
+        rsa_params.modulus_size = 2048;
+        return rsa_params;
+    }
+
+    uint8_t* build_message(size_t length) {
+        uint8_t* msg = new uint8_t[length];
+        memset(msg, 'a', length);
+        return msg;
+    }
+
+    size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
+        switch (params.key_size) {
+        case 256:
+        case 1024:
+            return 48;
+        case 2048:
+        case 4096:
+            return 72;
+        default:
+            // Oops.
+            return 0;
+        }
+    }
+
+    TrustyKeymasterDevice device;
+};
+
+class Malloc_Delete {
+  public:
+    Malloc_Delete(void* p) : p_(p) {}
+    ~Malloc_Delete() { free(p_); }
+
+  private:
+    void* p_;
+};
+
+typedef TrustyKeymasterTest KeyGenTest;
+TEST_F(KeyGenTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+}
+
+TEST_F(KeyGenTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t ec_params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &ec_params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+}
+
+typedef TrustyKeymasterTest SigningTest;
+TEST_F(SigningTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(message_len, siglen);
+}
+
+TEST_F(SigningTest, RsaShortMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8 - 1;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+                                                       message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, RsaLongMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8 + 1;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+                                                       message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaEmptyMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaLargeMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    size_t message_len = 1024 * 7;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    // contents of message don't matter.
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+typedef TrustyKeymasterTest VerificationTest;
+TEST_F(VerificationTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+                                              signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadSignature) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+
+    Malloc_Delete sig_deleter(signature);
+    signature[siglen / 2]++;
+    EXPECT_EQ(
+        KM_ERROR_VERIFICATION_FAILED,
+        device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    message[0]++;
+    EXPECT_EQ(
+        KM_ERROR_VERIFICATION_FAILED,
+        device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaShortMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+              device.verify_data(&sig_params, ptr, size, message.get(), message_len - 1, signature,
+                                 siglen));
+}
+
+TEST_F(VerificationTest, RsaLongMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len + 1));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+              device.verify_data(&sig_params, ptr, size, message.get(), message_len + 1, signature,
+                                 siglen));
+}
+
+TEST_F(VerificationTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message,
+                                              array_size(message) - 1, signature, siglen));
+}
+
+TEST_F(VerificationTest, EcdsaLargeMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    size_t message_len = 1024 * 7;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    // contents of message don't matter.
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+                                              signature, siglen));
+}
+
+static string read_file(const string& file_name) {
+    ifstream file_stream(file_name, std::ios::binary);
+    istreambuf_iterator<char> file_begin(file_stream);
+    istreambuf_iterator<char> file_end;
+    return string(file_begin, file_end);
+}
+
+typedef TrustyKeymasterTest ImportKeyTest;
+TEST_F(ImportKeyTest, RsaSuccess) {
+    string pk8_key = read_file("../../../../system/keymaster/rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
+
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+                                                 pk8_key.size(), &key, &size));
+    Malloc_Delete key_deleter(key);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_size = 1024 /* key size */ / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_size]);
+    memset(message.get(), 'a', message_size);
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message.get(), message_size,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message.get(), message_size,
+                                              signature, siglen));
+}
+
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+    string pk8_key = read_file("../../../../system/keymaster/ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+                                                 pk8_key.size(), &key, &size));
+    Malloc_Delete key_deleter(key);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+                                              array_size(message) - 1, signature, siglen));
+}
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
+                            size_t signature_len, const uint8_t* message, size_t message_len) {
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
+    ASSERT_TRUE(pkey.get() != NULL);
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    ASSERT_TRUE(ctx.get() != NULL);
+    ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
+    if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
+        ASSERT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING));
+    EXPECT_EQ(1, EVP_PKEY_verify(ctx.get(), signature, signature_len, message, message_len));
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    uint8_t* exported;
+    size_t exported_size;
+    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(ptr, size, &exported, &exported_size));
+    Malloc_Delete exported_deleter(exported);
+
+    // Sign a message so we can verify it with the exported pubkey.
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(message_len, siglen);
+    const uint8_t* tmp = exported;
+
+    VerifySignature(exported, exported_size, signature, siglen, message.get(), message_len);
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &key, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(key);
+
+    uint8_t* exported;
+    size_t exported_size;
+    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(key, size, &exported, &exported_size));
+    Malloc_Delete exported_deleter(exported);
+
+    // Sign a message so we can verify it with the exported pubkey.
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+                                              array_size(message) - 1, signature, siglen));
+
+    VerifySignature(exported, exported_size, signature, siglen, message, array_size(message) - 1);
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
new file mode 100644
index 0000000..b68209e
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO: make this generic in libtrusty
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyKeymaster"
+#include <cutils/log.h>
+
+#include <trusty/tipc.h>
+
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_keymaster_connect() {
+    int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+    if (rc < 0) {
+        return rc;
+    }
+
+    handle_ = rc;
+    return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                          uint32_t *out_size)  {
+    if (handle_ == 0) {
+        ALOGE("not connected\n");
+        return -EINVAL;
+    }
+
+    size_t msg_size = in_size + sizeof(struct keymaster_message);
+    struct keymaster_message *msg = malloc(msg_size);
+    msg->cmd = cmd;
+    memcpy(msg->payload, in, in_size);
+
+    ssize_t rc = write(handle_, msg, msg_size);
+    free(msg);
+
+    if (rc < 0) {
+        ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+                KEYMASTER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    rc = read(handle_, out, *out_size);
+    if (rc < 0) {
+        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+                cmd, KEYMASTER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    if ((size_t) rc < sizeof(struct keymaster_message)) {
+        ALOGE("invalid response size (%d)\n", (int) rc);
+        return -EINVAL;
+    }
+
+    msg = (struct keymaster_message *) out;
+
+    if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
+        ALOGE("invalid command (%d)", msg->cmd);
+        return -EINVAL;
+    }
+
+    *out_size = ((size_t) rc) - sizeof(struct keymaster_message);
+    return rc;
+}
+
+void trusty_keymaster_disconnect() {
+    if (handle_ != 0) {
+        tipc_close(handle_);
+    }
+}
+
diff --git a/libcutils/atomic.c b/trusty/keymaster/trusty_keymaster_ipc.h
similarity index 62%
copy from libcutils/atomic.c
copy to trusty/keymaster/trusty_keymaster_ipc.h
index d34aa00..9785247 100644
--- a/libcutils/atomic.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+__BEGIN_DECLS
 
-#define ANDROID_ATOMIC_INLINE
+int trusty_keymaster_connect(void);
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+         uint32_t *out_size);
+void trusty_keymaster_disconnect(void);
 
-#include <cutils/atomic.h>
+__END_DECLS
diff --git a/trusty/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
new file mode 100644
index 0000000..7ed880e
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_main.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+unsigned char rsa_privkey_pk8_der[] = {
+    0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
+    0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
+    0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
+    0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
+    0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
+    0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
+    0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
+    0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
+    0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
+    0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
+    0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
+    0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
+    0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
+    0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
+    0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
+    0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
+    0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
+    0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
+    0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
+    0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
+    0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
+    0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
+    0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
+    0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
+    0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
+    0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
+    0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
+    0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
+    0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
+    0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
+    0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
+    0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
+    0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
+    0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
+    0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
+    0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
+    0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
+    0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
+    0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
+unsigned int rsa_privkey_pk8_der_len = 633;
+
+unsigned char dsa_privkey_pk8_der[] = {
+    0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, 0x48,
+    0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3, 0xe9, 0xb6,
+    0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad, 0xbc, 0xc9, 0xd1,
+    0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8, 0xe0, 0x26, 0x44, 0x19,
+    0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde, 0xe5, 0x4f, 0x48, 0x15, 0x01,
+    0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8, 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c,
+    0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d, 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b,
+    0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2, 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7,
+    0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda, 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec,
+    0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24, 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb,
+    0xea, 0x17, 0xd2, 0x09, 0xb3, 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71,
+    0x68, 0xf7, 0xe3, 0x02, 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b,
+    0xf6, 0xcd, 0xd6, 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06,
+    0x88, 0xb1, 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8,
+    0x11, 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
+    0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80, 0xca,
+    0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62, 0x75, 0x8b,
+    0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf, 0x72, 0x9a, 0x67,
+    0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a, 0xba, 0x3b, 0xa8, 0x00,
+    0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00, 0x81, 0x9d, 0xfd, 0x53, 0x0c,
+    0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33, 0x91, 0x84, 0xbe, 0xad, 0x81};
+unsigned int dsa_privkey_pk8_der_len = 335;
+
+unsigned char ec_privkey_pk8_der[] = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+    0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
+    0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
+    0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
+    0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
+    0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
+    0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
+    0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
+    0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
+unsigned int ec_privkey_pk8_der_len = 138;
+
+struct EVP_PKEY_Delete {
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static bool test_import_rsa(TrustyKeymasterDevice* device) {
+    printf("===================\n");
+    printf("= RSA Import Test =\n");
+    printf("===================\n\n");
+
+    printf("=== Importing RSA keypair === \n");
+    uint8_t* key;
+    size_t size;
+    int error = device->import_keypair(rsa_privkey_pk8_der, rsa_privkey_pk8_der_len, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error importing key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> key_deleter(key);
+
+    printf("=== Signing with imported RSA key ===\n");
+    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = 1024 / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with imported RSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with imported RSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with imported RSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_rsa(TrustyKeymasterDevice* device) {
+    printf("============\n");
+    printf("= RSA Test =\n");
+    printf("============\n\n");
+
+    printf("=== Generating RSA key pair ===\n");
+    keymaster_rsa_keygen_params_t params;
+    params.public_exponent = 65537;
+    params.modulus_size = 2048;
+
+    uint8_t* key;
+    size_t size;
+    int error = device->generate_keypair(TYPE_RSA, &params, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error generating RSA key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with RSA key === \n");
+    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with RSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with RSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with RSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Exporting RSA public key ===\n");
+    uint8_t* exported_key;
+    size_t exported_size;
+    error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+    if (error != KM_ERROR_OK) {
+        printf("Error exporting RSA public key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Verifying with exported key ===\n");
+    const uint8_t* tmp = exported_key;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+        printf("Error initializing openss EVP context\n");
+        return false;
+    }
+    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+        printf("Exported key was the wrong type?!?\n");
+        return false;
+    }
+
+    EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+    if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+        printf("Verification with exported pubkey failed.\n");
+        return false;
+    } else {
+        printf("Verification succeeded\n");
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
+    printf("=====================\n");
+    printf("= ECDSA Import Test =\n");
+    printf("=====================\n\n");
+
+    printf("=== Importing ECDSA keypair === \n");
+    uint8_t* key;
+    size_t size;
+    int error = device->import_keypair(ec_privkey_pk8_der, ec_privkey_pk8_der_len, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error importing key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with imported ECDSA key ===\n");
+    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+    size_t message_len = 30 /* arbitrary */;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with imported ECDSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with imported ECDSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with imported ECDSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_ecdsa(TrustyKeymasterDevice* device) {
+    printf("==============\n");
+    printf("= ECDSA Test =\n");
+    printf("==============\n\n");
+
+    printf("=== Generating ECDSA key pair ===\n");
+    keymaster_ec_keygen_params_t params;
+    params.field_size = 521;
+    uint8_t* key;
+    size_t size;
+    int error = device->generate_keypair(TYPE_EC, &params, &key, &size);
+    if (error != 0) {
+        printf("Error generating ECDSA key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with ECDSA key === \n");
+    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+    size_t message_len = 30 /* arbitrary */;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with ECDSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with ECDSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with ECDSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Exporting ECDSA public key ===\n");
+    uint8_t* exported_key;
+    size_t exported_size;
+    error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+    if (error != KM_ERROR_OK) {
+        printf("Error exporting ECDSA public key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Verifying with exported key ===\n");
+    const uint8_t* tmp = exported_key;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+        printf("Error initializing openss EVP context\n");
+        return false;
+    }
+    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+        printf("Exported key was the wrong type?!?\n");
+        return false;
+    }
+
+    if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+        printf("Verification with exported pubkey failed.\n");
+        return false;
+    } else {
+        printf("Verification succeeded\n");
+    }
+
+    printf("\n");
+    return true;
+}
+
+int main(void) {
+
+    TrustyKeymasterDevice device(NULL);
+    if (device.session_error() != KM_ERROR_OK) {
+        printf("Failed to initialize Trusty session: %d\n", device.session_error());
+        return 1;
+    }
+    printf("Trusty session initialized\n");
+
+    bool success = true;
+    success &= test_rsa(&device);
+    success &= test_import_rsa(&device);
+    success &= test_ecdsa(&device);
+    success &= test_import_ecdsa(&device);
+
+    if (success) {
+        printf("\nTESTS PASSED!\n");
+    } else {
+        printf("\n!!!!TESTS FAILED!!!\n");
+    }
+
+    return success ? 0 : 1;
+}
diff --git a/trusty/storage/interface/Android.mk b/trusty/storage/interface/Android.mk
new file mode 100644
index 0000000..15cb6f3
--- /dev/null
+++ b/trusty/storage/interface/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libtrustystorageinterface
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
new file mode 100644
index 0000000..b196d88
--- /dev/null
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*
+ * Storage port names
+ * @STORAGE_CLIENT_TD_PORT:     Port used by clients that require tamper and
+ *                              rollback detection.
+ * @STORAGE_CLIENT_TDEA_PORT:   Port used by clients that require storage before
+ *                              the non-secure os has booted.
+ * @STORAGE_CLIENT_TP_PORT:     Port used by clients that require tamper proof
+ *                              storage. Note that non-secure code can prevent
+                                read and write operations from succeeding, but
+                                it cannot modify on-disk data.
+ * @STORAGE_DISK_PROXY_PORT:    Port used by non-secure proxy server
+ */
+#define STORAGE_CLIENT_TD_PORT     "com.android.trusty.storage.client.td"
+#define STORAGE_CLIENT_TDEA_PORT   "com.android.trusty.storage.client.tdea"
+#define STORAGE_CLIENT_TP_PORT     "com.android.trusty.storage.client.tp"
+#define STORAGE_DISK_PROXY_PORT    "com.android.trusty.storage.proxy"
+
+enum storage_cmd {
+	STORAGE_REQ_SHIFT = 1,
+	STORAGE_RESP_BIT  = 1,
+
+	STORAGE_RESP_MSG_ERR   = STORAGE_RESP_BIT,
+
+	STORAGE_FILE_DELETE    = 1 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_OPEN      = 2 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_CLOSE     = 3 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_READ      = 4 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_WRITE     = 5 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_GET_SIZE  = 6 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_SET_SIZE  = 7 << STORAGE_REQ_SHIFT,
+
+	STORAGE_RPMB_SEND      = 8 << STORAGE_REQ_SHIFT,
+
+	/* transaction support */
+	STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT,
+};
+
+/**
+ * enum storage_err - error codes for storage protocol
+ * @STORAGE_NO_ERROR:           all OK
+ * @STORAGE_ERR_GENERIC:        unknown error. Can occur when there's an internal server
+ *                              error, e.g. the server runs out of memory or is in a bad state.
+ * @STORAGE_ERR_NOT_VALID:      input not valid. May occur if the arguments passed
+ *                              into the command are not valid, for example if the file handle
+ *                              passed in is not a valid one.
+ * @STORAGE_ERR_UNIMPLEMENTED:  the command passed in is not recognized
+ * @STORAGE_ERR_ACCESS:         the file is not accessible in the requested mode
+ * @STORAGE_ERR_NOT_FOUND:      the file was not found
+ * @STORAGE_ERR_EXIST           the file exists when it shouldn't as in with OPEN_CREATE | OPEN_EXCLUSIVE.
+ * @STORAGE_ERR_TRANSACT        returned by various operations to indicate that current transaction
+ *                              is in error state. Such state could be only cleared by sending
+ *                              STORAGE_END_TRANSACTION message.
+ */
+enum storage_err {
+	STORAGE_NO_ERROR          = 0,
+	STORAGE_ERR_GENERIC       = 1,
+	STORAGE_ERR_NOT_VALID     = 2,
+	STORAGE_ERR_UNIMPLEMENTED = 3,
+	STORAGE_ERR_ACCESS        = 4,
+	STORAGE_ERR_NOT_FOUND     = 5,
+	STORAGE_ERR_EXIST         = 6,
+	STORAGE_ERR_TRANSACT      = 7,
+};
+
+/**
+ * storage_delete_flag - flags for controlling delete semantics
+ */
+enum storage_file_delete_flag {
+	STORAGE_FILE_DELETE_MASK = 0,
+};
+
+/**
+ * storage_file_flag - Flags to control 'open' semantics.
+ * @STORAGE_FILE_OPEN_CREATE:           if this file does not exist, create it.
+ * @STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: causes STORAGE_FILE_OPEN_CREATE to fail if the file
+ *                                      already exists. Only meaningful if used in combination
+ *                                      with STORAGE_FILE_OPEN_CREATE.
+ * @STORAGE_FILE_OPEN_TRUNCATE:         if this file already exists, discard existing content
+ *                                      and open it as a new file. No change in semantics if the
+ *                                      file does not exist.
+ * @STORAGE_FILE_OPEN_MASK:             mask for all open flags supported in current protocol.
+ *                                      All other bits must be set to 0.
+ */
+enum storage_file_open_flag {
+	STORAGE_FILE_OPEN_CREATE             = (1 << 0),
+	STORAGE_FILE_OPEN_CREATE_EXCLUSIVE   = (1 << 1),
+	STORAGE_FILE_OPEN_TRUNCATE           = (1 << 2),
+	STORAGE_FILE_OPEN_MASK               = STORAGE_FILE_OPEN_CREATE |
+					       STORAGE_FILE_OPEN_TRUNCATE |
+					       STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+};
+
+/**
+ * enum storage_msg_flag - protocol-level flags in struct storage_msg
+ * @STORAGE_MSG_FLAG_BATCH:             if set, command belongs to a batch transaction.
+ *                                      No response will be sent by the server until
+ *                                      it receives a command with this flag unset, at
+ *                                      which point a cummulative result for all messages
+ *                                      sent with STORAGE_MSG_FLAG_BATCH will be sent.
+ *                                      This is only supported by the non-secure disk proxy
+ *                                      server.
+ * @STORAGE_MSG_FLAG_PRE_COMMIT:        if set, indicates that server need to commit
+ *                                      pending changes before processing this message.
+ * @STORAGE_MSG_FLAG_POST_COMMIT:       if set, indicates that server need to commit
+ *                                      pending changes after processing this message.
+ * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit
+ *                                      current transaction after processing this message.
+ *                                      It is an alias for STORAGE_MSG_FLAG_POST_COMMIT.
+ */
+enum storage_msg_flag {
+	STORAGE_MSG_FLAG_BATCH = 0x1,
+	STORAGE_MSG_FLAG_PRE_COMMIT = 0x2,
+	STORAGE_MSG_FLAG_POST_COMMIT = 0x4,
+	STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT,
+};
+
+/*
+ * The following declarations are the message-specific contents of
+ * the 'payload' element inside struct storage_msg.
+ */
+
+/**
+ * struct storage_file_delete_req - request format for STORAGE_FILE_DELETE
+ * @flags: currently unused, must be set to 0.
+ * @name:  the name of the file
+ */
+struct storage_file_delete_req {
+	uint32_t flags;
+	char name[0];
+};
+
+/**
+ * struct storage_file_open_req - request format for STORAGE_FILE_OPEN
+ * @flags: any of enum storage_file_flag or'ed together
+ * @name:  the name of the file
+ */
+struct storage_file_open_req {
+	uint32_t flags;
+	char     name[0];
+};
+
+/**
+ * struct storage_file_open_resp - response format for STORAGE_FILE_OPEN
+ * @handle: opaque handle to the opened file. Only present on success.
+ */
+struct storage_file_open_resp {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_close_req - request format for STORAGE_FILE_CLOSE
+ * @handle: the handle for the file to close
+ */
+struct storage_file_close_req {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_read_req - request format for STORAGE_FILE_READ
+ * @handle: the handle for the file from which to read
+ * @size:   the quantity of bytes to read from the file
+ * @offset: the offset in the file from whence to read
+ */
+struct storage_file_read_req {
+	uint32_t handle;
+	uint32_t size;
+	uint64_t offset;
+};
+
+/**
+ * struct storage_file_read_resp - response format for STORAGE_FILE_READ
+ * @data: beginning of data retrieved from file
+ */
+struct storage_file_read_resp {
+	uint8_t data[0];
+};
+
+/**
+ * struct storage_file_write_req - request format for STORAGE_FILE_WRITE
+ * @handle:     the handle for the file to write to
+ * @offset:     the offset in the file from whence to write
+ * @__reserved: unused, must be set to 0.
+ * @data:       beginning of the data to be written
+ */
+struct storage_file_write_req {
+	uint64_t offset;
+	uint32_t handle;
+	uint32_t __reserved;
+	uint8_t  data[0];
+};
+
+/**
+ * struct storage_file_get_size_req - request format for STORAGE_FILE_GET_SIZE
+ * @handle: handle for which the size is requested
+ */
+struct storage_file_get_size_req {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_get_size_resp - response format for STORAGE_FILE_GET_SIZE
+ * @size:   the size of the file
+ */
+struct storage_file_get_size_resp {
+	uint64_t size;
+};
+
+/**
+ * struct storage_file_set_size_req - request format for STORAGE_FILE_SET_SIZE
+ * @handle: the file handle
+ * @size:   the desired size of the file
+ */
+struct storage_file_set_size_req {
+	uint64_t size;
+	uint32_t handle;
+};
+
+/**
+ * struct storage_rpmb_send_req - request format for STORAGE_RPMB_SEND
+ * @reliable_write_size:        size in bytes of reliable write region
+ * @write_size:                 size in bytes of write region
+ * @read_size:                  number of bytes to read for a read request
+ * @__reserved:                 unused, must be set to 0
+ * @payload:                    start of reliable write region, followed by
+ *                              write region.
+ *
+ * Only used in proxy<->server interface.
+ */
+struct storage_rpmb_send_req {
+	uint32_t reliable_write_size;
+	uint32_t write_size;
+	uint32_t read_size;
+	uint32_t __reserved;
+	uint8_t  payload[0];
+};
+
+/**
+ * struct storage_rpmb_send_resp: response type for STORAGE_RPMB_SEND
+ * @data: the data frames frames retrieved from the MMC.
+ */
+struct storage_rpmb_send_resp {
+	uint8_t data[0];
+};
+
+/**
+ * struct storage_msg - generic req/resp format for all storage commands
+ * @cmd:        one of enum storage_cmd
+ * @op_id:      client chosen operation identifier for an instance
+ *              of a command or atomic grouping of commands (transaction).
+ * @flags:      one or many of enum storage_msg_flag or'ed together.
+ * @size:       total size of the message including this header
+ * @result:     one of enum storage_err
+ * @__reserved: unused, must be set to 0.
+ * @payload:    beginning of command specific message format
+ */
+struct storage_msg {
+	uint32_t cmd;
+	uint32_t op_id;
+	uint32_t flags;
+	uint32_t size;
+	int32_t  result;
+	uint32_t __reserved;
+	uint8_t  payload[0];
+};
+
diff --git a/trusty/storage/proxy/Android.mk b/trusty/storage/proxy/Android.mk
new file mode 100644
index 0000000..9fc73d3
--- /dev/null
+++ b/trusty/storage/proxy/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2016 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := storageproxyd
+
+LOCAL_SRC_FILES := \
+	ipc.c \
+	rpmb.c \
+	storage.c \
+	proxy.c
+
+LOCAL_CLFAGS = -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+	libtrustystorageinterface \
+	libtrusty
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/trusty/storage/proxy/ipc.c b/trusty/storage/proxy/ipc.c
new file mode 100644
index 0000000..b4748e2
--- /dev/null
+++ b/trusty/storage/proxy/ipc.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <trusty/tipc.h>
+
+#include "ipc.h"
+#include "log.h"
+
+#define MAX_RECONNECT_RETRY_COUNT 5
+#define TRUSTY_RECONNECT_TIMEOUT_SEC 5
+
+static int tipc_fd = -1;
+
+int ipc_connect(const char *device, const char *port)
+{
+    int rc;
+    uint retry_cnt = 0;
+
+    assert(tipc_fd == -1);
+
+    while(true) {
+        rc = tipc_connect(device, port);
+        if (rc >= 0)
+            break;
+
+        ALOGE("failed (%d) to connect to storage server\n", rc);
+        if (++retry_cnt > MAX_RECONNECT_RETRY_COUNT) {
+            ALOGE("max number of reconnect retries (%d) has been reached\n",
+                   retry_cnt);
+            return -1;
+        }
+        sleep(TRUSTY_RECONNECT_TIMEOUT_SEC);
+    }
+    tipc_fd = rc;
+    return 0;
+}
+
+void ipc_disconnect(void)
+{
+    assert(tipc_fd >=  0);
+
+    tipc_close(tipc_fd);
+    tipc_fd = -1;
+}
+
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len)
+{
+    ssize_t rc;
+    struct iovec iovs[2] = {{msg, sizeof(*msg)}, {req_buf, req_buf_len}};
+
+    assert(tipc_fd >=  0);
+
+    rc = readv(tipc_fd, iovs, 2);
+    if (rc < 0) {
+        ALOGE("failed to read request: %s\n", strerror(errno));
+        return rc;
+    }
+
+   /* check for minimum size */
+   if ((size_t)rc < sizeof(*msg)) {
+       ALOGE("message is too short (%zu bytes received)\n", rc);
+       return -1;
+   }
+
+   /* check for message completeness */
+   if (msg->size != (uint32_t)rc) {
+       ALOGE("inconsistent message size [cmd=%d] (%u != %u)\n",
+             msg->cmd, msg->size, (uint32_t)rc);
+       return -1;
+   }
+
+   return rc - sizeof(*msg);
+}
+
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size)
+{
+    ssize_t rc;
+    struct iovec iovs[2] = {{msg, sizeof(*msg)}, {out, out_size}};
+
+    assert(tipc_fd >=  0);
+
+    msg->cmd |= STORAGE_RESP_BIT;
+
+    rc = writev(tipc_fd, iovs, out ? 2 : 1);
+    if (rc < 0) {
+        ALOGE("error sending response 0x%x: %s\n",
+              msg->cmd, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/ipc.h
similarity index 60%
copy from libcutils/atomic.c
copy to trusty/storage/proxy/ipc.h
index d34aa00..2e366bb 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/ipc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#include <stdint.h>
+#include <trusty/interface/storage.h>
 
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
+int ipc_connect(const char *device, const char *service_name);
+void ipc_disconnect(void);
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len);
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size);
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/log.h
similarity index 62%
copy from libcutils/atomic.c
copy to trusty/storage/proxy/log.h
index d34aa00..471cb50 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/log.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#define LOG_TAG "storageproxyd"
+#include <cutils/log.h>
 
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
new file mode 100644
index 0000000..d645ac0
--- /dev/null
+++ b/trusty/storage/proxy/proxy.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define REQ_BUFFER_SIZE 4096
+static uint8_t req_buffer[REQ_BUFFER_SIZE + 1];
+
+static const char *ss_data_root;
+static const char *trusty_devname;
+static const char *rpmb_devname;
+static const char *ss_srv_name = STORAGE_DISK_PROXY_PORT;
+
+static const char *_sopts = "hp:d:r:";
+static const struct option _lopts[] =  {
+    {"help",       no_argument,       NULL, 'h'},
+    {"trusty_dev", required_argument, NULL, 'd'},
+    {"data_path",  required_argument, NULL, 'p'},
+    {"rpmb_dev",   required_argument, NULL, 'r'},
+    {0, 0, 0, 0}
+};
+
+static void show_usage_and_exit(int code)
+{
+    ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev>\n");
+    exit(code);
+}
+
+static int drop_privs(void)
+{
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+
+    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
+        return -1;
+    }
+
+    /*
+     * ensure we're running as the system user
+     */
+    if (setgid(AID_SYSTEM) != 0) {
+        return -1;
+    }
+
+    if (setuid(AID_SYSTEM) != 0) {
+        return -1;
+    }
+
+    /*
+     * drop all capabilities except SYS_RAWIO
+     */
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted = CAP_TO_MASK(CAP_SYS_RAWIO);
+    capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective = CAP_TO_MASK(CAP_SYS_RAWIO);
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        return -1;
+    }
+
+    /* no-execute for user, no access for group and other */
+    umask(S_IXUSR | S_IRWXG | S_IRWXO);
+
+    return 0;
+}
+
+static int handle_req(struct storage_msg *msg, const void *req, size_t req_len)
+{
+    int rc;
+
+    if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) &&
+        (msg->cmd != STORAGE_RPMB_SEND)) {
+        /*
+         * handling post commit messages on non rpmb commands are not
+         * implemented as there is no use case for this yet.
+         */
+        ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
+        msg->result = STORAGE_ERR_UNIMPLEMENTED;
+        return ipc_respond(msg, NULL, 0);
+    }
+
+    if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
+        rc = storage_sync_checkpoint();
+        if (rc < 0) {
+            msg->result = STORAGE_ERR_GENERIC;
+            return ipc_respond(msg, NULL, 0);
+        }
+    }
+
+    switch (msg->cmd) {
+    case STORAGE_FILE_DELETE:
+        rc = storage_file_delete(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_OPEN:
+        rc = storage_file_open(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_CLOSE:
+        rc = storage_file_close(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_WRITE:
+        rc = storage_file_write(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_READ:
+        rc = storage_file_read(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_GET_SIZE:
+        rc = storage_file_get_size(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_SET_SIZE:
+        rc = storage_file_set_size(msg, req, req_len);
+        break;
+
+    case STORAGE_RPMB_SEND:
+        rc = rpmb_send(msg, req, req_len);
+        break;
+
+    default:
+        ALOGE("unhandled command 0x%x\n", msg->cmd);
+        msg->result = STORAGE_ERR_UNIMPLEMENTED;
+        rc = 1;
+    }
+
+    if (rc > 0) {
+        /* still need to send response */
+        rc = ipc_respond(msg, NULL, 0);
+    }
+    return rc;
+}
+
+static int proxy_loop(void)
+{
+    ssize_t rc;
+    struct storage_msg msg;
+
+    /* enter main message handling loop */
+    while (true) {
+
+        /* get incoming message */
+        rc = ipc_get_msg(&msg, req_buffer, REQ_BUFFER_SIZE);
+        if (rc < 0)
+            return rc;
+
+        /* handle request */
+        req_buffer[rc] = 0; /* force zero termination */
+        rc = handle_req(&msg, req_buffer, rc);
+        if (rc)
+            return rc;
+    }
+
+    return 0;
+}
+
+static void parse_args(int argc, char *argv[])
+{
+    int opt;
+    int oidx = 0;
+
+    while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
+        switch (opt) {
+
+        case 'd':
+            trusty_devname = strdup(optarg);
+            break;
+
+        case 'p':
+            ss_data_root = strdup(optarg);
+            break;
+
+        case 'r':
+            rpmb_devname = strdup(optarg);
+            break;
+
+        default:
+            ALOGE("unrecognized option (%c):\n", opt);
+            show_usage_and_exit(EXIT_FAILURE);
+        }
+    }
+
+    if (ss_data_root == NULL ||
+        trusty_devname == NULL ||
+        rpmb_devname == NULL) {
+        ALOGE("missing required argument(s)\n");
+        show_usage_and_exit(EXIT_FAILURE);
+    }
+
+    ALOGI("starting storageproxyd\n");
+    ALOGI("storage data root: %s\n", ss_data_root);
+    ALOGI("trusty dev: %s\n", trusty_devname);
+    ALOGI("rpmb dev: %s\n", rpmb_devname);
+}
+
+int main(int argc, char *argv[])
+{
+    int rc;
+    uint retry_cnt;
+
+    /* drop privileges */
+    if (drop_privs() < 0)
+        return EXIT_FAILURE;
+
+    /* parse arguments */
+    parse_args(argc, argv);
+
+    /* initialize secure storage directory */
+    rc = storage_init(ss_data_root);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* open rpmb device */
+    rc = rpmb_open(rpmb_devname);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* connect to Trusty secure storage server */
+    rc = ipc_connect(trusty_devname, ss_srv_name);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* enter main loop */
+    rc = proxy_loop();
+    ALOGE("exiting proxy loop with status (%d)\n", rc);
+
+    ipc_disconnect();
+    rpmb_close();
+
+    return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
new file mode 100644
index 0000000..9130458
--- /dev/null
+++ b/trusty/storage/proxy/rpmb.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <linux/major.h>
+#include <linux/mmc/ioctl.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define MMC_READ_MULTIPLE_BLOCK 18
+#define MMC_WRITE_MULTIPLE_BLOCK 25
+#define MMC_RELIABLE_WRITE_FLAG (1 << 31)
+
+#define MMC_RSP_PRESENT (1 << 0)
+#define MMC_RSP_CRC (1 << 2)
+#define MMC_RSP_OPCODE (1 << 4)
+#define MMC_CMD_ADTC (1 << 5)
+#define MMC_RSP_SPI_S1 (1 << 7)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
+
+#define MMC_WRITE_FLAG_R 0
+#define MMC_WRITE_FLAG_W 1
+#define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
+
+#define MMC_BLOCK_SIZE 512
+
+static int rpmb_fd = -1;
+static uint8_t read_buf[4096];
+
+#ifdef RPMB_DEBUG
+
+static void print_buf(const char *prefix, const uint8_t *buf, size_t size)
+{
+    size_t i;
+
+    printf("%s @%p [%zu]", prefix, buf, size);
+    for (i = 0; i < size; i++) {
+        if (i && i % 32 == 0)
+            printf("\n%*s", (int) strlen(prefix), "");
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+    fflush(stdout);
+}
+
+#endif
+
+
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
+{
+    int rc;
+    struct {
+        struct mmc_ioc_multi_cmd multi;
+        struct mmc_ioc_cmd cmd_buf[3];
+    } mmc = {};
+    struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
+    const struct storage_rpmb_send_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
+              req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t expected_len =
+            sizeof(*req) + req->reliable_write_size + req->write_size;
+    if (req_len != expected_len) {
+        ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
+              req_len, expected_len);
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    const uint8_t *write_buf = req->payload;
+    if (req->reliable_write_size) {
+        if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
+            ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_RELW;
+        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+        print_buf("request: ", write_buf, req->reliable_write_size);
+#endif
+        write_buf += req->reliable_write_size;
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    if (req->write_size) {
+        if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
+            ALOGW("invalid write size %u\n", req->write_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_W;
+        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+        print_buf("request: ", write_buf, req->write_size);
+#endif
+        write_buf += req->write_size;
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    if (req->read_size) {
+        if (req->read_size % MMC_BLOCK_SIZE != 0 ||
+            req->read_size > sizeof(read_buf)) {
+            ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_R;
+        cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), read_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+#endif
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
+    if (rc < 0) {
+        ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+#ifdef RPMB_DEBUG
+    if (req->read_size)
+        print_buf("response: ", read_buf, req->read_size);
+#endif
+
+    if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+        /*
+         * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
+         * is fully synchronous in this implementation.
+         */
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, read_buf, req->read_size);
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int rpmb_open(const char *rpmb_devname)
+{
+    int rc;
+
+    rc = open(rpmb_devname, O_RDWR, 0);
+    if (rc < 0) {
+        ALOGE("unable (%d) to open rpmb device '%s': %s\n",
+              errno, rpmb_devname, strerror(errno));
+        return rc;
+    }
+    rpmb_fd = rc;
+    return 0;
+}
+
+void rpmb_close(void)
+{
+    close(rpmb_fd);
+    rpmb_fd = -1;
+}
+
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/rpmb.h
similarity index 62%
rename from libcutils/atomic.c
rename to trusty/storage/proxy/rpmb.h
index d34aa00..85cff44 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/rpmb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,14 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#include <stdint.h>
+#include <trusty/interface/storage.h>
 
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
+int rpmb_open(const char *rpmb_devname);
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len);
+void rpmb_close(void);
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
new file mode 100644
index 0000000..c61e89d
--- /dev/null
+++ b/trusty/storage/proxy/storage.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "ipc.h"
+#include "storage.h"
+
+#define FD_TBL_SIZE 64
+#define MAX_READ_SIZE 4096
+
+enum sync_state {
+    SS_UNUSED = -1,
+    SS_CLEAN =  0,
+    SS_DIRTY =  1,
+};
+
+static int ssdir_fd = -1;
+static const char *ssdir_name;
+
+static enum sync_state fs_state;
+static enum sync_state dir_state;
+static enum sync_state fd_state[FD_TBL_SIZE];
+
+static struct {
+   struct storage_file_read_resp hdr;
+   uint8_t data[MAX_READ_SIZE];
+}  read_rsp;
+
+static uint32_t insert_fd(int open_flags, int fd)
+{
+    uint32_t handle = fd;
+
+    if (open_flags & O_CREAT) {
+        dir_state = SS_DIRTY;
+    }
+
+    if (handle < FD_TBL_SIZE) {
+            fd_state[fd] = SS_CLEAN; /* fd clean */
+            if (open_flags & O_TRUNC) {
+                fd_state[fd] = SS_DIRTY;  /* set fd dirty */
+            }
+    } else {
+            ALOGW("%s: untracked fd %u\n", __func__, fd);
+            if (open_flags & (O_TRUNC | O_CREAT)) {
+                fs_state = SS_DIRTY;
+            }
+    }
+    return handle;
+}
+
+static int lookup_fd(uint32_t handle, bool dirty)
+{
+    if (dirty) {
+        if (handle < FD_TBL_SIZE) {
+            fd_state[handle] = SS_DIRTY;
+        } else {
+            fs_state = SS_DIRTY;
+        }
+    }
+    return handle;
+}
+
+static int remove_fd(uint32_t handle)
+{
+    if (handle < FD_TBL_SIZE) {
+        fd_state[handle] = SS_UNUSED; /* set to uninstalled */
+    }
+    return handle;
+}
+
+static enum storage_err translate_errno(int error)
+{
+    enum storage_err result;
+    switch (error) {
+    case 0:
+        result = STORAGE_NO_ERROR;
+        break;
+    case EBADF:
+    case EINVAL:
+    case ENOTDIR:
+    case EISDIR:
+    case ENAMETOOLONG:
+        result = STORAGE_ERR_NOT_VALID;
+        break;
+    case ENOENT:
+        result = STORAGE_ERR_NOT_FOUND;
+        break;
+    case EEXIST:
+        result = STORAGE_ERR_EXIST;
+        break;
+    case EPERM:
+    case EACCES:
+        result = STORAGE_ERR_ACCESS;
+        break;
+    default:
+        result = STORAGE_ERR_GENERIC;
+        break;
+    }
+
+    return result;
+}
+
+static ssize_t write_with_retry(int fd, const void *buf_, size_t size, off_t offset)
+{
+    ssize_t rc;
+    const uint8_t *buf = buf_;
+
+    while (size > 0) {
+        rc = TEMP_FAILURE_RETRY(pwrite(fd, buf, size, offset));
+        if (rc < 0)
+            return rc;
+        size -= rc;
+        buf += rc;
+        offset += rc;
+    }
+    return 0;
+}
+
+static ssize_t read_with_retry(int fd, void *buf_, size_t size, off_t offset)
+{
+    ssize_t rc;
+    size_t  rcnt = 0;
+    uint8_t *buf = buf_;
+
+    while (size > 0) {
+        rc = TEMP_FAILURE_RETRY(pread(fd, buf, size, offset));
+        if (rc < 0)
+            return rc;
+        if (rc == 0)
+            break;
+        size -= rc;
+        buf += rc;
+        offset += rc;
+        rcnt += rc;
+    }
+    return rcnt;
+}
+
+int storage_file_delete(struct storage_msg *msg,
+                        const void *r, size_t req_len)
+{
+    char *path = NULL;
+    const struct storage_file_delete_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t fname_len = strlen(req->name);
+    if (fname_len != req_len - sizeof(*req)) {
+        ALOGE("%s: invalid filename length (%zd != %zd)\n",
+              __func__, fname_len, req_len - sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+    if (rc < 0) {
+        ALOGE("%s: asprintf failed\n", __func__);
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+
+    dir_state = SS_DIRTY;
+    rc = unlink(path);
+    if (rc < 0) {
+        rc = errno;
+        if (errno == ENOENT) {
+            ALOGV("%s: error (%d) unlinking file '%s'\n",
+                  __func__, rc, path);
+        } else {
+            ALOGE("%s: error (%d) unlinking file '%s'\n",
+                  __func__, rc, path);
+        }
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    ALOGV("%s: \"%s\"\n", __func__, path);
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    if (path)
+        free(path);
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_open(struct storage_msg *msg,
+                      const void *r, size_t req_len)
+{
+    char *path = NULL;
+    const struct storage_file_open_req *req = r;
+    struct storage_file_open_resp resp = {0};
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+               __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t fname_len = strlen(req->name);
+    if (fname_len != req_len - sizeof(*req)) {
+        ALOGE("%s: invalid filename length (%zd != %zd)\n",
+              __func__, fname_len, req_len - sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+    if (rc < 0) {
+        ALOGE("%s: asprintf failed\n", __func__);
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+
+    int open_flags = O_RDWR;
+
+    if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
+        open_flags |= O_TRUNC;
+
+    if (req->flags & STORAGE_FILE_OPEN_CREATE) {
+        /* open or create */
+        if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
+            /* create exclusive */
+            open_flags |= O_CREAT | O_EXCL;
+            rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+        } else {
+            /* try open first */
+            rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+            if (rc == -1 && errno == ENOENT) {
+                /* then try open with O_CREATE */
+                open_flags |= O_CREAT;
+                rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+            }
+
+        }
+    } else {
+        /* open an existing file */
+        rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+    }
+
+    if (rc < 0) {
+        rc = errno;
+        if (errno == EEXIST || errno == ENOENT) {
+            ALOGV("%s: failed to open file \"%s\": %s\n",
+                  __func__, path, strerror(errno));
+        } else {
+            ALOGE("%s: failed to open file \"%s\": %s\n",
+                  __func__, path, strerror(errno));
+        }
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+    free(path);
+
+    /* at this point rc contains storage file fd */
+    msg->result = STORAGE_NO_ERROR;
+    resp.handle = insert_fd(open_flags, rc);
+    ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
+          __func__, path, rc, resp.handle);
+
+    return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+    if (path)
+        free(path);
+    return ipc_respond(msg, NULL, 0);
+}
+
+int storage_file_close(struct storage_msg *msg,
+                       const void *r, size_t req_len)
+{
+    const struct storage_file_close_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = remove_fd(req->handle);
+    ALOGV("%s: handle = %u: fd = %u\n", __func__, req->handle, fd);
+
+    int rc = fsync(fd);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: fsync failed for fd=%u: %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    rc = close(fd);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: close failed for fd=%u: %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_write(struct storage_msg *msg,
+                       const void *r, size_t req_len)
+{
+    int rc;
+    const struct storage_file_write_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, true);
+    if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
+                         req->offset) < 0) {
+        rc = errno;
+        ALOGW("%s: error writing file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_read(struct storage_msg *msg,
+                      const void *r, size_t req_len)
+{
+    int rc;
+    const struct storage_file_read_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    if (req->size > MAX_READ_SIZE) {
+        ALOGW("%s: request is too large (%zd > %zd) - refusing\n",
+              __func__, req->size, MAX_READ_SIZE);
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, false);
+    ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
+                                       (off_t)req->offset);
+    if (read_res < 0) {
+        rc = errno;
+        ALOGW("%s: error reading file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr));
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_get_size(struct storage_msg *msg,
+                          const void *r, size_t req_len)
+{
+    const struct storage_file_get_size_req *req = r;
+    struct storage_file_get_size_resp resp = {0};
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    struct stat stat;
+    int fd = lookup_fd(req->handle, false);
+    int rc = fstat(fd, &stat);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: error stat'ing file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    resp.size = stat.st_size;
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_set_size(struct storage_msg *msg,
+                          const void *r, size_t req_len)
+{
+    const struct storage_file_set_size_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, true);
+    int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size));
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: error truncating file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+int storage_init(const char *dirname)
+{
+    fs_state = SS_CLEAN;
+    dir_state = SS_CLEAN;
+    for (uint i = 0; i < FD_TBL_SIZE; i++) {
+        fd_state[i] = SS_UNUSED;  /* uninstalled */
+    }
+
+    ssdir_fd = open(dirname, O_RDONLY);
+    if (ssdir_fd < 0) {
+        ALOGE("failed to open ss root dir \"%s\": %s\n",
+               dirname, strerror(errno));
+        return -1;
+    }
+    ssdir_name = dirname;
+    return 0;
+}
+
+int storage_sync_checkpoint(void)
+{
+    int rc;
+
+    /* sync fd table and reset it to clean state first */
+    for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
+         if (fd_state[fd] == SS_DIRTY) {
+             if (fs_state == SS_CLEAN) {
+                 /* need to sync individual fd */
+                 rc = fsync(fd);
+                 if (rc < 0) {
+                     ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
+                     return rc;
+                 }
+             }
+             fd_state[fd] = SS_CLEAN; /* set to clean */
+         }
+    }
+
+    /* check if we need to sync the directory */
+    if (dir_state == SS_DIRTY) {
+        if (fs_state == SS_CLEAN) {
+            rc = fsync(ssdir_fd);
+            if (rc < 0) {
+                ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
+                return rc;
+            }
+        }
+        dir_state = SS_CLEAN;  /* set to clean */
+    }
+
+    /* check if we need to sync the whole fs */
+    if (fs_state == SS_DIRTY) {
+        rc = syscall(SYS_syncfs, ssdir_fd);
+        if (rc < 0) {
+            ALOGE("syncfs failed: %s\n", strerror(errno));
+            return rc;
+        }
+        fs_state = SS_CLEAN;
+    }
+
+    return 0;
+}
+
diff --git a/trusty/storage/proxy/storage.h b/trusty/storage/proxy/storage.h
new file mode 100644
index 0000000..5a670d4
--- /dev/null
+++ b/trusty/storage/proxy/storage.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <trusty/interface/storage.h>
+
+int storage_file_delete(struct storage_msg *msg,
+                        const void *req, size_t req_len);
+
+int storage_file_open(struct storage_msg *msg,
+                      const void *req, size_t req_len);
+
+int storage_file_close(struct storage_msg *msg,
+                       const void *req, size_t req_len);
+
+int storage_file_write(struct storage_msg *msg,
+                       const void *req, size_t req_len);
+
+int storage_file_read(struct storage_msg *msg,
+                      const void *req, size_t req_len);
+
+int storage_file_get_size(struct storage_msg *msg,
+                          const void *req, size_t req_len);
+
+int storage_file_set_size(struct storage_msg *msg,
+                          const void *req, size_t req_len);
+
+int storage_init(const char *dirname);
+
+int storage_sync_checkpoint(void);
+
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
new file mode 100644
index 0000000..9c3a7df
--- /dev/null
+++ b/trusty/trusty-base.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2016 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This makefile should be included by devices that use Trusty TEE
+# to pull in the baseline set of Trusty specific modules.
+#
+
+PRODUCT_PACKAGES += \
+	keystore.trusty \
+	gatekeeper.trusty
+
+PRODUCT_PROPERTY_OVERRIDES += \
+	ro.hardware.keystore=trusty \
+	ro.hardware.gatekeeper=trusty
diff --git a/trusty/trusty-storage.mk b/trusty/trusty-storage.mk
new file mode 100644
index 0000000..3f26316
--- /dev/null
+++ b/trusty/trusty-storage.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+PRODUCT_PACKAGES += \
+	storageproxyd \