Merge "SystemClock: add test"
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 6693619..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 \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 49d2936..11e9c68 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -955,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;
         }
 
diff --git a/adb/adb.h b/adb/adb.h
index ea20800..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 36
+#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_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 45c6142..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"
@@ -1719,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");
@@ -1733,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")) {
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/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 f0c334e..fde344a 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -218,7 +218,7 @@
 
 TEST_F(sysdeps_poll, fd_count) {
     // https://code.google.com/p/android/issues/detail?id=12141
-    static constexpr int num_sockets = 512;
+    static constexpr int num_sockets = 256;
     std::vector<int> sockets;
     std::vector<adb_pollfd> pfds;
     sockets.resize(num_sockets * 2);
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index bc09fdc..faf7f3e 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -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/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/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 258bd76..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>
@@ -32,12 +33,15 @@
 #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>
@@ -287,6 +291,41 @@
   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);
@@ -414,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 amfd) {
+                         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;
@@ -432,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, amfd);
+                            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) {
@@ -458,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, amfd);
+                          request.original_si_code, request.abort_msg_address, amfd_data);
         break;
 
       default:
@@ -472,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;
   }
 
@@ -545,9 +592,11 @@
   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;
@@ -560,11 +609,11 @@
 
   int crash_signal = SIGKILL;
   succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
-                           &crash_signal, amfd);
+                           &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());
       }
     }
   }
@@ -577,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));
   }
@@ -593,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));
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 d802c8c..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>
@@ -202,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);
@@ -218,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"))) {
@@ -613,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);
@@ -640,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
@@ -708,7 +686,7 @@
 
 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, int amfd) {
+                       uintptr_t abort_msg_address, std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
@@ -719,8 +697,6 @@
   }
 
   log.tfd = tombstone_fd;
-  // Preserve amfd since it can be modified through the calls below without
-  // being closed.
-  log.amfd = amfd;
+  log.amfd_data = amfd_data;
   dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 7f3eebe..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, int amfd);
+                       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 1785b76..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) {
-            snprintf(ERROR, sizeof(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) {
-            snprintf(ERROR, sizeof(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) {
-                snprintf(ERROR, sizeof(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) {
-        snprintf(ERROR, sizeof(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)) {
-        snprintf(ERROR, sizeof(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) {
-        snprintf(ERROR, sizeof(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)) {
-        snprintf(ERROR, sizeof(ERROR), "data transfer failure (short transfer)");
+        g_error = "data transfer failure (short transfer)";
         transport->Close();
         return -1;
     }
@@ -216,7 +216,7 @@
 
     if (len > TRANSPORT_BUF_SIZE) {
         if (transport_buf_len > 0) {
-            snprintf(ERROR, sizeof(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) {
-            snprintf(ERROR, sizeof(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);
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/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 129a5bb..72554a8 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include <android-base/file.h>
+#include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -211,7 +212,7 @@
 }
 
 struct verity_table_params {
-    const char *table;
+    char *table;
     int mode;
     struct fec_ecc_metadata ecc;
     const char *ecc_dev;
@@ -843,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;
@@ -912,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, sizeof(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
@@ -922,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) {
@@ -1001,7 +1036,7 @@
     }
 
     fec_close(f);
-    free(invalid_table);
+    free(params.table);
     free(verity_blk_name);
 
     return retval;
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/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/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/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/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/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/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/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 88afc14..59bd479 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1043,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;
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 1a7d4aa..df2c766 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -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);
@@ -1393,6 +1394,7 @@
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1422,6 +1424,7 @@
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
 
             strcpy(key, log_namespace);
@@ -1453,6 +1456,7 @@
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1482,6 +1486,7 @@
                         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);
@@ -1527,6 +1534,7 @@
                         levels[i].level, tag, ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1556,12 +1564,14 @@
                         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/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 f0360db..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,9 +36,20 @@
 namespace android {
 
 #if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfig = "/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:
   LibraryNamespaces() : initialized_(false) { }
@@ -48,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())) {
@@ -94,11 +119,35 @@
   }
 
   void Initialize() {
-    std::vector<std::string> sonames;
+    // 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;
+    }
 
-    LOG_ALWAYS_FATAL_IF(!ReadConfig(kPublicNativeLibrariesSystemConfig, &sonames),
+    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",
-                        kPublicNativeLibrariesSystemConfig, strerror(errno));
+                        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);
 
@@ -117,6 +166,10 @@
     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.
@@ -159,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() {
@@ -172,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,
@@ -180,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,
@@ -206,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);
   }
 
@@ -233,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/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 997e682..920d504 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -810,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[BIG_BUFFER];
 
     int count = 0;
+    int minus_g = 0;
 
     int signals = 0;
 
@@ -833,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;
@@ -861,6 +907,7 @@
     pclose(fp);
 
     EXPECT_LE(1, count);
+    EXPECT_EQ(1, minus_g);
 
     EXPECT_EQ(1, signals);
 }
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 85f9415..d151ad6 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -36,7 +36,6 @@
     log \
     nandread \
     newfs_msdos \
-    ps \
     sendevent \
     start \
     stop \
diff --git a/toolbox/ps.c b/toolbox/ps.c
deleted file mode 100644
index 3b3c8a1..0000000
--- a/toolbox/ps.c
+++ /dev/null
@@ -1,340 +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")) {
-            if (argc < 3) {
-                /* Bug 26554285: Use printf because some apps require at least
-                 * one line of output to stdout even for errors.
-                 */
-                printf("no ppid\n");
-                return 1;
-            }
-            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/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 \