Merge "fs_mgr: pass sehandle to ext4 format routine"
diff --git a/adb/Android.mk b/adb/Android.mk
index 71d5aaf..6188184 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -208,24 +208,6 @@
 
 include $(BUILD_HOST_NATIVE_TEST)
 
-# adb device tracker (used by ddms) test tool
-# =========================================================
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_device_tracker_test
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := test_track_devices.cpp
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_utils_static libcrypto_static libcutils
-LOCAL_LDLIBS += -lrt -ldl -lpthread
-include $(BUILD_HOST_EXECUTABLE)
-endif
-
 # adb host tool
 # =========================================================
 include $(CLEAR_VARS)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 11e9c68..3f14f1a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -65,21 +65,34 @@
 void fatal(const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr, "error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+    fprintf(stderr, "error: %s\n", buf);
+#else
+    LOG(ERROR) << "error: " << buf;
+#endif
+
     va_end(ap);
-    exit(-1);
+    abort();
 }
 
 void fatal_errno(const char* fmt, ...) {
+    int err = errno;
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr, "error: %s: ", strerror(errno));
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+    fprintf(stderr, "error: %s: %s\n", buf, strerror(err));
+#else
+    LOG(ERROR) << "error: " << buf << ": " << strerror(err);
+#endif
+
     va_end(ap);
-    exit(-1);
+    abort();
 }
 
 apacket* get_apacket(void)
diff --git a/adb/adb.h b/adb/adb.h
index cb38e61..9227eb1 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -188,7 +188,7 @@
 
 
 void local_init(int port);
-void local_connect(int port);
+bool local_connect(int port);
 int  local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
 // USB host/client interface.
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index 1ffab09..215bbe6 100644
--- a/adb/adb_auth.cpp
+++ b/adb/adb_auth.cpp
@@ -72,19 +72,23 @@
 void send_auth_publickey(atransport *t)
 {
     D("Calling send_auth_publickey");
-    apacket *p = get_apacket();
-    int ret;
-
-    ret = adb_auth_get_userkey(p->data, MAX_PAYLOAD_V1);
-    if (!ret) {
+    std::string key = adb_auth_get_userkey();
+    if (key.empty()) {
         D("Failed to get user public key");
-        put_apacket(p);
         return;
     }
 
+    if (key.size() >= MAX_PAYLOAD_V1) {
+        D("User public key too large (%zu B)", key.size());
+        return;
+    }
+
+    apacket* p = get_apacket();
+    memcpy(p->data, key.c_str(), key.size() + 1);
+
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
-    p->msg.data_length = ret;
+    p->msg.data_length = key.size();
     send_packet(p, t);
 }
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1ab5e1a..6363bb4 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -41,7 +41,7 @@
 int adb_auth_sign(void *key, const unsigned char* token, size_t token_size,
                   unsigned char* sig);
 void *adb_auth_nextkey(void *current);
-int adb_auth_get_userkey(unsigned char *data, size_t len);
+std::string adb_auth_get_userkey();
 
 static inline int adb_auth_generate_token(void *token, size_t token_size) {
     return 0;
@@ -60,9 +60,7 @@
     return 0;
 }
 static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline int adb_auth_get_userkey(unsigned char *data, size_t len) {
-    return 0;
-}
+static inline std::string adb_auth_get_userkey() { return ""; }
 
 void adbd_auth_init(void);
 void adbd_cloexec_auth_socket();
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index ab641eb..03cebe9 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -18,26 +18,17 @@
 
 #include "sysdeps.h"
 #include "adb_auth.h"
+#include "adb_utils.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
-#  include "windows.h"
-#  include "shlobj.h"
-#else
-#  include <sys/types.h>
-#  include <sys/stat.h>
-#  include <unistd.h>
-#endif
-
 #include "adb.h"
 
 #include <android-base/errors.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
 #include <cutils/list.h>
@@ -247,46 +238,23 @@
 
 static int get_user_keyfilepath(char *filename, size_t len)
 {
-    const char *format, *home;
-    char android_dir[PATH_MAX];
+    const std::string home = adb_get_homedir_path(true);
+    D("home '%s'", home.c_str());
+
+    const std::string android_dir =
+            android::base::StringPrintf("%s%c%s", home.c_str(),
+                                        OS_PATH_SEPARATOR, ANDROID_PATH);
+
     struct stat buf;
-#ifdef _WIN32
-    std::string home_str;
-    home = getenv("ANDROID_SDK_HOME");
-    if (!home) {
-        WCHAR path[MAX_PATH];
-        const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
-        if (FAILED(hr)) {
-            D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str());
-            return -1;
-        }
-        if (!android::base::WideToUTF8(path, &home_str)) {
-            return -1;
-        }
-        home = home_str.c_str();
-    }
-    format = "%s\\%s";
-#else
-    home = getenv("HOME");
-    if (!home)
-        return -1;
-    format = "%s/%s";
-#endif
-
-    D("home '%s'", home);
-
-    if (snprintf(android_dir, sizeof(android_dir), format, home,
-                        ANDROID_PATH) >= (int)sizeof(android_dir))
-        return -1;
-
-    if (stat(android_dir, &buf)) {
-        if (adb_mkdir(android_dir, 0750) < 0) {
-            D("Cannot mkdir '%s'", android_dir);
+    if (stat(android_dir.c_str(), &buf)) {
+        if (adb_mkdir(android_dir.c_str(), 0750) < 0) {
+            D("Cannot mkdir '%s'", android_dir.c_str());
             return -1;
         }
     }
 
-    return snprintf(filename, len, format, android_dir, ADB_KEY_FILE);
+    return snprintf(filename, len, "%s%c%s",
+                    android_dir.c_str(), OS_PATH_SEPARATOR, ADB_KEY_FILE);
 }
 
 static int get_user_key(struct listnode *list)
@@ -367,39 +335,21 @@
     return NULL;
 }
 
-int adb_auth_get_userkey(unsigned char *data, size_t len)
-{
+std::string adb_auth_get_userkey() {
     char path[PATH_MAX];
     int ret = get_user_keyfilepath(path, sizeof(path) - 4);
     if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
         D("Error getting user key filename");
-        return 0;
+        return "";
     }
     strcat(path, ".pub");
 
-    // TODO(danalbert): ReadFileToString
-    // Note that on Windows, load_file() does not do CR/LF translation, but
-    // ReadFileToString() uses the C Runtime which uses CR/LF translation by
-    // default (by is overridable with _setmode()).
-    unsigned size;
-    char* file_data = reinterpret_cast<char*>(load_file(path, &size));
-    if (file_data == nullptr) {
+    std::string content;
+    if (!android::base::ReadFileToString(path, &content)) {
         D("Can't load '%s'", path);
-        return 0;
+        return "";
     }
-
-    if (len < (size_t)(size + 1)) {
-        D("%s: Content too large ret=%d", path, size);
-        free(file_data);
-        return 0;
-    }
-
-    memcpy(data, file_data, size);
-    free(file_data);
-    file_data = nullptr;
-    data[size] = '\0';
-
-    return size + 1;
+    return content;
 }
 
 int adb_auth_keygen(const char* filename) {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index d50f947..5206a99 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -41,7 +41,7 @@
 };
 
 #define VLOG_IS_ON(TAG) \
-    ((adb_trace_mask & (1 << TAG)) != 0)
+    ((adb_trace_mask & (1 << (TAG))) != 0)
 
 #define VLOG(TAG)         \
     if (LIKELY(!VLOG_IS_ON(TAG))) \
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 5d4755f..31ec8af 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -35,6 +35,14 @@
 #include "adb_trace.h"
 #include "sysdeps.h"
 
+#ifdef _WIN32
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include "windows.h"
+#  include "shlobj.h"
+#endif
+
 ADB_MUTEX_DEFINE(basename_lock);
 ADB_MUTEX_DEFINE(dirname_lock);
 
@@ -254,3 +262,30 @@
 
     return true;
 }
+
+std::string adb_get_homedir_path(bool check_env_first) {
+#ifdef _WIN32
+    if (check_env_first) {
+        if (const char* const home = getenv("ANDROID_SDK_HOME")) {
+            return home;
+        }
+    }
+
+    WCHAR path[MAX_PATH];
+    const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
+    if (FAILED(hr)) {
+        D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str());
+        return {};
+    }
+    std::string home_str;
+    if (!android::base::WideToUTF8(path, &home_str)) {
+        return {};
+    }
+    return home_str;
+#else
+    if (const char* const home = getenv("HOME")) {
+        return home;
+    }
+    return {};
+#endif
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index abf481b..f6b4b26 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include <android-base/macros.h>
+#include <android-base/unique_fd.h>
 
 void close_stdin();
 
@@ -31,6 +32,12 @@
 std::string adb_basename(const std::string& path);
 std::string adb_dirname(const std::string& path);
 
+// Return the user's home directory.
+// |check_env_first| - if true, on Windows check the ANDROID_SDK_HOME
+// environment variable before trying the WinAPI call (useful when looking for
+// the .android directory)
+std::string adb_get_homedir_path(bool check_env_first);
+
 bool mkdirs(const std::string& path);
 
 std::string escape_arg(const std::string& s);
@@ -51,42 +58,12 @@
                                std::string* error);
 
 // Helper to automatically close an FD when it goes out of scope.
-class ScopedFd {
-  public:
-    ScopedFd() {
+struct AdbCloser {
+    static void Close(int fd) {
+        adb_close(fd);
     }
-
-    ~ScopedFd() {
-        Reset();
-    }
-
-    void Reset(int fd = -1) {
-        if (fd != fd_) {
-            if (valid()) {
-                adb_close(fd_);
-            }
-            fd_ = fd;
-        }
-    }
-
-    int Release() {
-        int temp = fd_;
-        fd_ = -1;
-        return temp;
-    }
-
-    bool valid() const {
-        return fd_ >= 0;
-    }
-
-    int fd() const {
-        return fd_;
-    }
-
-  private:
-    int fd_ = -1;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedFd);
 };
 
+using unique_fd = android::base::unique_fd_impl<AdbCloser>;
+
 #endif
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 28dbb78..82fa19a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -35,6 +35,7 @@
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -871,47 +872,47 @@
  *   we hang up.
  */
 static int adb_sideload_host(const char* fn) {
-    unsigned sz;
-    size_t xfer = 0;
-    int status;
-    int last_percent = -1;
-    int opt = SIDELOAD_HOST_BLOCK_SIZE;
-
     printf("loading: '%s'", fn);
     fflush(stdout);
-    uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz));
-    if (data == 0) {
+
+    std::string content;
+    if (!android::base::ReadFileToString(fn, &content)) {
         printf("\n");
         fprintf(stderr, "* cannot read '%s' *\n", fn);
         return -1;
     }
 
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(content.data());
+    unsigned sz = content.size();
+
     std::string service =
             android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
-    int fd = adb_connect(service, &error);
-    if (fd < 0) {
+    unique_fd fd(adb_connect(service, &error));
+    if (fd >= 0) {
         // Try falling back to the older sideload method.  Maybe this
         // is an older device that doesn't support sideload-host.
         printf("\n");
-        status = adb_download_buffer("sideload", fn, data, sz, true);
-        goto done;
+        return adb_download_buffer("sideload", fn, data, sz, true);
     }
 
-    opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
 
+    size_t xfer = 0;
+    int last_percent = -1;
     while (true) {
         char buf[9];
         if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
-            status = -1;
-            goto done;
+            return -1;
         }
         buf[8] = '\0';
 
         if (strcmp("DONEDONE", buf) == 0) {
-            status = 0;
-            break;
+            printf("\rTotal xfer: %.2fx%*s\n",
+                   (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+            return 0;
         }
 
         int block = strtol(buf, NULL, 10);
@@ -919,21 +920,19 @@
         size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
         if (offset >= sz) {
             fprintf(stderr, "* attempt to read block %d past end\n", block);
-            status = -1;
-            goto done;
+            return -1;
         }
-        uint8_t* start = data + offset;
+        const uint8_t* start = data + offset;
         size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
         size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
         if (offset_end > sz) {
             to_write = sz - offset;
         }
 
-        if(!WriteFdExactly(fd, start, to_write)) {
+        if (!WriteFdExactly(fd, start, to_write)) {
             adb_status(fd, &error);
             fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
-            status = -1;
-            goto done;
+            return -1;
         }
         xfer += to_write;
 
@@ -950,13 +949,6 @@
             last_percent = percent;
         }
     }
-
-    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
-
-  done:
-    if (fd >= 0) adb_close(fd);
-    free(data);
-    return status;
 }
 
 /**
@@ -1067,10 +1059,9 @@
 
 static bool adb_root(const char* command) {
     std::string error;
-    ScopedFd fd;
 
-    fd.Reset(adb_connect(android::base::StringPrintf("%s:", command), &error));
-    if (!fd.valid()) {
+    unique_fd fd(adb_connect(android::base::StringPrintf("%s:", command), &error));
+    if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str());
         return false;
     }
@@ -1080,7 +1071,7 @@
     char* cur = buf;
     ssize_t bytes_left = sizeof(buf);
     while (bytes_left > 0) {
-        ssize_t bytes_read = adb_read(fd.fd(), cur, bytes_left);
+        ssize_t bytes_read = adb_read(fd, cur, bytes_left);
         if (bytes_read == 0) {
             break;
         } else if (bytes_read < 0) {
@@ -1902,6 +1893,14 @@
     else if (!strcmp(argv[0], "jdwp")) {
         return adb_connect_command("jdwp");
     }
+    else if (!strcmp(argv[0], "track-jdwp")) {
+        return adb_connect_command("track-jdwp");
+    }
+    else if (!strcmp(argv[0], "track-devices")) {
+        return adb_connect_command("host:track-devices");
+    }
+
+
     /* "adb /?" is a common idiom under Windows */
     else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
         help();
diff --git a/adb/console.cpp b/adb/console.cpp
index 15c6abd..e9b90a5 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -26,6 +26,31 @@
 #include "adb.h"
 #include "adb_client.h"
 #include "adb_io.h"
+#include "adb_utils.h"
+
+// Return the console authentication command for the emulator, if needed
+static std::string adb_construct_auth_command() {
+    static const char auth_token_filename[] = ".emulator_console_auth_token";
+
+    std::string auth_token_path = adb_get_homedir_path(false);
+    auth_token_path += OS_PATH_SEPARATOR;
+    auth_token_path += auth_token_filename;
+
+    // read the token
+    std::string token;
+    if (!android::base::ReadFileToString(auth_token_path, &token)
+        || token.empty()) {
+        // we either can't read the file, or it doesn't exist, or it's empty -
+        // either way we won't add any authentication command.
+        return {};
+    }
+
+    // now construct and return the actual command: "auth <token>\n"
+    std::string command = "auth ";
+    command += token;
+    command += '\n';
+    return command;
+}
 
 // Return the console port of the currently connected emulator (if any) or -1 if
 // there is no emulator, and -2 if there is more than one.
@@ -88,11 +113,11 @@
         return 1;
     }
 
-    std::string commands;
+    std::string commands = adb_construct_auth_command();
 
     for (int i = 1; i < argc; i++) {
         commands.append(argv[i]);
-        commands.append(i == argc - 1 ? "\n" : " ");
+        commands.push_back(i == argc - 1 ? '\n' : ' ');
     }
 
     commands.append("quit\n");
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index b59c9f2..4a188ee 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -8,7 +8,6 @@
 #endif
 ADB_MUTEX(basename_lock)
 ADB_MUTEX(dirname_lock)
-ADB_MUTEX(socket_list_lock)
 ADB_MUTEX(transport_lock)
 #if ADB_HOST
 ADB_MUTEX(local_transports_lock)
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 3eeed34..e8dad58 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -136,14 +136,14 @@
 }
 
 // Creates a socketpair and saves the endpoints to |fd1| and |fd2|.
-bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) {
+bool CreateSocketpair(unique_fd* fd1, unique_fd* fd2) {
     int sockets[2];
     if (adb_socketpair(sockets) < 0) {
         PLOG(ERROR) << "cannot create socket pair";
         return false;
     }
-    fd1->Reset(sockets[0]);
-    fd2->Reset(sockets[1]);
+    fd1->reset(sockets[0]);
+    fd2->reset(sockets[1]);
     return true;
 }
 
@@ -155,7 +155,7 @@
 
     const std::string& command() const { return command_; }
 
-    int local_socket_fd() const { return local_socket_sfd_.fd(); }
+    int local_socket_fd() const { return local_socket_sfd_; }
 
     pid_t pid() const { return pid_; }
 
@@ -165,19 +165,19 @@
 
   private:
     // Opens the file at |pts_name|.
-    int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
+    int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
 
     static void ThreadHandler(void* userdata);
     void PassDataStreams();
     void WaitForExit();
 
-    ScopedFd* SelectLoop(fd_set* master_read_set_ptr,
-                         fd_set* master_write_set_ptr);
+    unique_fd* SelectLoop(fd_set* master_read_set_ptr,
+                          fd_set* master_write_set_ptr);
 
     // Input/output stream handlers. Success returns nullptr, failure returns
     // a pointer to the failed FD.
-    ScopedFd* PassInput();
-    ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id);
+    unique_fd* PassInput();
+    unique_fd* PassOutput(unique_fd* sfd, ShellProtocol::Id id);
 
     const std::string command_;
     const std::string terminal_type_;
@@ -185,10 +185,10 @@
     SubprocessType type_;
     SubprocessProtocol protocol_;
     pid_t pid_ = -1;
-    ScopedFd local_socket_sfd_;
+    unique_fd local_socket_sfd_;
 
     // Shell protocol variables.
-    ScopedFd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
+    unique_fd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
     std::unique_ptr<ShellProtocol> input_, output_;
     size_t input_bytes_left_ = 0;
 
@@ -220,8 +220,8 @@
 }
 
 bool Subprocess::ForkAndExec(std::string* error) {
-    ScopedFd child_stdinout_sfd, child_stderr_sfd;
-    ScopedFd parent_error_sfd, child_error_sfd;
+    unique_fd child_stdinout_sfd, child_stderr_sfd;
+    unique_fd parent_error_sfd, child_error_sfd;
     char pts_name[PATH_MAX];
 
     if (command_.empty()) {
@@ -285,7 +285,7 @@
         int fd;
         pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
         if (pid_ > 0) {
-          stdinout_sfd_.Reset(fd);
+          stdinout_sfd_.reset(fd);
         }
     } else {
         if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) {
@@ -313,40 +313,39 @@
         init_subproc_child();
 
         if (type_ == SubprocessType::kPty) {
-            child_stdinout_sfd.Reset(OpenPtyChildFd(pts_name, &child_error_sfd));
+            child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
         }
 
-        dup2(child_stdinout_sfd.fd(), STDIN_FILENO);
-        dup2(child_stdinout_sfd.fd(), STDOUT_FILENO);
-        dup2(child_stderr_sfd.valid() ? child_stderr_sfd.fd() : child_stdinout_sfd.fd(),
-             STDERR_FILENO);
+        dup2(child_stdinout_sfd, STDIN_FILENO);
+        dup2(child_stdinout_sfd, STDOUT_FILENO);
+        dup2(child_stderr_sfd != -1 ? child_stderr_sfd : child_stdinout_sfd, STDERR_FILENO);
 
         // exec doesn't trigger destructors, close the FDs manually.
-        stdinout_sfd_.Reset();
-        stderr_sfd_.Reset();
-        child_stdinout_sfd.Reset();
-        child_stderr_sfd.Reset();
-        parent_error_sfd.Reset();
-        close_on_exec(child_error_sfd.fd());
+        stdinout_sfd_.reset(-1);
+        stderr_sfd_.reset(-1);
+        child_stdinout_sfd.reset(-1);
+        child_stderr_sfd.reset(-1);
+        parent_error_sfd.reset(-1);
+        close_on_exec(child_error_sfd);
 
         if (command_.empty()) {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
         } else {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
         }
-        WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed: ");
-        WriteFdExactly(child_error_sfd.fd(), strerror(errno));
-        child_error_sfd.Reset();
+        WriteFdExactly(child_error_sfd, "exec '" _PATH_BSHELL "' failed: ");
+        WriteFdExactly(child_error_sfd, strerror(errno));
+        child_error_sfd.reset(-1);
         _Exit(1);
     }
 
     // Subprocess parent.
     D("subprocess parent: stdin/stdout FD = %d, stderr FD = %d",
-      stdinout_sfd_.fd(), stderr_sfd_.fd());
+      stdinout_sfd_.get(), stderr_sfd_.get());
 
     // Wait to make sure the subprocess exec'd without error.
-    child_error_sfd.Reset();
-    std::string error_message = ReadAll(parent_error_sfd.fd());
+    child_error_sfd.reset(-1);
+    std::string error_message = ReadAll(parent_error_sfd);
     if (!error_message.empty()) {
         *error = error_message;
         return false;
@@ -356,7 +355,7 @@
     if (protocol_ == SubprocessProtocol::kNone) {
         // No protocol: all streams pass through the stdinout FD and hook
         // directly into the local socket for raw data transfer.
-        local_socket_sfd_.Reset(stdinout_sfd_.Release());
+        local_socket_sfd_.reset(stdinout_sfd_.release());
     } else {
         // Shell protocol: create another socketpair to intercept data.
         if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
@@ -365,10 +364,10 @@
             kill(pid_, SIGKILL);
             return false;
         }
-        D("protocol FD = %d", protocol_sfd_.fd());
+        D("protocol FD = %d", protocol_sfd_.get());
 
-        input_.reset(new ShellProtocol(protocol_sfd_.fd()));
-        output_.reset(new ShellProtocol(protocol_sfd_.fd()));
+        input_.reset(new ShellProtocol(protocol_sfd_));
+        output_.reset(new ShellProtocol(protocol_sfd_));
         if (!input_ || !output_) {
             *error = "failed to allocate shell protocol objects";
             kill(pid_, SIGKILL);
@@ -379,7 +378,7 @@
         // likely but could happen under unusual circumstances, such as if we
         // write a ton of data to stdin but the subprocess never reads it and
         // the pipe fills up.
-        for (int fd : {stdinout_sfd_.fd(), stderr_sfd_.fd()}) {
+        for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
             if (fd >= 0) {
                 if (!set_file_block_mode(fd, false)) {
                     *error = android::base::StringPrintf(
@@ -402,7 +401,7 @@
     return true;
 }
 
-int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) {
+int Subprocess::OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd) {
     int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC);
     if (child_fd == -1) {
         // Don't use WriteFdFmt; since we're in the fork() child we don't want
@@ -410,26 +409,26 @@
         const char* messages[] = {"child failed to open pseudo-term slave ",
                                   pts_name, ": ", strerror(errno)};
         for (const char* message : messages) {
-            WriteFdExactly(error_sfd->fd(), message);
+            WriteFdExactly(*error_sfd, message);
         }
-        exit(-1);
+        abort();
     }
 
     if (make_pty_raw_) {
         termios tattr;
         if (tcgetattr(child_fd, &tattr) == -1) {
             int saved_errno = errno;
-            WriteFdExactly(error_sfd->fd(), "tcgetattr failed: ");
-            WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
-            exit(-1);
+            WriteFdExactly(*error_sfd, "tcgetattr failed: ");
+            WriteFdExactly(*error_sfd, strerror(saved_errno));
+            abort();
         }
 
         cfmakeraw(&tattr);
         if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) {
             int saved_errno = errno;
-            WriteFdExactly(error_sfd->fd(), "tcsetattr failed: ");
-            WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
-            exit(-1);
+            WriteFdExactly(*error_sfd, "tcsetattr failed: ");
+            WriteFdExactly(*error_sfd, strerror(saved_errno));
+            abort();
         }
     }
 
@@ -449,7 +448,7 @@
 }
 
 void Subprocess::PassDataStreams() {
-    if (!protocol_sfd_.valid()) {
+    if (protocol_sfd_ == -1) {
         return;
     }
 
@@ -457,21 +456,20 @@
     fd_set master_read_set, master_write_set;
     FD_ZERO(&master_read_set);
     FD_ZERO(&master_write_set);
-    for (ScopedFd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
-        if (sfd->valid()) {
-            FD_SET(sfd->fd(), &master_read_set);
+    for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
+        if (*sfd != -1) {
+            FD_SET(*sfd, &master_read_set);
         }
     }
 
     // Pass data until the protocol FD or both the subprocess pipes die, at
     // which point we can't pass any more data.
-    while (protocol_sfd_.valid() &&
-            (stdinout_sfd_.valid() || stderr_sfd_.valid())) {
-        ScopedFd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
+    while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
+        unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
         if (dead_sfd) {
-            D("closing FD %d", dead_sfd->fd());
-            FD_CLR(dead_sfd->fd(), &master_read_set);
-            FD_CLR(dead_sfd->fd(), &master_write_set);
+            D("closing FD %d", dead_sfd->get());
+            FD_CLR(*dead_sfd, &master_read_set);
+            FD_CLR(*dead_sfd, &master_write_set);
             if (dead_sfd == &protocol_sfd_) {
                 // Using SIGHUP is a decent general way to indicate that the
                 // controlling process is going away. If specific signals are
@@ -480,25 +478,24 @@
                 D("protocol FD died, sending SIGHUP to pid %d", pid_);
                 kill(pid_, SIGHUP);
             }
-            dead_sfd->Reset();
+            dead_sfd->reset(-1);
         }
     }
 }
 
 namespace {
 
-inline bool ValidAndInSet(const ScopedFd& sfd, fd_set* set) {
-    return sfd.valid() && FD_ISSET(sfd.fd(), set);
+inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
+    return sfd != -1 && FD_ISSET(sfd, set);
 }
 
 }   // namespace
 
-ScopedFd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
-                                 fd_set* master_write_set_ptr) {
+unique_fd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
+                                  fd_set* master_write_set_ptr) {
     fd_set read_set, write_set;
-    int select_n = std::max(std::max(protocol_sfd_.fd(), stdinout_sfd_.fd()),
-                            stderr_sfd_.fd()) + 1;
-    ScopedFd* dead_sfd = nullptr;
+    int select_n = std::max(std::max(protocol_sfd_, stdinout_sfd_), stderr_sfd_) + 1;
+    unique_fd* dead_sfd = nullptr;
 
     // Keep calling select() and passing data until an FD closes/errors.
     while (!dead_sfd) {
@@ -509,8 +506,8 @@
                 continue;
             } else {
                 PLOG(ERROR) << "select failed, closing subprocess pipes";
-                stdinout_sfd_.Reset();
-                stderr_sfd_.Reset();
+                stdinout_sfd_.reset(-1);
+                stderr_sfd_.reset(-1);
                 return nullptr;
             }
         }
@@ -530,8 +527,8 @@
             dead_sfd = PassInput();
             // If we didn't finish writing, block on stdin write.
             if (input_bytes_left_) {
-                FD_CLR(protocol_sfd_.fd(), master_read_set_ptr);
-                FD_SET(stdinout_sfd_.fd(), master_write_set_ptr);
+                FD_CLR(protocol_sfd_, master_read_set_ptr);
+                FD_SET(stdinout_sfd_, master_write_set_ptr);
             }
         }
 
@@ -540,8 +537,8 @@
             dead_sfd = PassInput();
             // If we finished writing, go back to blocking on protocol read.
             if (!input_bytes_left_) {
-                FD_SET(protocol_sfd_.fd(), master_read_set_ptr);
-                FD_CLR(stdinout_sfd_.fd(), master_write_set_ptr);
+                FD_SET(protocol_sfd_, master_read_set_ptr);
+                FD_CLR(stdinout_sfd_, master_write_set_ptr);
             }
         }
     }  // while (!dead_sfd)
@@ -549,19 +546,18 @@
     return dead_sfd;
 }
 
-ScopedFd* Subprocess::PassInput() {
+unique_fd* Subprocess::PassInput() {
     // Only read a new packet if we've finished writing the last one.
     if (!input_bytes_left_) {
         if (!input_->Read()) {
             // Read() uses ReadFdExactly() which sets errno to 0 on EOF.
             if (errno != 0) {
-                PLOG(ERROR) << "error reading protocol FD "
-                            << protocol_sfd_.fd();
+                PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
             }
             return &protocol_sfd_;
         }
 
-        if (stdinout_sfd_.valid()) {
+        if (stdinout_sfd_ != -1) {
             switch (input_->id()) {
                 case ShellProtocol::kIdWindowSizeChange:
                     int rows, cols, x_pixels, y_pixels;
@@ -572,7 +568,7 @@
                         ws.ws_col = cols;
                         ws.ws_xpixel = x_pixels;
                         ws.ws_ypixel = y_pixels;
-                        ioctl(stdinout_sfd_.fd(), TIOCSWINSZ, &ws);
+                        ioctl(stdinout_sfd_, TIOCSWINSZ, &ws);
                     }
                     break;
                 case ShellProtocol::kIdStdin:
@@ -580,11 +576,11 @@
                     break;
                 case ShellProtocol::kIdCloseStdin:
                     if (type_ == SubprocessType::kRaw) {
-                        if (adb_shutdown(stdinout_sfd_.fd(), SHUT_WR) == 0) {
+                        if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) {
                             return nullptr;
                         }
                         PLOG(ERROR) << "failed to shutdown writes to FD "
-                                    << stdinout_sfd_.fd();
+                                    << stdinout_sfd_;
                         return &stdinout_sfd_;
                     } else {
                         // PTYs can't close just input, so rather than close the
@@ -593,7 +589,7 @@
                         // non-interactively which is rare and unsupported.
                         // If necessary, the client can manually close the shell
                         // with `exit` or by killing the adb client process.
-                        D("can't close input for PTY FD %d", stdinout_sfd_.fd());
+                        D("can't close input for PTY FD %d", stdinout_sfd_.get());
                     }
                     break;
             }
@@ -602,11 +598,10 @@
 
     if (input_bytes_left_ > 0) {
         int index = input_->data_length() - input_bytes_left_;
-        int bytes = adb_write(stdinout_sfd_.fd(), input_->data() + index,
-                              input_bytes_left_);
+        int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_);
         if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
             if (bytes < 0) {
-                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.fd();
+                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_;
             }
             // stdin is done, mark this packet as finished and we'll just start
             // dumping any further data received from the protocol FD.
@@ -620,20 +615,20 @@
     return nullptr;
 }
 
-ScopedFd* Subprocess::PassOutput(ScopedFd* sfd, ShellProtocol::Id id) {
-    int bytes = adb_read(sfd->fd(), output_->data(), output_->data_capacity());
+unique_fd* Subprocess::PassOutput(unique_fd* sfd, ShellProtocol::Id id) {
+    int bytes = adb_read(*sfd, output_->data(), output_->data_capacity());
     if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
         // read() returns EIO if a PTY closes; don't report this as an error,
         // it just means the subprocess completed.
         if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) {
-            PLOG(ERROR) << "error reading output FD " << sfd->fd();
+            PLOG(ERROR) << "error reading output FD " << *sfd;
         }
         return sfd;
     }
 
     if (bytes > 0 && !output_->Write(id, bytes)) {
         if (errno != 0) {
-            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.fd();
+            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
         }
         return &protocol_sfd_;
     }
@@ -665,25 +660,25 @@
     }
 
     // If we have an open protocol FD send an exit packet.
-    if (protocol_sfd_.valid()) {
+    if (protocol_sfd_ != -1) {
         output_->data()[0] = exit_code;
         if (output_->Write(ShellProtocol::kIdExit, 1)) {
             D("wrote the exit code packet: %d", exit_code);
         } else {
             PLOG(ERROR) << "failed to write the exit code packet";
         }
-        protocol_sfd_.Reset();
+        protocol_sfd_.reset(-1);
     }
 
     // Pass the local socket FD to the shell cleanup fdevent.
     if (SHELL_EXIT_NOTIFY_FD >= 0) {
-        int fd = local_socket_sfd_.fd();
+        int fd = local_socket_sfd_;
         if (WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd))) {
             D("passed fd %d to SHELL_EXIT_NOTIFY_FD (%d) for pid %d",
               fd, SHELL_EXIT_NOTIFY_FD, pid_);
             // The shell exit fdevent now owns the FD and will close it once
             // the last bit of data flushes through.
-            local_socket_sfd_.Release();
+            static_cast<void>(local_socket_sfd_.release());
         } else {
             PLOG(ERROR) << "failed to write fd " << fd
                         << " to SHELL_EXIT_NOTIFY_FD (" << SHELL_EXIT_NOTIFY_FD
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index aecaba2..b2555d0 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <mutex>
 #include <string>
 #include <vector>
 
@@ -35,17 +36,14 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "sysdeps/mutex.h"
 #include "transport.h"
 
-ADB_MUTEX_DEFINE( socket_list_lock );
-
-static void local_socket_close_locked(asocket *s);
-
+static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
 static unsigned local_socket_next_id = 1;
 
 static asocket local_socket_list = {
-    .next = &local_socket_list,
-    .prev = &local_socket_list,
+    .next = &local_socket_list, .prev = &local_socket_list,
 };
 
 /* the the list of currently closing local sockets.
@@ -53,62 +51,53 @@
 ** write to their fd.
 */
 static asocket local_socket_closing_list = {
-    .next = &local_socket_closing_list,
-    .prev = &local_socket_closing_list,
+    .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
 };
 
 // Parse the global list of sockets to find one with id |local_id|.
 // If |peer_id| is not 0, also check that it is connected to a peer
 // with id |peer_id|. Returns an asocket handle on success, NULL on failure.
-asocket *find_local_socket(unsigned local_id, unsigned peer_id)
-{
-    asocket *s;
-    asocket *result = NULL;
+asocket* find_local_socket(unsigned local_id, unsigned peer_id) {
+    asocket* s;
+    asocket* result = NULL;
 
-    adb_mutex_lock(&socket_list_lock);
+    std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
     for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
-        if (s->id != local_id)
+        if (s->id != local_id) {
             continue;
+        }
         if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) {
             result = s;
         }
         break;
     }
-    adb_mutex_unlock(&socket_list_lock);
 
     return result;
 }
 
-static void
-insert_local_socket(asocket*  s, asocket*  list)
-{
-    s->next       = list;
-    s->prev       = s->next->prev;
+static void insert_local_socket(asocket* s, asocket* list) {
+    s->next = list;
+    s->prev = s->next->prev;
     s->prev->next = s;
     s->next->prev = s;
 }
 
-
-void install_local_socket(asocket *s)
-{
-    adb_mutex_lock(&socket_list_lock);
+void install_local_socket(asocket* s) {
+    std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
 
     s->id = local_socket_next_id++;
 
     // Socket ids should never be 0.
-    if (local_socket_next_id == 0)
-      local_socket_next_id = 1;
+    if (local_socket_next_id == 0) {
+        fatal("local socket id overflow");
+    }
 
     insert_local_socket(s, &local_socket_list);
-
-    adb_mutex_unlock(&socket_list_lock);
 }
 
-void remove_socket(asocket *s)
-{
+void remove_socket(asocket* s) {
     // socket_list_lock should already be held
-    if (s->prev && s->next)
-    {
+    if (s->prev && s->next) {
         s->prev->next = s->next;
         s->next->prev = s->prev;
         s->next = 0;
@@ -117,50 +106,47 @@
     }
 }
 
-void close_all_sockets(atransport *t)
-{
-    asocket *s;
+void close_all_sockets(atransport* t) {
+    asocket* s;
 
-        /* this is a little gross, but since s->close() *will* modify
-        ** the list out from under you, your options are limited.
-        */
-    adb_mutex_lock(&socket_list_lock);
+    /* this is a little gross, but since s->close() *will* modify
+    ** the list out from under you, your options are limited.
+    */
+    std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
 restart:
-    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
-        if(s->transport == t || (s->peer && s->peer->transport == t)) {
-            local_socket_close_locked(s);
+    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+        if (s->transport == t || (s->peer && s->peer->transport == t)) {
+            s->close(s);
             goto restart;
         }
     }
-    adb_mutex_unlock(&socket_list_lock);
 }
 
-static int local_socket_enqueue(asocket *s, apacket *p)
-{
+static int local_socket_enqueue(asocket* s, apacket* p) {
     D("LS(%d): enqueue %d", s->id, p->len);
 
     p->ptr = p->data;
 
-        /* if there is already data queue'd, we will receive
-        ** events when it's time to write.  just add this to
-        ** the tail
-        */
-    if(s->pkt_first) {
+    /* if there is already data queue'd, we will receive
+    ** events when it's time to write.  just add this to
+    ** the tail
+    */
+    if (s->pkt_first) {
         goto enqueue;
     }
 
-        /* write as much as we can, until we
-        ** would block or there is an error/eof
-        */
-    while(p->len > 0) {
+    /* write as much as we can, until we
+    ** would block or there is an error/eof
+    */
+    while (p->len > 0) {
         int r = adb_write(s->fd, p->ptr, p->len);
-        if(r > 0) {
+        if (r > 0) {
             p->len -= r;
             p->ptr += r;
             continue;
         }
-        if((r == 0) || (errno != EAGAIN)) {
-            D( "LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno) );
+        if ((r == 0) || (errno != EAGAIN)) {
+            D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno));
             put_apacket(p);
             s->has_write_error = true;
             s->close(s);
@@ -170,55 +156,46 @@
         }
     }
 
-    if(p->len == 0) {
+    if (p->len == 0) {
         put_apacket(p);
         return 0; /* ready for more data */
     }
 
 enqueue:
     p->next = 0;
-    if(s->pkt_first) {
+    if (s->pkt_first) {
         s->pkt_last->next = p;
     } else {
         s->pkt_first = p;
     }
     s->pkt_last = p;
 
-        /* make sure we are notified when we can drain the queue */
+    /* make sure we are notified when we can drain the queue */
     fdevent_add(&s->fde, FDE_WRITE);
 
     return 1; /* not ready (backlog) */
 }
 
-static void local_socket_ready(asocket *s)
-{
+static void local_socket_ready(asocket* s) {
     /* far side is ready for data, pay attention to
        readable events */
     fdevent_add(&s->fde, FDE_READ);
 }
 
-static void local_socket_close(asocket *s)
-{
-    adb_mutex_lock(&socket_list_lock);
-    local_socket_close_locked(s);
-    adb_mutex_unlock(&socket_list_lock);
-}
-
 // be sure to hold the socket list lock when calling this
-static void local_socket_destroy(asocket  *s)
-{
+static void local_socket_destroy(asocket* s) {
     apacket *p, *n;
     int exit_on_close = s->exit_on_close;
 
     D("LS(%d): destroying fde.fd=%d", s->id, s->fde.fd);
 
-        /* IMPORTANT: the remove closes the fd
-        ** that belongs to this socket
-        */
+    /* IMPORTANT: the remove closes the fd
+    ** that belongs to this socket
+    */
     fdevent_remove(&s->fde);
 
-        /* dispose of any unwritten data */
-    for(p = s->pkt_first; p; p = n) {
+    /* dispose of any unwritten data */
+    for (p = s->pkt_first; p; p = n) {
         D("LS(%d): discarding %d bytes", s->id, p->len);
         n = p->next;
         put_apacket(p);
@@ -232,41 +209,35 @@
     }
 }
 
-
-static void local_socket_close_locked(asocket *s)
-{
-    D("entered local_socket_close_locked. LS(%d) fd=%d", s->id, s->fd);
-    if(s->peer) {
-        D("LS(%d): closing peer. peer->id=%d peer->fd=%d",
-          s->id, s->peer->id, s->peer->fd);
+static void local_socket_close(asocket* s) {
+    D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd);
+    std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
+    if (s->peer) {
+        D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
         /* Note: it's important to call shutdown before disconnecting from
          * the peer, this ensures that remote sockets can still get the id
          * of the local socket they're connected to, to send a CLOSE()
          * protocol event. */
-        if (s->peer->shutdown)
-          s->peer->shutdown(s->peer);
-        s->peer->peer = 0;
-        // tweak to avoid deadlock
-        if (s->peer->close == local_socket_close) {
-            local_socket_close_locked(s->peer);
-        } else {
-            s->peer->close(s->peer);
+        if (s->peer->shutdown) {
+            s->peer->shutdown(s->peer);
         }
-        s->peer = 0;
+        s->peer->peer = nullptr;
+        s->peer->close(s->peer);
+        s->peer = nullptr;
     }
 
-        /* If we are already closing, or if there are no
-        ** pending packets, destroy immediately
-        */
+    /* If we are already closing, or if there are no
+    ** pending packets, destroy immediately
+    */
     if (s->closing || s->has_write_error || s->pkt_first == NULL) {
-        int   id = s->id;
+        int id = s->id;
         local_socket_destroy(s);
         D("LS(%d): closed", id);
         return;
     }
 
-        /* otherwise, put on the closing list
-        */
+    /* otherwise, put on the closing list
+    */
     D("LS(%d): closing", s->id);
     s->closing = 1;
     fdevent_del(&s->fde, FDE_READ);
@@ -276,8 +247,7 @@
     CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
 }
 
-static void local_socket_event_func(int fd, unsigned ev, void* _s)
-{
+static void local_socket_event_func(int fd, unsigned ev, void* _s) {
     asocket* s = reinterpret_cast<asocket*>(_s);
     D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev);
 
@@ -334,10 +304,9 @@
         s->peer->ready(s->peer);
     }
 
-
     if (ev & FDE_READ) {
-        apacket *p = get_apacket();
-        unsigned char *x = p->data;
+        apacket* p = get_apacket();
+        unsigned char* x = p->data;
         const size_t max_payload = s->get_max_payload();
         size_t avail = max_payload;
         int r = 0;
@@ -345,8 +314,8 @@
 
         while (avail > 0) {
             r = adb_read(fd, x, avail);
-            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu",
-              s->id, s->fd, r, r < 0 ? errno : 0, avail);
+            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r,
+              r < 0 ? errno : 0, avail);
             if (r == -1) {
                 if (errno == EAGAIN) {
                     break;
@@ -361,8 +330,8 @@
             is_eof = 1;
             break;
         }
-        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d",
-          s->id, s->fd, r, is_eof, s->fde.force_eof);
+        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof,
+          s->fde.force_eof);
         if ((avail == max_payload) || (s->peer == 0)) {
             put_apacket(p);
         } else {
@@ -376,48 +345,48 @@
             D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
 
             if (r < 0) {
-                    /* error return means they closed us as a side-effect
-                    ** and we must return immediately.
-                    **
-                    ** note that if we still have buffered packets, the
-                    ** socket will be placed on the closing socket list.
-                    ** this handler function will be called again
-                    ** to process FDE_WRITE events.
-                    */
+                /* error return means they closed us as a side-effect
+                ** and we must return immediately.
+                **
+                ** note that if we still have buffered packets, the
+                ** socket will be placed on the closing socket list.
+                ** this handler function will be called again
+                ** to process FDE_WRITE events.
+                */
                 return;
             }
 
             if (r > 0) {
-                    /* if the remote cannot accept further events,
-                    ** we disable notification of READs.  They'll
-                    ** be enabled again when we get a call to ready()
-                    */
+                /* if the remote cannot accept further events,
+                ** we disable notification of READs.  They'll
+                ** be enabled again when we get a call to ready()
+                */
                 fdevent_del(&s->fde, FDE_READ);
             }
         }
         /* Don't allow a forced eof if data is still there */
         if ((s->fde.force_eof && !r) || is_eof) {
-            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d",
-              is_eof, r, s->fde.force_eof);
+            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof);
             s->close(s);
             return;
         }
     }
 
-    if (ev & FDE_ERROR){
-            /* this should be caught be the next read or write
-            ** catching it here means we may skip the last few
-            ** bytes of readable data.
-            */
+    if (ev & FDE_ERROR) {
+        /* this should be caught be the next read or write
+        ** catching it here means we may skip the last few
+        ** bytes of readable data.
+        */
         D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd);
         return;
     }
 }
 
-asocket *create_local_socket(int fd)
-{
-    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
-    if (s == NULL) fatal("cannot allocate socket");
+asocket* create_local_socket(int fd) {
+    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+    if (s == NULL) {
+        fatal("cannot allocate socket");
+    }
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
     s->ready = local_socket_ready;
@@ -430,32 +399,33 @@
     return s;
 }
 
-asocket *create_local_service_socket(const char *name,
-                                     const atransport* transport)
-{
+asocket* create_local_service_socket(const char* name, const atransport* transport) {
 #if !ADB_HOST
-    if (!strcmp(name,"jdwp")) {
+    if (!strcmp(name, "jdwp")) {
         return create_jdwp_service_socket();
     }
-    if (!strcmp(name,"track-jdwp")) {
+    if (!strcmp(name, "track-jdwp")) {
         return create_jdwp_tracker_service_socket();
     }
 #endif
     int fd = service_to_fd(name, transport);
-    if(fd < 0) return 0;
+    if (fd < 0) {
+        return 0;
+    }
 
     asocket* s = create_local_socket(fd);
     D("LS(%d): bound to '%s' via %d", s->id, name, fd);
 
 #if !ADB_HOST
     char debug[PROPERTY_VALUE_MAX];
-    if (!strncmp(name, "root:", 5))
+    if (!strncmp(name, "root:", 5)) {
         property_get("ro.debuggable", debug, "");
+    }
 
-    if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
-        || (!strncmp(name, "unroot:", 7) && getuid() == 0)
-        || !strncmp(name, "usb:", 4)
-        || !strncmp(name, "tcpip:", 6)) {
+    if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) ||
+        (!strncmp(name, "unroot:", 7) && getuid() == 0) ||
+        !strncmp(name, "usb:", 4) ||
+        !strncmp(name, "tcpip:", 6)) {
         D("LS(%d): enabling exit_on_close", s->id);
         s->exit_on_close = 1;
     }
@@ -465,9 +435,8 @@
 }
 
 #if ADB_HOST
-static asocket *create_host_service_socket(const char *name, const char* serial)
-{
-    asocket *s;
+static asocket* create_host_service_socket(const char* name, const char* serial) {
+    asocket* s;
 
     s = host_service_to_socket(name, serial);
 
@@ -480,10 +449,8 @@
 }
 #endif /* ADB_HOST */
 
-static int remote_socket_enqueue(asocket *s, apacket *p)
-{
-    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d",
-      s->id, s->fd, s->peer->fd);
+static int remote_socket_enqueue(asocket* s, apacket* p) {
+    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
     p->msg.command = A_WRTE;
     p->msg.arg0 = s->peer->id;
     p->msg.arg1 = s->id;
@@ -492,40 +459,35 @@
     return 1;
 }
 
-static void remote_socket_ready(asocket *s)
-{
-    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d",
-      s->id, s->fd, s->peer->fd);
-    apacket *p = get_apacket();
+static void remote_socket_ready(asocket* s) {
+    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+    apacket* p = get_apacket();
     p->msg.command = A_OKAY;
     p->msg.arg0 = s->peer->id;
     p->msg.arg1 = s->id;
     send_packet(p, s->transport);
 }
 
-static void remote_socket_shutdown(asocket *s)
-{
-    D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d",
-      s->id, s->fd, s->peer?s->peer->fd:-1);
-    apacket *p = get_apacket();
+static void remote_socket_shutdown(asocket* s) {
+    D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+      s->peer ? s->peer->fd : -1);
+    apacket* p = get_apacket();
     p->msg.command = A_CLSE;
-    if(s->peer) {
+    if (s->peer) {
         p->msg.arg0 = s->peer->id;
     }
     p->msg.arg1 = s->id;
     send_packet(p, s->transport);
 }
 
-static void remote_socket_close(asocket *s)
-{
+static void remote_socket_close(asocket* s) {
     if (s->peer) {
         s->peer->peer = 0;
-        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d",
-          s->id, s->peer->id, s->peer->fd);
+        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
         s->peer->close(s->peer);
     }
-    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d",
-      s->id, s->fd, s->peer?s->peer->fd:-1);
+    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+      s->peer ? s->peer->fd : -1);
     D("RS(%d): closed", s->id);
     free(s);
 }
@@ -534,12 +496,15 @@
 // |t|. Where |id| is the socket id of the corresponding service on the other
 //  side of the transport (it is allocated by the remote side and _cannot_ be 0).
 // Returns a new non-NULL asocket handle.
-asocket *create_remote_socket(unsigned id, atransport *t)
-{
-    if (id == 0) fatal("invalid remote socket id (0)");
+asocket* create_remote_socket(unsigned id, atransport* t) {
+    if (id == 0) {
+        fatal("invalid remote socket id (0)");
+    }
     asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
 
-    if (s == NULL) fatal("cannot allocate socket");
+    if (s == NULL) {
+        fatal("cannot allocate socket");
+    }
     s->id = id;
     s->enqueue = remote_socket_enqueue;
     s->ready = remote_socket_ready;
@@ -551,13 +516,12 @@
     return s;
 }
 
-void connect_to_remote(asocket *s, const char *destination)
-{
+void connect_to_remote(asocket* s, const char* destination) {
     D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd);
-    apacket *p = get_apacket();
+    apacket* p = get_apacket();
     size_t len = strlen(destination) + 1;
 
-    if(len > (s->get_max_payload()-1)) {
+    if (len > (s->get_max_payload() - 1)) {
         fatal("destination oversized");
     }
 
@@ -565,15 +529,13 @@
     p->msg.command = A_OPEN;
     p->msg.arg0 = s->id;
     p->msg.data_length = len;
-    strcpy((char*) p->data, destination);
+    strcpy((char*)p->data, destination);
     send_packet(p, s->transport);
 }
 
-
 /* this is used by magic sockets to rig local sockets to
    send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket *s)
-{
+static void local_socket_ready_notify(asocket* s) {
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
@@ -584,8 +546,7 @@
 /* this is used by magic sockets to rig local sockets to
    send the failure message if they are closed before
    connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket *s)
-{
+static void local_socket_close_notify(asocket* s) {
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
@@ -593,28 +554,41 @@
     s->close(s);
 }
 
-static unsigned unhex(unsigned char *s, int len)
-{
+static unsigned unhex(unsigned char* s, int len) {
     unsigned n = 0, c;
 
-    while(len-- > 0) {
-        switch((c = *s++)) {
-        case '0': case '1': case '2':
-        case '3': case '4': case '5':
-        case '6': case '7': case '8':
-        case '9':
-            c -= '0';
-            break;
-        case 'a': case 'b': case 'c':
-        case 'd': case 'e': case 'f':
-            c = c - 'a' + 10;
-            break;
-        case 'A': case 'B': case 'C':
-        case 'D': case 'E': case 'F':
-            c = c - 'A' + 10;
-            break;
-        default:
-            return 0xffffffff;
+    while (len-- > 0) {
+        switch ((c = *s++)) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                c -= '0';
+                break;
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+                c = c - 'a' + 10;
+                break;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+                c = c - 'A' + 10;
+                break;
+            default:
+                return 0xffffffff;
         }
 
         n = (n << 4) | c;
@@ -671,31 +645,29 @@
 
 }  // namespace internal
 
-#endif // ADB_HOST
+#endif  // ADB_HOST
 
-static int smart_socket_enqueue(asocket *s, apacket *p)
-{
+static int smart_socket_enqueue(asocket* s, apacket* p) {
     unsigned len;
 #if ADB_HOST
-    char *service = nullptr;
+    char* service = nullptr;
     char* serial = nullptr;
     TransportType type = kTransportAny;
 #endif
 
     D("SS(%d): enqueue %d", s->id, p->len);
 
-    if(s->pkt_first == 0) {
+    if (s->pkt_first == 0) {
         s->pkt_first = p;
         s->pkt_last = p;
     } else {
-        if((s->pkt_first->len + p->len) > s->get_max_payload()) {
+        if ((s->pkt_first->len + p->len) > s->get_max_payload()) {
             D("SS(%d): overflow", s->id);
             put_apacket(p);
             goto fail;
         }
 
-        memcpy(s->pkt_first->data + s->pkt_first->len,
-               p->data, p->len);
+        memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len);
         s->pkt_first->len += p->len;
         put_apacket(p);
 
@@ -703,7 +675,9 @@
     }
 
     /* don't bother if we can't decode the length */
-    if(p->len < 4) return 0;
+    if (p->len < 4) {
+        return 0;
+    }
 
     len = unhex(p->data, 4);
     if ((len < 1) || (len > MAX_PAYLOAD_V1)) {
@@ -711,27 +685,27 @@
         goto fail;
     }
 
-    D("SS(%d): len is %d", s->id, len );
+    D("SS(%d): len is %d", s->id, len);
     /* can't do anything until we have the full header */
-    if((len + 4) > p->len) {
-        D("SS(%d): waiting for %d more bytes", s->id, len+4 - p->len);
+    if ((len + 4) > p->len) {
+        D("SS(%d): waiting for %d more bytes", s->id, len + 4 - p->len);
         return 0;
     }
 
     p->data[len + 4] = 0;
 
-    D("SS(%d): '%s'", s->id, (char*) (p->data + 4));
+    D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
 
 #if ADB_HOST
-    service = (char *)p->data + 4;
-    if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
+    service = (char*)p->data + 4;
+    if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
         char* serial_end;
         service += strlen("host-serial:");
 
         // serial number should follow "host:" and could be a host:port string.
         serial_end = internal::skip_host_serial(service);
         if (serial_end) {
-            *serial_end = 0; // terminate string
+            *serial_end = 0;  // terminate string
             serial = service;
             service = serial_end + 1;
         }
@@ -749,42 +723,42 @@
     }
 
     if (service) {
-        asocket *s2;
+        asocket* s2;
 
-            /* some requests are handled immediately -- in that
-            ** case the handle_host_request() routine has sent
-            ** the OKAY or FAIL message and all we have to do
-            ** is clean up.
-            */
-        if(handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
-                /* XXX fail message? */
-            D( "SS(%d): handled host service '%s'", s->id, service );
+        /* some requests are handled immediately -- in that
+        ** case the handle_host_request() routine has sent
+        ** the OKAY or FAIL message and all we have to do
+        ** is clean up.
+        */
+        if (handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
+            /* XXX fail message? */
+            D("SS(%d): handled host service '%s'", s->id, service);
             goto fail;
         }
         if (!strncmp(service, "transport", strlen("transport"))) {
-            D( "SS(%d): okay transport", s->id );
+            D("SS(%d): okay transport", s->id);
             p->len = 0;
             return 0;
         }
 
-            /* try to find a local service with this name.
-            ** if no such service exists, we'll fail out
-            ** and tear down here.
-            */
+        /* try to find a local service with this name.
+        ** if no such service exists, we'll fail out
+        ** and tear down here.
+        */
         s2 = create_host_service_socket(service, serial);
-        if(s2 == 0) {
-            D( "SS(%d): couldn't create host service '%s'", s->id, service );
+        if (s2 == 0) {
+            D("SS(%d): couldn't create host service '%s'", s->id, service);
             SendFail(s->peer->fd, "unknown host service");
             goto fail;
         }
 
-            /* we've connected to a local host service,
-            ** so we make our peer back into a regular
-            ** local socket and bind it to the new local
-            ** service socket, acknowledge the successful
-            ** connection, and close this smart socket now
-            ** that its work is done.
-            */
+        /* we've connected to a local host service,
+        ** so we make our peer back into a regular
+        ** local socket and bind it to the new local
+        ** service socket, acknowledge the successful
+        ** connection, and close this smart socket now
+        ** that its work is done.
+        */
         SendOkay(s->peer->fd);
 
         s->peer->ready = local_socket_ready;
@@ -793,10 +767,10 @@
         s->peer->peer = s2;
         s2->peer = s->peer;
         s->peer = 0;
-        D( "SS(%d): okay", s->id );
+        D("SS(%d): okay", s->id);
         s->close(s);
 
-            /* initial state is "ready" */
+        /* initial state is "ready" */
         s2->ready(s2);
         return 0;
     }
@@ -811,53 +785,50 @@
     }
 #endif
 
-    if(!(s->transport) || (s->transport->connection_state == kCsOffline)) {
-           /* if there's no remote we fail the connection
-            ** right here and terminate it
-            */
+    if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+        /* if there's no remote we fail the connection
+         ** right here and terminate it
+         */
         SendFail(s->peer->fd, "device offline (x)");
         goto fail;
     }
 
-
-        /* instrument our peer to pass the success or fail
-        ** message back once it connects or closes, then
-        ** detach from it, request the connection, and
-        ** tear down
-        */
+    /* instrument our peer to pass the success or fail
+    ** message back once it connects or closes, then
+    ** detach from it, request the connection, and
+    ** tear down
+    */
     s->peer->ready = local_socket_ready_notify;
     s->peer->shutdown = nullptr;
     s->peer->close = local_socket_close_notify;
     s->peer->peer = 0;
-        /* give him our transport and upref it */
+    /* give him our transport and upref it */
     s->peer->transport = s->transport;
 
-    connect_to_remote(s->peer, (char*) (p->data + 4));
+    connect_to_remote(s->peer, (char*)(p->data + 4));
     s->peer = 0;
     s->close(s);
     return 1;
 
 fail:
-        /* we're going to close our peer as a side-effect, so
-        ** return -1 to signal that state to the local socket
-        ** who is enqueueing against us
-        */
+    /* we're going to close our peer as a side-effect, so
+    ** return -1 to signal that state to the local socket
+    ** who is enqueueing against us
+    */
     s->close(s);
     return -1;
 }
 
-static void smart_socket_ready(asocket *s)
-{
+static void smart_socket_ready(asocket* s) {
     D("SS(%d): ready", s->id);
 }
 
-static void smart_socket_close(asocket *s)
-{
+static void smart_socket_close(asocket* s) {
     D("SS(%d): closed", s->id);
-    if(s->pkt_first){
+    if (s->pkt_first) {
         put_apacket(s->pkt_first);
     }
-    if(s->peer) {
+    if (s->peer) {
         s->peer->peer = 0;
         s->peer->close(s->peer);
         s->peer = 0;
@@ -865,10 +836,9 @@
     free(s);
 }
 
-static asocket *create_smart_socket(void)
-{
+static asocket* create_smart_socket(void) {
     D("Creating smart socket");
-    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
     if (s == NULL) fatal("cannot allocate socket");
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
@@ -879,10 +849,9 @@
     return s;
 }
 
-void connect_to_smartsocket(asocket *s)
-{
+void connect_to_smartsocket(asocket* s) {
     D("Connecting to smart socket");
-    asocket *ss = create_smart_socket();
+    asocket* ss = create_smart_socket();
     s->peer = ss;
     ss->peer = s;
     s->ready(s);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3586da8..212c1c3 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -29,8 +29,9 @@
 #include <string>
 #include <vector>
 
-// Include this before open/unlink are defined as macros below.
+// Include this before open/close/unlink are defined as macros below.
 #include <android-base/errors.h>
+#include <android-base/unique_fd.h>
 #include <android-base/utf8.h>
 
 /*
@@ -268,9 +269,6 @@
 int unix_isatty(int fd);
 #define  isatty  ___xxx_isatty
 
-/* normally provided by <cutils/misc.h> */
-extern void*  load_file(const char*  pathname, unsigned*  psize);
-
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
     Sleep( mseconds );
@@ -457,7 +455,6 @@
 
 #else /* !_WIN32 a.k.a. Unix */
 
-#include <cutils/misc.h>
 #include <cutils/sockets.h>
 #include <cutils/threads.h>
 #include <fcntl.h>
diff --git a/adb/sysdeps/condition_variable.h b/adb/sysdeps/condition_variable.h
new file mode 100644
index 0000000..117cd40
--- /dev/null
+++ b/adb/sysdeps/condition_variable.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+
+#include "sysdeps/mutex.h"
+
+#if defined(_WIN32)
+
+#include <windows.h>
+
+#include <android-base/macros.h>
+
+// The prebuilt version of mingw we use doesn't support condition_variable.
+// Therefore, implement our own using the Windows primitives.
+// Put them directly into the std namespace, so that when they're actually available, the build
+// breaks until they're removed.
+
+namespace std {
+
+class condition_variable {
+  public:
+    condition_variable() {
+        InitializeConditionVariable(&cond_);
+    }
+
+    void wait(std::unique_lock<std::mutex>& lock) {
+        std::mutex *m = lock.mutex();
+        m->lock_count_--;
+        SleepConditionVariableCS(&cond_, m->native_handle(), INFINITE);
+        m->lock_count_++;
+    }
+
+    void notify_one() {
+        WakeConditionVariable(&cond_);
+    }
+
+  private:
+    CONDITION_VARIABLE cond_;
+
+    DISALLOW_COPY_AND_ASSIGN(condition_variable);
+};
+
+}
+
+#endif  // defined(_WIN32)
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
new file mode 100644
index 0000000..226f7f1
--- /dev/null
+++ b/adb/sysdeps/mutex.h
@@ -0,0 +1,120 @@
+/*
+ * 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
+#if defined(_WIN32)
+
+#include <windows.h>
+
+#include <android-base/macros.h>
+
+#include "adb.h"
+
+// The prebuilt version of mingw we use doesn't support mutex or recursive_mutex.
+// Therefore, implement our own using the Windows primitives.
+// Put them directly into the std namespace, so that when they're actually available, the build
+// breaks until they're removed.
+
+#include <mutex>
+namespace std {
+
+// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class.
+class recursive_mutex {
+  public:
+    typedef CRITICAL_SECTION* native_handle_type;
+
+    recursive_mutex() {
+        InitializeCriticalSection(&cs_);
+    }
+
+    ~recursive_mutex() {
+        DeleteCriticalSection(&cs_);
+    }
+
+    void lock() {
+        EnterCriticalSection(&cs_);
+    }
+
+    bool try_lock() {
+        return TryEnterCriticalSection(&cs_);
+    }
+
+    void unlock() {
+        LeaveCriticalSection(&cs_);
+    }
+
+    native_handle_type native_handle() {
+        return &cs_;
+    }
+
+  private:
+    CRITICAL_SECTION cs_;
+
+    DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
+};
+
+class mutex {
+  public:
+    typedef CRITICAL_SECTION* native_handle_type;
+
+    mutex() {
+    }
+
+    ~mutex() {
+    }
+
+    void lock() {
+        mutex_.lock();
+        if (++lock_count_ != 1) {
+            fatal("non-recursive mutex locked reentrantly");
+        }
+    }
+
+    void unlock() {
+        if (--lock_count_ != 0) {
+            fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_);
+        }
+        mutex_.unlock();
+    }
+
+    bool try_lock() {
+        if (!mutex_.try_lock()) {
+            return false;
+        }
+
+        if (lock_count_ != 0) {
+            mutex_.unlock();
+            return false;
+        }
+
+        ++lock_count_;
+        return true;
+    }
+
+    native_handle_type native_handle() {
+        return mutex_.native_handle();
+    }
+
+  private:
+    recursive_mutex mutex_;
+    size_t lock_count_ = 0;
+
+    friend class condition_variable;
+};
+
+}
+
+#endif  // defined(_WIN32)
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index fde344a..740f283 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -20,6 +20,8 @@
 
 #include "adb_io.h"
 #include "sysdeps.h"
+#include "sysdeps/condition_variable.h"
+#include "sysdeps/mutex.h"
 
 static void increment_atomic_int(void* c) {
     sleep(1);
@@ -244,3 +246,77 @@
         adb_close(fd);
     }
 }
+
+TEST(sysdeps_mutex, mutex_smoke) {
+    static std::atomic<bool> finished(false);
+    static std::mutex &m = *new std::mutex();
+    m.lock();
+    ASSERT_FALSE(m.try_lock());
+    adb_thread_create([](void*) {
+        ASSERT_FALSE(m.try_lock());
+        m.lock();
+        finished.store(true);
+        adb_sleep_ms(200);
+        m.unlock();
+    }, nullptr);
+
+    ASSERT_FALSE(finished.load());
+    adb_sleep_ms(100);
+    ASSERT_FALSE(finished.load());
+    m.unlock();
+    adb_sleep_ms(100);
+    m.lock();
+    ASSERT_TRUE(finished.load());
+    m.unlock();
+}
+
+// Our implementation on Windows aborts on double lock.
+#if defined(_WIN32)
+TEST(sysdeps_mutex, mutex_reentrant_lock) {
+    std::mutex &m = *new std::mutex();
+
+    m.lock();
+    ASSERT_FALSE(m.try_lock());
+    EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly");
+}
+#endif
+
+TEST(sysdeps_mutex, recursive_mutex_smoke) {
+    static std::recursive_mutex &m = *new std::recursive_mutex();
+
+    m.lock();
+    ASSERT_TRUE(m.try_lock());
+    m.unlock();
+
+    adb_thread_create([](void*) {
+        ASSERT_FALSE(m.try_lock());
+        m.lock();
+        adb_sleep_ms(500);
+        m.unlock();
+    }, nullptr);
+
+    adb_sleep_ms(100);
+    m.unlock();
+    adb_sleep_ms(100);
+    ASSERT_FALSE(m.try_lock());
+    m.lock();
+    m.unlock();
+}
+
+TEST(sysdeps_condition_variable, smoke) {
+    static std::mutex &m = *new std::mutex;
+    static std::condition_variable &cond = *new std::condition_variable;
+    static volatile bool flag = false;
+
+    std::unique_lock<std::mutex> lock(m);
+    adb_thread_create([](void*) {
+        m.lock();
+        flag = true;
+        cond.notify_one();
+        m.unlock();
+    }, nullptr);
+
+    while (!flag) {
+        cond.wait(lock);
+    }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index faf7f3e..f94d6fc 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -110,62 +110,6 @@
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
-/*****      replaces libs/cutils/load_file.c                          *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-void *load_file(const char *fn, unsigned *_sz)
-{
-    HANDLE    file;
-    char     *data;
-    DWORD     file_size;
-
-    std::wstring fn_wide;
-    if (!android::base::UTF8ToWide(fn, &fn_wide))
-        return NULL;
-
-    file = CreateFileW( fn_wide.c_str(),
-                        GENERIC_READ,
-                        FILE_SHARE_READ,
-                        NULL,
-                        OPEN_EXISTING,
-                        0,
-                        NULL );
-
-    if (file == INVALID_HANDLE_VALUE)
-        return NULL;
-
-    file_size = GetFileSize( file, NULL );
-    data      = NULL;
-
-    if (file_size > 0) {
-        data = (char*) malloc( file_size + 1 );
-        if (data == NULL) {
-            D("load_file: could not allocate %ld bytes", file_size );
-            file_size = 0;
-        } else {
-            DWORD  out_bytes;
-
-            if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
-                 out_bytes != file_size )
-            {
-                D("load_file: could not read %ld bytes from '%s'", file_size, fn);
-                free(data);
-                data      = NULL;
-                file_size = 0;
-            }
-        }
-    }
-    CloseHandle( file );
-
-    *_sz = (unsigned) file_size;
-    return  data;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
 /*****    common file descriptor handling                             *****/
 /*****                                                                *****/
 /**************************************************************************/
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
deleted file mode 100644
index b10f8ee..0000000
--- a/adb/test_track_devices.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// TODO: replace this with a shell/python script.
-
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <errno.h>
-#include <memory.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-
-static void
-panic( const char*  msg )
-{
-    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
-    exit(1);
-}
-
-int main(int argc, char* argv[]) {
-    const char* request = "host:track-devices";
-
-    if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
-        request = "track-jdwp";
-    }
-
-    int                  ret;
-    struct sockaddr_in   server;
-    char                 buffer[1024];
-
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(5037);
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    int s = socket( PF_INET, SOCK_STREAM, 0 );
-    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
-    if (ret < 0) panic( "could not connect to server" );
-
-    /* send the request */
-    int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
-    if (!android::base::WriteFully(s, buffer, len))
-        panic( "could not send request" );
-
-    /* read the OKAY answer */
-    if (!android::base::ReadFully(s, buffer, 4))
-        panic( "could not read request" );
-
-    printf( "server answer: %.*s\n", 4, buffer );
-
-    /* now loop */
-    while (true) {
-        char  head[5] = "0000";
-
-        if (!android::base::ReadFully(s, head, 4))
-            panic("could not read length");
-
-        int len;
-        if (sscanf(head, "%04x", &len) != 1 )
-            panic("could not decode length");
-
-        if (!android::base::ReadFully(s, buffer, len))
-            panic("could not read data");
-
-        printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
-    }
-    close(s);
-}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 55082a5..65b05b8 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -952,6 +952,8 @@
     for (const auto& transport : pending_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             adb_mutex_unlock(&transport_lock);
+            VLOG(TRANSPORT) << "socket transport " << transport->serial
+                << " is already in pending_list and fails to register";
             delete t;
             return -1;
         }
@@ -960,6 +962,8 @@
     for (const auto& transport : transport_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             adb_mutex_unlock(&transport_lock);
+            VLOG(TRANSPORT) << "socket transport " << transport->serial
+                << " is already in transport_list and fails to register";
             delete t;
             return -1;
         }
@@ -992,8 +996,7 @@
 void kick_all_tcp_devices() {
     adb_mutex_lock(&transport_lock);
     for (auto& t : transport_list) {
-        // TCP/IP devices have adb_port == 0.
-        if (t->type == kTransportLocal && t->adb_port == 0) {
+        if (t->IsTcpDevice()) {
             // Kicking breaks the read_transport thread of this transport out of any read, then
             // the read_transport thread will notify the main thread to make this transport
             // offline. Then the main thread will notify the write_transport thread to exit.
diff --git a/adb/transport.h b/adb/transport.h
index 35d7b50..46d472b 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -87,7 +87,22 @@
     char* model = nullptr;
     char* device = nullptr;
     char* devpath = nullptr;
-    int adb_port = -1;  // Use for emulators (local transport)
+    void SetLocalPortForEmulator(int port) {
+        CHECK_EQ(local_port_for_emulator_, -1);
+        local_port_for_emulator_ = port;
+    }
+
+    bool GetLocalPortForEmulator(int* port) const {
+        if (type == kTransportLocal && local_port_for_emulator_ != -1) {
+            *port = local_port_for_emulator_;
+            return true;
+        }
+        return false;
+    }
+
+    bool IsTcpDevice() const {
+        return type == kTransportLocal && local_port_for_emulator_ == -1;
+    }
 
     void* key = nullptr;
     unsigned char token[TOKEN_SIZE] = {};
@@ -128,6 +143,7 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
+    int local_port_for_emulator_ = -1;
     bool kicked_ = false;
     void (*kick_func_)(atransport*) = nullptr;
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 4121f47..31b5ad6 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -17,6 +17,8 @@
 #define TRACE_TAG TRANSPORT
 
 #include "sysdeps.h"
+#include "sysdeps/condition_variable.h"
+#include "sysdeps/mutex.h"
 #include "transport.h"
 
 #include <errno.h>
@@ -25,6 +27,8 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <vector>
+
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 
@@ -85,9 +89,9 @@
     return 0;
 }
 
-void local_connect(int port) {
+bool local_connect(int port) {
     std::string dummy;
-    local_connect_arbitrary_ports(port-1, port, &dummy);
+    return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
 }
 
 int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) {
@@ -121,18 +125,71 @@
 }
 
 #if ADB_HOST
+
+static void PollAllLocalPortsForEmulator() {
+    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    int count = ADB_LOCAL_TRANSPORT_MAX;
+
+    // Try to connect to any number of running emulator instances.
+    for ( ; count > 0; count--, port += 2 ) {
+        local_connect(port);
+    }
+}
+
+// Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
+constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
+constexpr uint32_t LOCAL_PORT_RETRY_INTERVAL_IN_MS = 1000;
+
+struct RetryPort {
+    int port;
+    uint32_t retry_count;
+};
+
+// Retry emulators just kicked.
+static std::vector<RetryPort>& retry_ports = *new std::vector<RetryPort>;
+std::mutex &retry_ports_lock = *new std::mutex;
+std::condition_variable &retry_ports_cond = *new std::condition_variable;
+
 static void client_socket_thread(void* x) {
     adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting");
+    PollAllLocalPortsForEmulator();
     while (true) {
-        int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-        int count = ADB_LOCAL_TRANSPORT_MAX;
-
-        // Try to connect to any number of running emulator instances.
-        for ( ; count > 0; count--, port += 2 ) {
-            local_connect(port);
+        std::vector<RetryPort> ports;
+        // Collect retry ports.
+        {
+            std::unique_lock<std::mutex> lock(retry_ports_lock);
+            while (retry_ports.empty()) {
+                retry_ports_cond.wait(lock);
+            }
+            retry_ports.swap(ports);
         }
-        sleep(1);
+        // Sleep here instead of the end of loop, because if we immediately try to reconnect
+        // the emulator just kicked, the adbd on the emulator may not have time to remove the
+        // just kicked transport.
+        adb_sleep_ms(LOCAL_PORT_RETRY_INTERVAL_IN_MS);
+
+        // Try connecting retry ports.
+        std::vector<RetryPort> next_ports;
+        for (auto& port : ports) {
+            VLOG(TRANSPORT) << "retry port " << port.port << ", last retry_count "
+                << port.retry_count;
+            if (local_connect(port.port)) {
+                VLOG(TRANSPORT) << "retry port " << port.port << " successfully";
+                continue;
+            }
+            if (--port.retry_count > 0) {
+                next_ports.push_back(port);
+            } else {
+                VLOG(TRANSPORT) << "stop retrying port " << port.port;
+            }
+        }
+
+        // Copy back left retry ports.
+        {
+            std::unique_lock<std::mutex> lock(retry_ports_lock);
+            retry_ports.insert(retry_ports.end(), next_ports.begin(), next_ports.end());
+        }
     }
 }
 
@@ -167,7 +224,9 @@
             D("server: new connection on fd %d", fd);
             close_on_exec(fd);
             disable_tcp_nagle(fd);
-            register_socket_transport(fd, "host", port, 1);
+            if (register_socket_transport(fd, "host", port, 1) != 0) {
+                adb_close(fd);
+            }
         }
     }
     D("transport: server_socket_thread() exiting");
@@ -261,8 +320,8 @@
                 /* Host is connected. Register the transport, and start the
                  * exchange. */
                 std::string serial = android::base::StringPrintf("host-%d", fd);
-                register_socket_transport(fd, serial.c_str(), port, 1);
-                if (!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
+                if (register_socket_transport(fd, serial.c_str(), port, 1) != 0 ||
+                    !WriteFdExactly(fd, _start_req, strlen(_start_req))) {
                     adb_close(fd);
                 }
             }
@@ -339,17 +398,32 @@
         t->sfd = -1;
         adb_close(fd);
     }
+#if ADB_HOST
+    int local_port;
+    if (t->GetLocalPortForEmulator(&local_port)) {
+        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+        std::unique_lock<std::mutex> lock(retry_ports_lock);
+        RetryPort port;
+        port.port = local_port;
+        port.retry_count = LOCAL_PORT_RETRY_COUNT;
+        retry_ports.push_back(port);
+        retry_ports_cond.notify_one();
+    }
+#endif
 }
 
 
 #if ADB_HOST
 /* Only call this function if you already hold local_transports_lock. */
-atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
+static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
 {
     int i;
     for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
-            return local_transports[i];
+        int local_port;
+        if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
+            if (local_port == adb_port) {
+                return local_transports[i];
+            }
         }
     }
     return NULL;
@@ -396,13 +470,12 @@
     t->sync_token = 1;
     t->connection_state = kCsOffline;
     t->type = kTransportLocal;
-    t->adb_port = 0;
 
 #if ADB_HOST
     if (local) {
         adb_mutex_lock( &local_transports_lock );
         {
-            t->adb_port = adb_port;
+            t->SetLocalPortForEmulator(adb_port);
             atransport* existing_transport =
                     find_emulator_transport_by_adb_port_locked(adb_port);
             int index = get_available_local_transport_index_locked();
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 0ba6b4b..c10b48c 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -400,35 +400,33 @@
     v2_descriptor.os_header = os_desc_header;
     v2_descriptor.os_desc = os_desc_compat;
 
-    if (h->control < 0) { // might have already done this before
-        D("OPENING %s", USB_FFS_ADB_EP0);
-        h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
-        if (h->control < 0) {
-            D("[ %s: cannot open control endpoint: errno=%d]", USB_FFS_ADB_EP0, errno);
+    D("OPENING %s", USB_FFS_ADB_EP0);
+    h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+    if (h->control < 0) {
+        D("[ %s: cannot open control endpoint: errno=%d]", USB_FFS_ADB_EP0, errno);
+        goto err;
+    }
+
+    ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
+    if (ret < 0) {
+        v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+        v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+        v1_descriptor.header.fs_count = 3;
+        v1_descriptor.header.hs_count = 3;
+        v1_descriptor.fs_descs = fs_descriptors;
+        v1_descriptor.hs_descs = hs_descriptors;
+        D("[ %s: Switching to V1_descriptor format errno=%d ]", USB_FFS_ADB_EP0, errno);
+        ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
+        if (ret < 0) {
+            D("[ %s: write descriptors failed: errno=%d ]", USB_FFS_ADB_EP0, errno);
             goto err;
         }
+    }
 
-        ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
-        if (ret < 0) {
-            v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
-            v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
-            v1_descriptor.header.fs_count = 3;
-            v1_descriptor.header.hs_count = 3;
-            v1_descriptor.fs_descs = fs_descriptors;
-            v1_descriptor.hs_descs = hs_descriptors;
-            D("[ %s: Switching to V1_descriptor format errno=%d ]", USB_FFS_ADB_EP0, errno);
-            ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
-            if (ret < 0) {
-                D("[ %s: write descriptors failed: errno=%d ]", USB_FFS_ADB_EP0, errno);
-                goto err;
-            }
-        }
-
-        ret = adb_write(h->control, &strings, sizeof(strings));
-        if (ret < 0) {
-            D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
-            goto err;
-        }
+    ret = adb_write(h->control, &strings, sizeof(strings));
+    if (ret < 0) {
+        D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
+        goto err;
     }
 
     h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
@@ -556,6 +554,7 @@
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
+    adb_close(h->control);
     // Notify usb_adb_open_thread to open a new connection.
     adb_mutex_lock(&h->lock);
     h->open_new_connection = true;
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index b86c232..56e2dde 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -194,13 +194,13 @@
 
 // Helper for CHECK_STRxx(s1,s2) macros.
 #define CHECK_STROP(s1, s2, sense)                                         \
-  if (LIKELY((strcmp(s1, s2) == 0) == sense))                              \
+  if (LIKELY((strcmp(s1, s2) == 0) == (sense)))                            \
     ;                                                                      \
   else                                                                     \
     ABORT_AFTER_LOG_FATAL                                                  \
     LOG(FATAL) << "Check failed: "                                         \
-               << "\"" << s1 << "\""                                       \
-               << (sense ? " == " : " != ") << "\"" << s2 << "\""
+               << "\"" << (s1) << "\""                                     \
+               << ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
 
 // Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
 #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
@@ -213,7 +213,7 @@
     if (rc != 0) {                                                     \
       errno = rc;                                                      \
       ABORT_AFTER_LOG_FATAL                                            \
-      PLOG(FATAL) << #call << " failed for " << what; \
+      PLOG(FATAL) << #call << " failed for " << (what);                \
     }                                                                  \
   } while (false)
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index ab41c55..869e60f 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -39,25 +39,33 @@
 namespace android {
 namespace base {
 
-class unique_fd final {
+struct DefaultCloser {
+  static void Close(int fd) {
+    // Even if close(2) fails with EINTR, the fd will have been closed.
+    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
+    // else's fd.
+    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+    ::close(fd);
+  }
+};
+
+template <typename Closer>
+class unique_fd_impl final {
  public:
-  unique_fd() : value_(-1) {}
+  unique_fd_impl() : value_(-1) {}
 
-  explicit unique_fd(int value) : value_(value) {}
-  ~unique_fd() { clear(); }
+  explicit unique_fd_impl(int value) : value_(value) {}
+  ~unique_fd_impl() { clear(); }
 
-  unique_fd(unique_fd&& other) : value_(other.release()) {}
-  unique_fd& operator=(unique_fd&& s) {
+  unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
+  unique_fd_impl& operator=(unique_fd_impl&& s) {
     reset(s.release());
     return *this;
   }
 
   void reset(int new_value) {
     if (value_ != -1) {
-      // Even if close(2) fails with EINTR, the fd will have been closed.
-      // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
-      // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
-      close(value_);
+      Closer::Close(value_);
     }
     value_ = new_value;
   }
@@ -78,10 +86,12 @@
  private:
   int value_;
 
-  unique_fd(const unique_fd&);
-  void operator=(const unique_fd&);
+  unique_fd_impl(const unique_fd_impl&);
+  void operator=(const unique_fd_impl&);
 };
 
+using unique_fd = unique_fd_impl<DefaultCloser>;
+
 }  // namespace base
 }  // namespace android
 
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 9959f2e..3d99cab 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -29,7 +29,7 @@
 
 #include "elf_utils.h"
 
-#define NOTE_ALIGN(size)  ((size + 3) & ~3)
+#define NOTE_ALIGN(size)  (((size) + 3) & ~3)
 
 template <typename HdrType, typename PhdrType, typename NhdrType>
 static bool get_build_id(
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
index c7796ef..762bae5 100644
--- a/debuggerd/test/host_signal_fixup.h
+++ b/debuggerd/test/host_signal_fixup.h
@@ -57,7 +57,7 @@
 #endif
 
 #if !defined(SI_DETHREAD)
-#define SI_DETHREAD -7
+#define SI_DETHREAD (-7)
 #endif
 
 #endif
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index cd673f3..d9e17bb 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -16,8 +16,8 @@
 
 #include <sys/cdefs.h>
 
-#define FS_MGR_SETUP_VERITY_DISABLED -2
-#define FS_MGR_SETUP_VERITY_FAIL -1
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
 
 __BEGIN_DECLS
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/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c5e1f32..b498618 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -80,11 +80,11 @@
 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
-#define FS_MGR_MNTALL_FAIL -1
+#define FS_MGR_MNTALL_FAIL (-1)
 int fs_mgr_mount_all(struct fstab *fstab);
 
-#define FS_MGR_DOMNT_FAILED -1
-#define FS_MGR_DOMNT_BUSY -2
+#define FS_MGR_DOMNT_FAILED (-1)
+#define FS_MGR_DOMNT_BUSY (-2)
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
diff --git a/include/cutils/aref.h b/include/cutils/aref.h
deleted file mode 100644
index 3bd36ea..0000000
--- a/include/cutils/aref.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2013 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 _CUTILS_AREF_H_
-#define _CUTILS_AREF_H_
-
-#include <stddef.h>
-#include <sys/cdefs.h>
-
-#include <cutils/atomic.h>
-
-__BEGIN_DECLS
-
-#define AREF_TO_ITEM(aref, container, member) \
-    (container *) (((char*) (aref)) - offsetof(container, member))
-
-struct aref
-{
-    volatile int32_t count;
-};
-
-static inline void aref_init(struct aref *r)
-{
-    r->count = 1;
-}
-
-static inline int32_t aref_count(struct aref *r)
-{
-    return r->count;
-}
-
-static inline void aref_get(struct aref *r)
-{
-    android_atomic_inc(&r->count);
-}
-
-static inline void aref_put(struct aref *r, void (*release)(struct aref *))
-{
-    if (android_atomic_dec(&r->count) == 1)
-        release(r);
-}
-
-__END_DECLS
-
-#endif // _CUTILS_AREF_H_
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/private/canned_fs_config.h b/include/private/canned_fs_config.h
new file mode 100644
index 0000000..d9f51ca
--- /dev/null
+++ b/include/private/canned_fs_config.h
@@ -0,0 +1,26 @@
+/*
+ * 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 _CANNED_FS_CONFIG_H
+#define _CANNED_FS_CONFIG_H
+
+#include <inttypes.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/RefBase.h b/include/utils/RefBase.h
index eac6a78..14d9cb1 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_REF_BASE_H
 #define ANDROID_REF_BASE_H
 
-#include <cutils/atomic.h>
+#include <atomic>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -176,16 +176,17 @@
 public:
     inline LightRefBase() : mCount(0) { }
     inline void incStrong(__attribute__((unused)) const void* id) const {
-        android_atomic_inc(&mCount);
+        mCount.fetch_add(1, std::memory_order_relaxed);
     }
     inline void decStrong(__attribute__((unused)) const void* id) const {
-        if (android_atomic_dec(&mCount) == 1) {
+        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
+            std::atomic_thread_fence(std::memory_order_acquire);
             delete static_cast<const T*>(this);
         }
     }
     //! DEBUGGING ONLY: Get current strong ref count.
     inline int32_t getStrongCount() const {
-        return mCount;
+        return mCount.load(std::memory_order_relaxed);
     }
 
     typedef LightRefBase<T> basetype;
@@ -200,7 +201,7 @@
             const void* old_id, const void* new_id) { }
 
 private:
-    mutable volatile int32_t mCount;
+    mutable std::atomic<int32_t> mCount;
 };
 
 // This is a wrapper around LightRefBase that simply enforces a virtual
diff --git a/init/devices.cpp b/init/devices.cpp
index d452dd3..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)
 {
@@ -747,7 +743,7 @@
 static void handle_device_event(struct uevent *uevent)
 {
     if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
-        fixup_sys_perms(uevent->path);
+        fixup_sys_perms(uevent->path, uevent->subsystem);
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
         handle_block_device_event(uevent);
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 09f4638..baff58c 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -38,7 +38,7 @@
 #include "ueventd_keywords.h"
 
 #define KEYWORD(symbol, flags, nargs) \
-    [ K_##symbol ] = { #symbol, nargs + 1, flags, },
+    [ K_##symbol ] = { #symbol, (nargs) + 1, flags, },
 
 static struct {
     const char *name;
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index b4dc48d..6d750ea 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -24,7 +24,7 @@
 
 // This is an extremely simplified version of libpagemap.
 
-#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
 
 #define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
 #define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index df6c6c1..7066c79 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -1420,7 +1420,7 @@
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
-#define MAX_LEAK_BYTES 32*1024UL
+#define MAX_LEAK_BYTES (32*1024UL)
 
 void CheckForLeak(pid_t pid, pid_t tid) {
   // Do a few runs to get the PSS stable.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index b5780b8..822a7d3 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -19,6 +19,7 @@
 libcutils_common_sources := \
         config_utils.c \
         fs_config.c \
+        canned_fs_config.c \
         hashmap.c \
         iosched_policy.c \
         load_file.c \
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index c85f06b..1f9f753 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -62,12 +62,12 @@
 
 int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_NOT_PURGED;
+    return 0 /*ASHMEM_NOT_PURGED*/;
 }
 
 int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_IS_UNPINNED;
+    return 0 /*ASHMEM_IS_UNPINNED*/;
 }
 
 int ashmem_get_size_region(int fd)
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
new file mode 100644
index 0000000..5800857
--- /dev/null
+++ b/libcutils/canned_fs_config.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/canned_fs_config.h>
+
+typedef struct {
+	const char* path;
+	unsigned uid;
+	unsigned gid;
+	unsigned mode;
+	uint64_t capabilities;
+} Path;
+
+static Path* canned_data = NULL;
+static int canned_alloc = 0;
+static int canned_used = 0;
+
+static int path_compare(const void* a, const void* b) {
+	return strcmp(((Path*)a)->path, ((Path*)b)->path);
+}
+
+int load_canned_fs_config(const char* fn) {
+	FILE* f = fopen(fn, "r");
+	if (f == NULL) {
+		fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
+		return -1;
+	}
+
+	char line[PATH_MAX + 200];
+	while (fgets(line, sizeof(line), f)) {
+		while (canned_used >= canned_alloc) {
+			canned_alloc = (canned_alloc+1) * 2;
+			canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+		}
+		Path* p = canned_data + canned_used;
+		p->path = strdup(strtok(line, " "));
+		p->uid = atoi(strtok(NULL, " "));
+		p->gid = atoi(strtok(NULL, " "));
+		p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
+		p->capabilities = 0;
+
+		char* token = NULL;
+		do {
+			token = strtok(NULL, " ");
+			if (token && strncmp(token, "capabilities=", 13) == 0) {
+				p->capabilities = strtoll(token+13, NULL, 0);
+				break;
+			}
+		} while (token);
+
+		canned_used++;
+	}
+
+	fclose(f);
+
+	qsort(canned_data, canned_used, sizeof(Path), path_compare);
+	printf("loaded %d fs_config entries\n", canned_used);
+
+	return 0;
+}
+
+static const int kDebugCannedFsConfig = 0;
+
+void canned_fs_config(const char* path, int dir, const char* target_out_path,
+					  unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
+	Path key;
+    key.path = path;
+    if (path[0] == '/')
+        key.path++;   // canned paths lack the leading '/'
+	Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
+	if (p == NULL) {
+		fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+		exit(1);
+	}
+	*uid = p->uid;
+	*gid = p->gid;
+	*mode = p->mode;
+	*capabilities = p->capabilities;
+
+	if (kDebugCannedFsConfig) {
+		// for debugging, run the built-in fs_config and compare the results.
+
+		unsigned c_uid, c_gid, c_mode;
+		uint64_t c_capabilities;
+		fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+
+		if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
+		if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
+		if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
+		if (c_capabilities != *capabilities)
+			printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
+				path,
+				*capabilities,
+				c_capabilities);
+        }
+}
diff --git a/libcutils/strdup8to16.c b/libcutils/strdup8to16.c
index 63e5ca4..c23cf8b 100644
--- a/libcutils/strdup8to16.c
+++ b/libcutils/strdup8to16.c
@@ -27,7 +27,7 @@
 #define UTF16_REPLACEMENT_CHAR 0xfffd
 
 /* Clever trick from Dianne that returns 1-4 depending on leading bit sequence*/
-#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1)
+#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> (((ch) >> 3) & 0x1e)) & 3) + 1)
 
 /* note: macro expands to multiple lines */
 #define UTF8_SHIFT_AND_MASK(unicode, byte)  \
diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h
index 5af39d0..3c28080 100644
--- a/libion/kernel-headers/linux/ion.h
+++ b/libion/kernel-headers/linux/ion.h
@@ -38,7 +38,7 @@
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
 #define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
-#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
 #define ION_FLAG_CACHED 1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define ION_FLAG_CACHED_NEEDS_SYNC 2
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 67f4c20..49a3b75 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -27,21 +27,21 @@
 extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
 
 #define read_transport_for_each(transp, transports)                         \
-    for (transp = node_to_item((transports)->next,                          \
+    for ((transp) = node_to_item((transports)->next,                        \
                                struct android_log_transport_read, node);    \
-         (transp != node_to_item(transports,                                \
+         ((transp) != node_to_item(transports,                              \
                                  struct android_log_transport_read, node)); \
-         transp = node_to_item(transp->node.next,                           \
+         (transp) = node_to_item((transp)->node.next,                       \
                                struct android_log_transport_read, node))    \
 
 #define read_transport_for_each_safe(transp, n, transports)                 \
-    for (transp = node_to_item((transports)->next,                          \
+    for ((transp) = node_to_item((transports)->next,                        \
                                struct android_log_transport_read, node),    \
-         n = transp->node.next;                                             \
-         (transp != node_to_item(transports,                                \
+         (n) = (transp)->node.next;                                         \
+         ((transp) != node_to_item(transports,                              \
                                  struct android_log_transport_read, node)); \
-         transp = node_to_item(n, struct android_log_transport_read, node), \
-         n = transp->node.next)
+         (transp) = node_to_item(n, struct android_log_transport_read, node), \
+         (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_read();
 
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3a02a4e..3b01a9a 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -27,21 +27,21 @@
 extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
 
 #define write_transport_for_each(transp, transports)                         \
-    for (transp = node_to_item((transports)->next,                           \
-                               struct android_log_transport_write, node);    \
-         (transp != node_to_item(transports,                                 \
+    for ((transp) = node_to_item((transports)->next,                         \
+                                 struct android_log_transport_write, node);  \
+         ((transp) != node_to_item(transports,                               \
                                  struct android_log_transport_write, node)); \
-         transp = node_to_item(transp->node.next,                            \
-                               struct android_log_transport_write, node))    \
+         (transp) = node_to_item((transp)->node.next,                        \
+                                 struct android_log_transport_write, node))  \
 
 #define write_transport_for_each_safe(transp, n, transports)                 \
-    for (transp = node_to_item((transports)->next,                           \
-                               struct android_log_transport_write, node),    \
-         n = transp->node.next;                                              \
-         (transp != node_to_item(transports,                                 \
-                                 struct android_log_transport_write, node)); \
-         transp = node_to_item(n, struct android_log_transport_write, node), \
-         n = transp->node.next)
+    for ((transp) = node_to_item((transports)->next,                         \
+                                 struct android_log_transport_write, node),  \
+         (n) = (transp)->node.next;                                          \
+         ((transp) != node_to_item(transports,                               \
+                                   struct android_log_transport_write, node)); \
+         (transp) = node_to_item(n, struct android_log_transport_write, node), \
+         (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_write();
 
diff --git a/liblog/logger.h b/liblog/logger.h
index c727f29..5087256 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -124,23 +124,23 @@
 
 /* assumes caller has structures read-locked, single threaded, or fenced */
 #define transport_context_for_each(transp, logger_list)              \
-  for (transp = node_to_item((logger_list)->transport.next,          \
+  for ((transp) = node_to_item((logger_list)->transport.next,        \
                              struct android_log_transport_context,   \
                              node);                                  \
-       (transp != node_to_item(&(logger_list)->transport,            \
+       ((transp) != node_to_item(&(logger_list)->transport,          \
                                struct android_log_transport_context, \
                                node)) &&                             \
-           (transp->parent == (logger_list));                        \
-       transp = node_to_item(transp->node.next,                      \
+           ((transp)->parent == (logger_list));                      \
+       (transp) = node_to_item((transp)->node.next,                  \
                              struct android_log_transport_context, node))
 
 #define logger_for_each(logp, logger_list)                          \
-    for (logp = node_to_item((logger_list)->logger.next,            \
+    for ((logp) = node_to_item((logger_list)->logger.next,          \
                              struct android_log_logger, node);      \
-         (logp != node_to_item(&(logger_list)->logger,              \
+         ((logp) != node_to_item(&(logger_list)->logger,            \
                                struct android_log_logger, node)) && \
-             (logp->parent == (logger_list));                       \
-         logp = node_to_item((logp)->node.next,                     \
+             ((logp)->parent == (logger_list));                     \
+         (logp) = node_to_item((logp)->node.next,                   \
                              struct android_log_logger, node))
 
 /* OS specific dribs and drabs */
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 0d6ba08..00157b7 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -125,7 +125,7 @@
     ssize_t ret = -EINVAL;                                                    \
     struct android_log_transport_context *transp;                             \
     struct android_log_logger *logger_internal =                              \
-            (struct android_log_logger *)logger;                              \
+            (struct android_log_logger *)(logger);                            \
                                                                               \
     if (!logger_internal) {                                                   \
         return ret;                                                           \
@@ -186,7 +186,7 @@
 #define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                 \
     struct android_log_transport_context *transp;                             \
     struct android_log_logger_list *logger_list_internal =                    \
-            (struct android_log_logger_list *)logger_list;                    \
+            (struct android_log_logger_list *)(logger_list);                  \
                                                                               \
     ssize_t ret = init_transport_context(logger_list_internal);               \
     if (ret < 0) {                                                            \
@@ -341,6 +341,43 @@
     return logger_list;
 }
 
+/* Validate log_msg packet, read function has already been null checked */
+static int android_transport_read(struct android_log_logger_list *logger_list,
+                                  struct android_log_transport_context *transp,
+                                  struct log_msg *log_msg)
+{
+    int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+
+    if (ret > (int)sizeof(*log_msg)) {
+        ret = sizeof(*log_msg);
+    }
+
+    transp->ret = ret;
+
+    /* propagate errors, or make sure len & hdr_size members visible */
+    if (ret < (int)(sizeof(log_msg->entry.len) +
+                    sizeof(log_msg->entry.hdr_size))) {
+        if (ret >= (int)sizeof(log_msg->entry.len)) {
+            log_msg->entry.len = 0;
+        }
+        return ret;
+    }
+
+    /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+    if (log_msg->entry_v2.hdr_size == 0) {
+        log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+    }
+
+    /* len validation */
+    if (ret <= log_msg->entry_v2.hdr_size) {
+        log_msg->entry.len = 0;
+    } else {
+        log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+    }
+
+    return ret;
+}
+
 /* Read from the selected logs */
 LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
                                                struct log_msg *log_msg)
@@ -378,7 +415,7 @@
                     } else if ((logger_list_internal->mode &
                                 ANDROID_LOG_NONBLOCK) ||
                             !transp->transport->poll) {
-                        retval = transp->ret = (*transp->transport->read)(
+                        retval = android_transport_read(
                                 logger_list_internal,
                                 transp,
                                 &transp->logMsg);
@@ -397,7 +434,7 @@
                             }
                             retval = transp->ret = pollval;
                         } else if (pollval > 0) {
-                            retval = transp->ret = (*transp->transport->read)(
+                            retval = android_transport_read(
                                     logger_list_internal,
                                     transp,
                                     &transp->logMsg);
@@ -434,16 +471,22 @@
         if (!oldest) {
             return ret;
         }
-        memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
-                    (oldest->logMsg.entry.hdr_size ?
-                        oldest->logMsg.entry.hdr_size :
-                        sizeof(struct logger_entry)));
+        // ret is a positive value less than sizeof(struct log_msg)
+        ret = oldest->ret;
+        if (ret < oldest->logMsg.entry.hdr_size) {
+            // zero truncated header fields.
+            memset(log_msg, 0,
+                   (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
+                       sizeof(oldest->logMsg) :
+                       oldest->logMsg.entry.hdr_size));
+        }
+        memcpy(log_msg, &oldest->logMsg, ret);
         oldest->logMsg.entry.len = 0; /* Mark it as copied */
-        return oldest->ret;
+        return ret;
     }
 
     /* if only one, no need to copy into transport_context and merge-sort */
-    return (transp->transport->read)(logger_list_internal, transp, log_msg);
+    return android_transport_read(logger_list_internal, transp, log_msg);
 }
 
 /* Close all the logs */
diff --git a/liblog/tests/benchmark.h b/liblog/tests/benchmark.h
index 7f96e6d..57b3748 100644
--- a/liblog/tests/benchmark.h
+++ b/liblog/tests/benchmark.h
@@ -141,7 +141,7 @@
 void StopBenchmarkTiming(uint64_t);
 
 #define BENCHMARK(f) \
-    static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
-        (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f)
+    static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = /* NOLINT */ \
+        (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f) /* NOLINT */
 
 #endif // BIONIC_BENCHMARK_H_
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 21d9ebd..b528214 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -26,7 +26,7 @@
 
 #include <hardware/memtrack.h>
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
 static const memtrack_module_t *module;
 
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
index 879a3a0..e85df5f 100644
--- a/libmemunreachable/tests/LeakFolding_test.cpp
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -37,10 +37,10 @@
   Heap heap_;
 };
 
-#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&buffer[0])
-#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&buffer[0]) + sizeof(buffer))
+#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&(buffer)[0])
+#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&(buffer)[0]) + sizeof(buffer))
 #define ALLOCATION(heap_walker, buffer) \
-  ASSERT_EQ(true, heap_walker.Allocation(buffer_begin(buffer), buffer_end(buffer)))
+  ASSERT_EQ(true, (heap_walker).Allocation(buffer_begin(buffer), buffer_end(buffer)))
 
 TEST_F(LeakFoldingTest, one) {
   void* buffer1[1] = {nullptr};
diff --git a/libnativeloader/dlext_namespaces.h b/libnativeloader/dlext_namespaces.h
index ca9e619..13a44e2 100644
--- a/libnativeloader/dlext_namespaces.h
+++ b/libnativeloader/dlext_namespaces.h
@@ -83,7 +83,8 @@
                                                             const char* ld_library_path,
                                                             const char* default_library_path,
                                                             uint64_t type,
-                                                            const char* permitted_when_isolated_path);
+                                                            const char* permitted_when_isolated_path,
+                                                            android_namespace_t* parent);
 
 __END_DECLS
 
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 927cbec..713a59d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -95,13 +95,14 @@
       namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
     }
 
+    android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+
     ns = android_create_namespace("classloader-namespace",
                                   nullptr,
                                   library_path.c_str(),
                                   namespace_type,
-                                  java_permitted_path != nullptr ?
-                                      permitted_path.c_str() :
-                                      nullptr);
+                                  permitted_path.c_str(),
+                                  parent_ns);
 
     if (ns != nullptr) {
       namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
@@ -202,6 +203,29 @@
     return initialized_;
   }
 
+  jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
+    jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
+    jmethodID get_parent = env->GetMethodID(class_loader_class,
+                                            "getParent",
+                                            "()Ljava/lang/ClassLoader;");
+
+    return env->CallObjectMethod(class_loader, get_parent);
+  }
+
+  android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+    jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+
+    while (parent_class_loader != nullptr) {
+      android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
+      if (ns != nullptr) {
+        return ns;
+      }
+
+      parent_class_loader = GetParentClassLoader(env, parent_class_loader);
+    }
+    return nullptr;
+  }
+
   bool initialized_;
   std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
   std::string public_libraries_;
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index c6b9fe4..56e1d59 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -243,12 +243,8 @@
     property_set(result_prop_name, "");
 
     /* Start the daemon and wait until it's ready */
-    if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
-                 p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
-    else
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
-                 p2p_interface, DHCP_CONFIG_PATH, interface);
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+            p2p_interface);
     memset(prop_value, '\0', PROPERTY_VALUE_MAX);
     property_set(ctrl_prop, daemon_cmd);
     if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
@@ -288,7 +284,8 @@
             DAEMON_PROP_NAME,
             p2p_interface);
 
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+            p2p_interface);
 
     /* Stop the daemon and wait until it's reported to be stopped */
     property_set(ctrl_prop, daemon_cmd);
@@ -317,7 +314,8 @@
             DAEMON_PROP_NAME,
             p2p_interface);
 
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+            p2p_interface);
 
     /* Stop the daemon and wait until it's reported to be stopped */
     property_set(ctrl_prop, daemon_cmd);
@@ -357,8 +355,8 @@
     property_set(result_prop_name, "");
 
     /* Start the renew daemon and wait until it's ready */
-    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW,
-            p2p_interface, interface);
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME_RENEW,
+            p2p_interface);
     memset(prop_value, '\0', PROPERTY_VALUE_MAX);
     property_set(ctrl_prop, daemon_cmd);
 
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index 39dd614..5cbd63d 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -279,14 +279,14 @@
 	"4.0", "5.0", "0.5", "10.0"
 };
 
-#define insn_condition(x)	arm32_insn_conditions[(x >> 28) & 0x0f]
-#define insn_blktrans(x)	insn_block_transfers[(x >> 23) & 3]
-#define insn_stkblktrans(x)	insn_stack_block_transfers[(3*((x >> 20)&1))^((x >> 23)&3)]
-#define op2_shift(x)		op_shifts[(x >> 5) & 3]
-#define insn_fparnd(x)		insn_fpa_rounding[(x >> 5) & 0x03]
-#define insn_fpaprec(x)		insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
-#define insn_fpaprect(x)	insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
-#define insn_fpaimm(x)		insn_fpaconstants[x & 0x07]
+#define insn_condition(x)	arm32_insn_conditions[((x) >> 28) & 0x0f]
+#define insn_blktrans(x)	insn_block_transfers[((x) >> 23) & 3]
+#define insn_stkblktrans(x)	insn_stack_block_transfers[(3*(((x) >> 20)&1))^(((x) >> 23)&3)]
+#define op2_shift(x)		op_shifts[((x) >> 5) & 3]
+#define insn_fparnd(x)		insn_fpa_rounding[((x) >> 5) & 0x03]
+#define insn_fpaprec(x)		insn_fpa_precision[((((x) >> 18) & 2)|((x) >> 7)) & 1]
+#define insn_fpaprect(x)	insn_fpa_precision[((((x) >> 21) & 2)|((x) >> 15)) & 1]
+#define insn_fpaimm(x)		insn_fpaconstants[(x) & 0x07]
 
 /* Local prototypes */
 static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
index d45dabc..563b0f1 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_context.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_context.h
@@ -120,7 +120,7 @@
 template<bool> struct CTA;
 template<> struct CTA<true> { };
 
-#define GGL_CONTEXT(con, c)         context_t *con = static_cast<context_t *>(c)
+#define GGL_CONTEXT(con, c)         context_t *(con) = static_cast<context_t *>(c) /* NOLINT */
 #define GGL_OFFSETOF(field)         uintptr_t(&(((context_t*)0)->field))
 #define GGL_INIT_PROC(p, f)         p.f = ggl_ ## f;
 #define GGL_BETWEEN(x, L, H)        (uint32_t((x)-(L)) <= ((H)-(L)))
@@ -136,14 +136,14 @@
 // ----------------------------------------------------------------------------
 
 #define GGL_RESERVE_NEEDS(name, l, s)                               \
-    const uint32_t  GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<l);  \
+    const uint32_t  GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<(l));  \
     const uint32_t  GGL_NEEDS_##name##_SHIFT = (l);
 
 #define GGL_BUILD_NEEDS(val, name)                                  \
     (((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
 
 #define GGL_READ_NEEDS(name, n)                                     \
-    (uint32_t(n & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
+    (uint32_t((n) & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
 
 #define GGL_NEED_MASK(name)     (uint32_t(GGL_NEEDS_##name##_MASK))
 #define GGL_NEED(name, val)     GGL_BUILD_NEEDS(val, name)
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index f48e1d0..aa18360 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -26,10 +26,6 @@
 #include <cutils/memory.h>
 #include <cutils/log.h>
 
-#ifdef __arm__
-#include <machine/cpu-features.h>
-#endif
-
 #include "buffer.h"
 #include "scanline.h"
 
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index cd30800..d284736 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -57,7 +57,7 @@
 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
 
 #define container_of(inner, outer_t, elem) \
-	((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+	((outer_t *)((char *)(inner) - offsetof(outer_t, elem)))
 
 struct output_file_ops {
 	int (*open)(struct output_file *, int fd);
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 22162fa..085b314 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -27,7 +27,6 @@
 
 #include <utils/RefBase.h>
 
-#include <utils/Atomic.h>
 #include <utils/CallStack.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
@@ -57,6 +56,68 @@
 
 namespace android {
 
+// Usage, invariants, etc:
+
+// It is normally OK just to keep weak pointers to an object.  The object will
+// be deallocated by decWeak when the last weak reference disappears.
+// Once a a strong reference has been created, the object will disappear once
+// the last strong reference does (decStrong).
+// AttemptIncStrong will succeed if the object has a strong reference, or if it
+// has a weak reference and has never had a strong reference.
+// AttemptIncWeak really does succeed only if there is already a WEAK
+// reference, and thus may fail when attemptIncStrong would succeed.
+// OBJECT_LIFETIME_WEAK changes this behavior to retain the object
+// unconditionally until the last reference of either kind disappears.  The
+// client ensures that the extendObjectLifetime call happens before the dec
+// call that would otherwise have deallocated the object, or before an
+// attemptIncStrong call that might rely on it.  We do not worry about
+// concurrent changes to the object lifetime.
+// mStrong is the strong reference count.  mWeak is the weak reference count.
+// Between calls, and ignoring memory ordering effects, mWeak includes strong
+// references, and is thus >= mStrong.
+//
+// A weakref_impl is allocated as the value of mRefs in a RefBase object on
+// construction.
+// In the OBJECT_LIFETIME_STRONG case, it is deallocated in the RefBase
+// destructor iff the strong reference count was never incremented. The
+// destructor can be invoked either from decStrong, or from decWeak if there
+// was never a strong reference. If the reference count had been incremented,
+// it is deallocated directly in decWeak, and hence still lives as long as
+// the last weak reference.
+// In the OBJECT_LIFETIME_WEAK case, it is always deallocated from the RefBase
+// destructor, which is always invoked by decWeak. DecStrong explicitly avoids
+// the deletion in this case.
+//
+// Memory ordering:
+// The client must ensure that every inc() call, together with all other
+// accesses to the object, happens before the corresponding dec() call.
+//
+// We try to keep memory ordering constraints on atomics as weak as possible,
+// since memory fences or ordered memory accesses are likely to be a major
+// performance cost for this code. All accesses to mStrong, mWeak, and mFlags
+// explicitly relax memory ordering in some way.
+//
+// The only operations that are not memory_order_relaxed are reference count
+// decrements. All reference count decrements are release operations.  In
+// addition, the final decrement leading the deallocation is followed by an
+// acquire fence, which we can view informally as also turning it into an
+// acquire operation.  (See 29.8p4 [atomics.fences] for details. We could
+// alternatively use acq_rel operations for all decrements. This is probably
+// slower on most current (2016) hardware, especially on ARMv7, but that may
+// not be true indefinitely.)
+//
+// This convention ensures that the second-to-last decrement synchronizes with
+// (in the language of 1.10 in the C++ standard) the final decrement of a
+// reference count. Since reference counts are only updated using atomic
+// read-modify-write operations, this also extends to any earlier decrements.
+// (See "release sequence" in 1.10.)
+//
+// Since all operations on an object happen before the corresponding reference
+// count decrement, and all reference count decrements happen before the final
+// one, we are guaranteed that all other object accesses happen before the
+// object is destroyed.
+
+
 #define INITIAL_STRONG_VALUE (1<<28)
 
 // ---------------------------------------------------------------------------
@@ -64,10 +125,10 @@
 class RefBase::weakref_impl : public RefBase::weakref_type
 {
 public:
-    volatile int32_t    mStrong;
-    volatile int32_t    mWeak;
-    RefBase* const      mBase;
-    volatile int32_t    mFlags;
+    std::atomic<int32_t>    mStrong;
+    std::atomic<int32_t>    mWeak;
+    RefBase* const          mBase;
+    std::atomic<int32_t>    mFlags;
 
 #if !DEBUG_REFS
 
@@ -141,7 +202,7 @@
     void addStrongRef(const void* id) {
         //ALOGD_IF(mTrackEnabled,
         //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
-        addRef(&mStrongRefs, id, mStrong);
+        addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed));
     }
 
     void removeStrongRef(const void* id) {
@@ -150,7 +211,7 @@
         if (!mRetain) {
             removeRef(&mStrongRefs, id);
         } else {
-            addRef(&mStrongRefs, id, -mStrong);
+            addRef(&mStrongRefs, id, -mStrong.load(std::memory_order_relaxed));
         }
     }
 
@@ -162,14 +223,14 @@
     }
 
     void addWeakRef(const void* id) {
-        addRef(&mWeakRefs, id, mWeak);
+        addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));
     }
 
     void removeWeakRef(const void* id) {
         if (!mRetain) {
             removeRef(&mWeakRefs, id);
         } else {
-            addRef(&mWeakRefs, id, -mWeak);
+            addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed));
         }
     }
 
@@ -330,7 +391,7 @@
     refs->incWeak(id);
     
     refs->addStrongRef(id);
-    const int32_t c = android_atomic_inc(&refs->mStrong);
+    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
     ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
 #if PRINT_REFS
     ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
@@ -339,7 +400,10 @@
         return;
     }
 
-    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+            std::memory_order_relaxed);
+    // A decStrong() must still happen after us.
+    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
     refs->mBase->onFirstRef();
 }
 
@@ -347,27 +411,39 @@
 {
     weakref_impl* const refs = mRefs;
     refs->removeStrongRef(id);
-    const int32_t c = android_atomic_dec(&refs->mStrong);
+    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
 #if PRINT_REFS
     ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
 #endif
     ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
     if (c == 1) {
+        std::atomic_thread_fence(std::memory_order_acquire);
         refs->mBase->onLastStrongRef(id);
-        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
+        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
             delete this;
+            // Since mStrong had been incremented, the destructor did not
+            // delete refs.
         }
     }
+    // Note that even with only strong reference operations, the thread
+    // deallocating this may not be the same as the thread deallocating refs.
+    // That's OK: all accesses to this happen before its deletion here,
+    // and all accesses to refs happen before its deletion in the final decWeak.
+    // The destructor can safely access mRefs because either it's deleting
+    // mRefs itself, or it's running entirely before the final mWeak decrement.
     refs->decWeak(id);
 }
 
 void RefBase::forceIncStrong(const void* id) const
 {
+    // Allows initial mStrong of 0 in addition to INITIAL_STRONG_VALUE.
+    // TODO: Better document assumptions.
     weakref_impl* const refs = mRefs;
     refs->incWeak(id);
     
     refs->addStrongRef(id);
-    const int32_t c = android_atomic_inc(&refs->mStrong);
+    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
     ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
                refs);
 #if PRINT_REFS
@@ -376,7 +452,8 @@
 
     switch (c) {
     case INITIAL_STRONG_VALUE:
-        android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+        refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+                std::memory_order_relaxed);
         // fall through...
     case 0:
         refs->mBase->onFirstRef();
@@ -385,7 +462,8 @@
 
 int32_t RefBase::getStrongCount() const
 {
-    return mRefs->mStrong;
+    // Debugging only; No memory ordering guarantees.
+    return mRefs->mStrong.load(std::memory_order_relaxed);
 }
 
 RefBase* RefBase::weakref_type::refBase() const
@@ -397,7 +475,8 @@
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->addWeakRef(id);
-    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
+    const int32_t c __unused = impl->mWeak.fetch_add(1,
+            std::memory_order_relaxed);
     ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
 }
 
@@ -406,16 +485,19 @@
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->removeWeakRef(id);
-    const int32_t c = android_atomic_dec(&impl->mWeak);
+    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
     ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
     if (c != 1) return;
+    atomic_thread_fence(std::memory_order_acquire);
 
-    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
         // This is the regular lifetime case. The object is destroyed
         // when the last strong reference goes away. Since weakref_impl
         // outlive the object, it is not destroyed in the dtor, and
         // we'll have to do it here.
-        if (impl->mStrong == INITIAL_STRONG_VALUE) {
+        if (impl->mStrong.load(std::memory_order_relaxed)
+                == INITIAL_STRONG_VALUE) {
             // Special case: we never had a strong reference, so we need to
             // destroy the object now.
             delete impl->mBase;
@@ -424,13 +506,10 @@
             delete impl;
         }
     } else {
-        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
+        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+        // is gone, we can destroy the object.
         impl->mBase->onLastWeakRef(id);
-        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
-            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
-            // is gone, we can destroy the object.
-            delete impl->mBase;
-        }
+        delete impl->mBase;
     }
 }
 
@@ -439,7 +518,7 @@
     incWeak(id);
     
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
-    int32_t curCount = impl->mStrong;
+    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
 
     ALOG_ASSERT(curCount >= 0,
             "attemptIncStrong called on %p after underflow", this);
@@ -447,19 +526,20 @@
     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
         // we're in the easy/common case of promoting a weak-reference
         // from an existing strong reference.
-        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
+        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+                std::memory_order_relaxed)) {
             break;
         }
         // the strong count has changed on us, we need to re-assert our
-        // situation.
-        curCount = impl->mStrong;
+        // situation. curCount was updated by compare_exchange_weak.
     }
     
     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
         // we're now in the harder case of either:
         // - there never was a strong reference on us
         // - or, all strong references have been released
-        if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
+        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
             // this object has a "normal" life-time, i.e.: it gets destroyed
             // when the last strong reference goes away
             if (curCount <= 0) {
@@ -473,13 +553,13 @@
             // there never was a strong-reference, so we can try to
             // promote this object; we need to do that atomically.
             while (curCount > 0) {
-                if (android_atomic_cmpxchg(curCount, curCount + 1,
-                        &impl->mStrong) == 0) {
+                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
+                        std::memory_order_relaxed)) {
                     break;
                 }
                 // the strong count has changed on us, we need to re-assert our
                 // situation (e.g.: another thread has inc/decStrong'ed us)
-                curCount = impl->mStrong;
+                // curCount has been updated.
             }
 
             if (curCount <= 0) {
@@ -499,7 +579,7 @@
             }
             // grab a strong-reference, which is always safe due to the
             // extended life-time.
-            curCount = android_atomic_inc(&impl->mStrong);
+            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
         }
 
         // If the strong reference count has already been incremented by
@@ -518,21 +598,16 @@
     ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
 #endif
 
-    // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
-    // this must be done safely, i.e.: handle the case where several threads
+    // curCount is the value of mStrong before we increment ed it.
+    // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
+    // This must be done safely, i.e.: handle the case where several threads
     // were here in attemptIncStrong().
-    curCount = impl->mStrong;
-    while (curCount >= INITIAL_STRONG_VALUE) {
-        ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
-                "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
-                this);
-        if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
-                &impl->mStrong) == 0) {
-            break;
-        }
-        // the strong-count changed on us, we need to re-assert the situation,
-        // for e.g.: it's possible the fix-up happened in another thread.
-        curCount = impl->mStrong;
+    // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
+    // this in the middle of another incStrong.  The subtraction is handled
+    // by the thread that started with INITIAL_STRONG_VALUE.
+    if (curCount == INITIAL_STRONG_VALUE) {
+        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
+                std::memory_order_relaxed);
     }
 
     return true;
@@ -542,14 +617,15 @@
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
 
-    int32_t curCount = impl->mWeak;
+    int32_t curCount = impl->mWeak.load(std::memory_order_relaxed);
     ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
                this);
     while (curCount > 0) {
-        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
+        if (impl->mWeak.compare_exchange_weak(curCount, curCount+1,
+                std::memory_order_relaxed)) {
             break;
         }
-        curCount = impl->mWeak;
+        // curCount has been updated.
     }
 
     if (curCount > 0) {
@@ -561,7 +637,9 @@
 
 int32_t RefBase::weakref_type::getWeakCount() const
 {
-    return static_cast<const weakref_impl*>(this)->mWeak;
+    // Debug only!
+    return static_cast<const weakref_impl*>(this)->mWeak
+            .load(std::memory_order_relaxed);
 }
 
 void RefBase::weakref_type::printRefs() const
@@ -592,17 +670,19 @@
 
 RefBase::~RefBase()
 {
-    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+    if (mRefs->mStrong.load(std::memory_order_relaxed)
+            == INITIAL_STRONG_VALUE) {
         // we never acquired a strong (and/or weak) reference on this object.
         delete mRefs;
     } else {
-        // life-time of this object is extended to WEAK or FOREVER, in
+        // life-time of this object is extended to WEAK, in
         // which case weakref_impl doesn't out-live the object and we
         // can free it now.
-        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+        int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
+        if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
             // It's possible that the weak count is not 0 if the object
             // re-acquired a weak reference in its destructor
-            if (mRefs->mWeak == 0) {
+            if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
                 delete mRefs;
             }
         }
@@ -613,7 +693,9 @@
 
 void RefBase::extendObjectLifetime(int32_t mode)
 {
-    android_atomic_or(mode, &mRefs->mFlags);
+    // Must be happens-before ordered with respect to construction or any
+    // operation that could destroy the object.
+    mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
 }
 
 void RefBase::onFirstRef()
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index c7dd1ab..f3d6d8f 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -20,7 +20,6 @@
 #include <string.h>
 
 #include <log/log.h>
-#include <utils/Atomic.h>
 
 #include "SharedBuffer.h"
 
@@ -37,18 +36,19 @@
 
     SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
     if (sb) {
-        sb->mRefs = 1;
+        // Should be std::atomic_init(&sb->mRefs, 1);
+        // But that generates a warning with some compilers.
+        // The following is OK on Android-supported platforms.
+        sb->mRefs.store(1, std::memory_order_relaxed);
         sb->mSize = size;
     }
     return sb;
 }
 
 
-ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
+void SharedBuffer::dealloc(const SharedBuffer* released)
 {
-    if (released->mRefs != 0) return -1; // XXX: invalid operation
     free(const_cast<SharedBuffer*>(released));
-    return 0;
 }
 
 SharedBuffer* SharedBuffer::edit() const
@@ -108,14 +108,15 @@
 }
 
 void SharedBuffer::acquire() const {
-    android_atomic_inc(&mRefs);
+    mRefs.fetch_add(1, std::memory_order_relaxed);
 }
 
 int32_t SharedBuffer::release(uint32_t flags) const
 {
     int32_t prev = 1;
-    if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
-        mRefs = 0;
+    if (onlyOwner() || ((prev = mRefs.fetch_sub(1, std::memory_order_release) == 1)
+            && (atomic_thread_fence(std::memory_order_acquire), true))) {
+        mRefs.store(0, std::memory_order_relaxed);
         if ((flags & eKeepStorage) == 0) {
             free(const_cast<SharedBuffer*>(this));
         }
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index b670953..48358cd 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
+/*
+ * DEPRECATED.  DO NOT USE FOR NEW CODE.
+ */
+
 #ifndef ANDROID_SHARED_BUFFER_H
 #define ANDROID_SHARED_BUFFER_H
 
+#include <atomic>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -43,7 +48,7 @@
      * In other words, the buffer must have been release by all its
      * users.
      */
-    static          ssize_t                 dealloc(const SharedBuffer* released);
+    static          void                    dealloc(const SharedBuffer* released);
 
     //! access the data for read
     inline          const void*             data() const;
@@ -94,12 +99,16 @@
         SharedBuffer(const SharedBuffer&);
         SharedBuffer& operator = (const SharedBuffer&);
  
-        // 16 bytes. must be sized to preserve correct alignment.
-        mutable int32_t        mRefs;
-                size_t         mSize;
-                uint32_t       mReserved[2];
+        // Must be sized to preserve correct alignment.
+        mutable std::atomic<int32_t>        mRefs;
+                size_t                      mSize;
+                uint32_t                    mReserved[2];
 };
 
+static_assert(sizeof(SharedBuffer) % 8 == 0
+        && (sizeof(size_t) > 4 || sizeof(SharedBuffer) == 16),
+        "SharedBuffer has unexpected size");
+
 // ---------------------------------------------------------------------------
 
 const void* SharedBuffer::data() const {
@@ -127,7 +136,7 @@
 }
 
 bool SharedBuffer::onlyOwner() const {
-    return (mRefs == 1);
+    return (mRefs.load(std::memory_order_acquire) == 1);
 }
 
 }; // namespace android
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index c5ae327..965e32c 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,18 +19,13 @@
  * System clock functions.
  */
 
-#if defined(__ANDROID__)
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
 #include <sys/time.h>
 #include <limits.h>
 #include <fcntl.h>
 #include <string.h>
+#include <errno.h>
 
+#include <cutils/compiler.h>
 #include <utils/SystemClock.h>
 #include <utils/Timers.h>
 
@@ -61,30 +56,16 @@
  */
 int64_t elapsedRealtimeNano()
 {
-#if defined(__ANDROID__)
-    static int s_fd = -1;
-
-    if (s_fd == -1) {
-        int fd = open("/dev/alarm", O_RDONLY);
-        if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
-            close(fd);
-        }
-    }
-
+#if defined(__linux__)
     struct timespec ts;
-    if (ioctl(s_fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts) == 0) {
-        return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+    int err = clock_gettime(CLOCK_BOOTTIME, &ts);
+    if (CC_UNLIKELY(err)) {
+        // This should never happen, but just in case ...
+        ALOGE("clock_gettime(CLOCK_BOOTTIME) failed: %s", strerror(errno));
+        return 0;
     }
 
-    // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
-    if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) {
-        return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
-    }
-
-    // XXX: there was an error, probably because the driver didn't
-    // exist ... this should return
-    // a real error, like an exception!
-    return systemTime(SYSTEM_TIME_MONOTONIC);
+    return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
 #else
     return systemTime(SYSTEM_TIME_MONOTONIC);
 #endif
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index 8f07f1a..21fe19c 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -28,6 +28,7 @@
     LruCache_test.cpp \
     String8_test.cpp \
     StrongPointer_test.cpp \
+    SystemClock_test.cpp \
     Unicode_test.cpp \
     Vector_test.cpp \
 
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/tests/SystemClock_test.cpp
new file mode 100644
index 0000000..5ad060b
--- /dev/null
+++ b/libutils/tests/SystemClock_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+static const auto MS_IN_NS = 1000000;
+
+static const int64_t SLEEP_MS = 500;
+static const int64_t SLEEP_NS = SLEEP_MS * MS_IN_NS;
+// Conservatively assume that we might be descheduled for up to 50 ms
+static const int64_t SLACK_MS = 50;
+static const int64_t SLACK_NS = SLACK_MS * MS_IN_NS;
+
+TEST(SystemClock, SystemClock) {
+    auto startUptimeMs = android::uptimeMillis();
+    auto startRealtimeMs = android::elapsedRealtime();
+    auto startRealtimeNs = android::elapsedRealtimeNano();
+
+    ASSERT_GT(startUptimeMs, 0)
+            << "uptimeMillis() reported an impossible uptime";
+    ASSERT_GE(startRealtimeMs, startUptimeMs)
+            << "elapsedRealtime() thinks we've suspended for negative time";
+    ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+            << "elapsedRealtimeNano() thinks we've suspended for negative time";
+
+    ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+    ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+
+    timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = SLEEP_MS * MS_IN_NS;
+    auto nanosleepErr = TEMP_FAILURE_RETRY(nanosleep(&ts, nullptr));
+    ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
+
+    auto endUptimeMs = android::uptimeMillis();
+    auto endRealtimeMs = android::elapsedRealtime();
+    auto endRealtimeNs = android::elapsedRealtimeNano();
+
+    EXPECT_GE(endUptimeMs - startUptimeMs, SLEEP_MS)
+            << "uptimeMillis() advanced too little after nanosleep()";
+    EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
+            << "uptimeMillis() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
+            << "elapsedRealtime() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
+            << "elapsedRealtime() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeNs - startRealtimeNs, SLEEP_NS)
+            << "elapsedRealtimeNano() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
+            << "elapsedRealtimeNano() advanced too much after nanosleep()";
+
+    EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+    EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index aa3db8a..37fbdb8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -114,7 +114,7 @@
 static struct proc *pidhash[PIDHASH_SZ];
 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
+#define ADJTOSLOT(adj) ((adj) + -OOM_ADJUST_MIN)
 static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
 
 /*
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6f7d264..b32c27d 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -33,7 +33,7 @@
 #include "LogUtils.h"
 
 #define log_id_for_each(i) \
-    for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+    for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
 
 class LogStatistics;
 
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index 186384b..e19b058 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -1,6 +1,7 @@
 on property:sys.usb.config=none && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/UDC "none"
     stop adbd
+    setprop sys.usb.ffs.ready 0
     write /config/usb_gadget/g1/bDeviceClass 0
     write /config/usb_gadget/g1/bDeviceSubClass 0
     write /config/usb_gadget/g1/bDeviceProtocol 0
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index 434d370..7c3ddd4 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -43,7 +43,7 @@
 #define __type_fit(t, a) (0 == 0)
 
 // TODO: should this be in our <sys/cdefs.h>?
-#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
 
 // This at least matches GNU dd(1) behavior.
 #define SIGINFO SIGUSR1
diff --git a/trusty/storage/lib/Android.mk b/trusty/storage/lib/Android.mk
new file mode 100644
index 0000000..7e0fc9d
--- /dev/null
+++ b/trusty/storage/lib/Android.mk
@@ -0,0 +1,37 @@
+#
+# 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 := libtrustystorage
+
+LOCAL_SRC_FILES := \
+	storage.c \
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
+	liblog \
+	libtrusty \
+	libtrustystorageinterface
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/trusty/storage/lib/include/trusty/lib/storage.h b/trusty/storage/lib/include/trusty/lib/storage.h
new file mode 100644
index 0000000..b8ddf67
--- /dev/null
+++ b/trusty/storage/lib/include/trusty/lib/storage.h
@@ -0,0 +1,154 @@
+/*
+ * 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>
+
+#define STORAGE_MAX_NAME_LENGTH_BYTES 159
+
+__BEGIN_DECLS
+
+typedef uint32_t storage_session_t;
+typedef uint64_t file_handle_t;
+typedef uint64_t storage_off_t;
+
+#define STORAGE_INVALID_SESSION ((storage_session_t)-1)
+
+/**
+ * storage_ops_flags - storage related operation flags
+ * @STORAGE_OP_COMPLETE: forces to commit current transaction
+ */
+enum storage_ops_flags {
+    STORAGE_OP_COMPLETE = 0x1,
+};
+
+/**
+ * storage_open_session() - Opens a storage session.
+ * @device:    device node for talking with Trusty
+ * @session_p: pointer to location in which to store session handle
+ *             in case of success.
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_session(const char *device, storage_session_t *session_p, const char *port);
+
+/**
+ * storage_close_session() - Closes the session.
+ * @session: the session to close
+ */
+void storage_close_session(storage_session_t session);
+
+/**
+ * storage_open_file() - Opens a file
+ * @session:  the storage_session_t returned from a call to storage_open_session
+ * @handle_p: pointer to location in which to store file handle in case of success
+ * @name:     a null-terminated string identifier of the file to open.
+ *            Cannot be more than STORAGE_MAX_NAME_LENGTH_BYTES in length.
+ * @flags:    A bitmask consisting any storage_file_flag value or'ed together:
+ * - STORAGE_FILE_OPEN_CREATE:           if this file does not exist, create it.
+ * - STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: when specified, opening file with
+ *                                       STORAGE_OPEN_FILE_CREATE flag will
+ *                                       fail if the file already exists.
+ *                                       Only meaningful if used in combination
+ *                                       with STORAGE_FILE_OPEN_CREATE flag.
+ * - 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.
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_file(storage_session_t session, file_handle_t *handle_p,
+                      const char *name, uint32_t flags, uint32_t opflags);
+
+/**
+ * storage_close_file() - Closes a file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ */
+void storage_close_file(file_handle_t handle);
+
+/**
+ * storage_delete_file - Deletes a file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @name: the name of the file to delete
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_delete_file(storage_session_t session, const char *name,
+                        uint32_t opflags);
+
+/**
+ * storage_read() - Reads a file at a given offset.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to read in the file
+ * @buf: the buffer in which to write the data read
+ * @size: the size of buf and number of bytes to read
+ *
+ * Return: the number of bytes read on success, negative error code on failure
+ */
+ssize_t storage_read(file_handle_t handle,
+                     storage_off_t off, void *buf, size_t size);
+
+/**
+ * storage_write() - Writes to a file at a given offset. Grows the file if necessary.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to write in the file
+ * @buf: the buffer containing the data to write
+ * @size: the size of buf and number of bytes to write
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: the number of bytes written on success, negative error code on failure
+ */
+ssize_t storage_write(file_handle_t handle,
+                      storage_off_t off, const void *buf, size_t size,
+                      uint32_t opflags);
+
+/**
+ * storage_set_file_size() - Sets the size of the file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the number of bytes to set as the new size of the file
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_set_file_size(file_handle_t handle, storage_off_t file_size,
+                          uint32_t opflags);
+
+/**
+ * storage_get_file_size() - Gets the size of the file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @size: pointer to storage_off_t in which to store the file size
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_get_file_size(file_handle_t handle, storage_off_t *size);
+
+
+/**
+ * storage_end_transaction: End current transaction
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @complete: if true, commit current transaction, discard it otherwise
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_end_transaction(storage_session_t session, bool complete);
+
+
+__END_DECLS
diff --git a/trusty/storage/lib/storage.c b/trusty/storage/lib/storage.c
new file mode 100644
index 0000000..8130f76
--- /dev/null
+++ b/trusty/storage/lib/storage.c
@@ -0,0 +1,311 @@
+/*
+ * 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 <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <trusty/tipc.h>
+#include <trusty/lib/storage.h>
+
+#define LOG_TAG "trusty_storage_client"
+#include <cutils/log.h>
+
+#define MAX_CHUNK_SIZE 4040
+
+static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid)
+{
+    return ((uint64_t)s << 32) | fid;
+}
+
+static inline storage_session_t _to_session(file_handle_t fh)
+{
+    return (storage_session_t)(fh >> 32);
+}
+
+static inline uint32_t _to_handle(file_handle_t fh)
+{
+    return (uint32_t) fh;
+}
+
+static inline uint32_t _to_msg_flags(uint32_t opflags)
+{
+    uint32_t msg_flags = 0;
+
+    if (opflags & STORAGE_OP_COMPLETE)
+        msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE;
+
+    return msg_flags;
+}
+
+static ssize_t check_response(struct storage_msg *msg, ssize_t res)
+{
+    if (res < 0)
+        return res;
+
+    if ((size_t)res < sizeof(*msg)) {
+        ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg));
+        return -EIO;
+    }
+
+    ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result);
+
+    switch(msg->result) {
+        case STORAGE_NO_ERROR:
+            return res - sizeof(*msg);
+
+        case STORAGE_ERR_NOT_FOUND:
+            return -ENOENT;
+
+        case STORAGE_ERR_EXIST:
+            return -EEXIST;
+
+        case STORAGE_ERR_NOT_VALID:
+            return -EINVAL;
+
+        case STORAGE_ERR_UNIMPLEMENTED:
+            ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd);
+            return -EINVAL;
+
+        case STORAGE_ERR_ACCESS:
+             return -EACCES;
+
+        case STORAGE_ERR_TRANSACT:
+             return -EBUSY;
+
+        case STORAGE_ERR_GENERIC:
+            ALOGE("cmd 0x%x: internal server error\n", msg->cmd);
+            return -EIO;
+
+        default:
+            ALOGE("cmd 0x%x: unhandled server response %u\n",
+                   msg->cmd, msg->result);
+    }
+
+    return -EIO;
+}
+
+static ssize_t send_reqv(storage_session_t session,
+                         const struct iovec *tx_iovs, uint tx_iovcnt,
+                         const struct iovec *rx_iovs, uint rx_iovcnt)
+{
+    ssize_t rc;
+
+    rc = writev(session, tx_iovs, tx_iovcnt);
+    if (rc < 0) {
+        rc = -errno;
+        ALOGE("failed to send request: %s\n", strerror(errno));
+        return rc;
+    }
+
+    rc = readv(session, rx_iovs, rx_iovcnt);
+    if (rc < 0) {
+        rc = -errno;
+        ALOGE("failed to recv response: %s\n", strerror(errno));
+        return rc;
+    }
+
+    return rc;
+}
+
+int storage_open_session(const char *device, storage_session_t *session_p,
+                         const char *port)
+{
+    int rc = tipc_connect(device, port);
+    if (rc < 0)
+        return rc;
+    *session_p = (storage_session_t) rc;
+    return 0;
+}
+
+void storage_close_session(storage_session_t session)
+{
+    tipc_close(session);
+}
+
+
+int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name,
+                      uint32_t flags, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)};
+    struct storage_file_open_req req = { .flags = flags };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+    struct storage_file_open_resp rsp = { 0 };
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+    ssize_t rc = send_reqv(session, tx, 3, rx, 2);
+    rc = check_response(&msg, rc);
+    if (rc < 0)
+        return rc;
+
+    if ((size_t)rc != sizeof(rsp)) {
+        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+        return -EIO;
+    }
+
+    *handle_p = make_file_handle(session, rsp.handle);
+    return 0;
+}
+
+void storage_close_file(file_handle_t fh)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE };
+    struct storage_file_close_req req = { .handle = _to_handle(fh)};
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+    rc = check_response(&msg, rc);
+    if (rc < 0) {
+        ALOGE("close file failed (%d)\n", (int)rc);
+    }
+}
+
+int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)};
+    struct storage_file_delete_req req = { .flags = 0, };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(session, tx, 3, rx, 1);
+    return check_response(&msg, rc);
+}
+
+static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_READ };
+    struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+    return check_response(&msg, rc);
+}
+
+ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+    int rc;
+    size_t bytes_read = 0;
+    size_t chunk = MAX_CHUNK_SIZE;
+    uint8_t *ptr = buf;
+
+    while (size) {
+        if (chunk > size)
+            chunk = size;
+        rc = _read_chunk(fh, off, ptr, chunk);
+        if (rc < 0)
+            return rc;
+        if (rc == 0)
+            break;
+        off += rc;
+        ptr += rc;
+        bytes_read += rc;
+        size -= rc;
+    }
+    return bytes_read;
+}
+
+static int _write_req(file_handle_t fh, storage_off_t off,
+                      const void *buf, size_t size, uint32_t msg_flags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, };
+    struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1);
+    rc = check_response(&msg, rc);
+    return rc < 0 ? rc : size;
+}
+
+ssize_t storage_write(file_handle_t fh, storage_off_t off,
+                      const void *buf, size_t size, uint32_t opflags)
+{
+    int rc;
+    size_t bytes_written = 0;
+    size_t chunk = MAX_CHUNK_SIZE;
+    const uint8_t *ptr = buf;
+    uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE);
+
+    while (size) {
+        if (chunk >= size) {
+            /* last chunk in sequence */
+            chunk = size;
+            msg_flags = _to_msg_flags(opflags);
+        }
+        rc = _write_req(fh, off, ptr, chunk, msg_flags);
+        if (rc < 0)
+            return rc;
+        if ((size_t)rc != chunk) {
+            ALOGE("got partial write (%d)\n", (int)rc);
+            return -EIO;
+        }
+        off += chunk;
+        ptr += chunk;
+        bytes_written += chunk;
+        size -= chunk;
+    }
+    return bytes_written;
+}
+
+int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)};
+    struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+    return check_response(&msg, rc);
+}
+
+int storage_get_file_size(file_handle_t fh, storage_off_t *size_p)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE };
+    struct storage_file_get_size_req  req = { .handle = _to_handle(fh), };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct storage_file_get_size_resp rsp;
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+    rc = check_response(&msg, rc);
+    if (rc < 0)
+        return rc;
+
+    if ((size_t)rc != sizeof(rsp)) {
+        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+        return -EIO;
+    }
+
+    *size_p = rsp.size;
+    return 0;
+}
+
+int storage_end_transaction(storage_session_t session, bool complete)
+{
+    struct storage_msg msg = {
+        .cmd = STORAGE_END_TRANSACTION,
+        .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0,
+    };
+    struct iovec iov = {&msg, sizeof(msg)};
+
+    ssize_t rc = send_reqv(session, &iov, 1, &iov, 1);
+    return check_response(&msg, rc);
+}
diff --git a/trusty/storage/proxy/Android.mk b/trusty/storage/proxy/Android.mk
index 9fc73d3..745e302 100644
--- a/trusty/storage/proxy/Android.mk
+++ b/trusty/storage/proxy/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_MODULE := storageproxyd
 
+LOCAL_C_INCLUDES += bionic/libc/kernel/uapi
+
 LOCAL_SRC_FILES := \
 	ipc.c \
 	rpmb.c \
diff --git a/trusty/storage/tests/Android.mk b/trusty/storage/tests/Android.mk
new file mode 100644
index 0000000..71c904d
--- /dev/null
+++ b/trusty/storage/tests/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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 := secure-storage-unit-test
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_STATIC_LIBRARIES := \
+	libtrustystorageinterface \
+	libtrustystorage \
+	libtrusty \
+	liblog
+LOCAL_SRC_FILES := main.cpp
+include $(BUILD_NATIVE_TEST)
+
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
new file mode 100644
index 0000000..a771b87
--- /dev/null
+++ b/trusty/storage/tests/main.cpp
@@ -0,0 +1,3040 @@
+/*
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include <gtest/gtest.h>
+
+#include <trusty/lib/storage.h>
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+static inline bool is_32bit_aligned(size_t sz)
+{
+    return ((sz & 0x3) == 0);
+}
+
+static inline bool is_valid_size(size_t sz) {
+    return (sz > 0) && is_32bit_aligned(sz);
+}
+
+static bool is_valid_offset(storage_off_t off)
+{
+    return (off & 0x3) == 0ULL;
+}
+
+static void fill_pattern32(uint32_t *buf, size_t len, storage_off_t off)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+    while (cnt--) {
+        *buf++ = pattern++;
+    }
+}
+
+static bool check_pattern32(const uint32_t *buf, size_t len, storage_off_t off)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+    while (cnt--) {
+        if (*buf != pattern)
+            return false;
+        buf++;
+        pattern++;
+    }
+    return true;
+}
+
+static bool check_value32(const uint32_t *buf, size_t len, uint32_t val)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    while (cnt--) {
+        if (*buf != val)
+            return false;
+        buf++;
+    }
+    return true;
+}
+
+using testing::TestWithParam;
+
+class StorageServiceTest : public virtual TestWithParam<const char *> {
+public:
+    StorageServiceTest() {}
+    virtual ~StorageServiceTest() {}
+
+    virtual void SetUp() {
+        port_ = GetParam();
+        test_buf_ = NULL;
+        aux_session_ = STORAGE_INVALID_SESSION;
+        int rc = storage_open_session(TRUSTY_DEVICE_NAME, &session_, port_);
+        ASSERT_EQ(0, rc);
+    }
+
+    virtual void TearDown() {
+        if (test_buf_) {
+            delete[] test_buf_;
+            test_buf_ = NULL;
+        }
+        storage_close_session(session_);
+
+        if (aux_session_ != STORAGE_INVALID_SESSION) {
+            storage_close_session(aux_session_);
+            aux_session_ = STORAGE_INVALID_SESSION;
+        }
+    }
+
+    void WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete);
+
+    void WriteZeroChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete );
+    void WritePatternChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete);
+    void WritePattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len, bool complete);
+
+    void ReadChunk(file_handle_t handle, storage_off_t off, size_t chunk_len,
+                   size_t head_len, size_t pattern_len, size_t tail_len);
+    void ReadPattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len);
+    void ReadPatternEOF(file_handle_t handle, storage_off_t off, size_t chunk_len, size_t exp_len);
+
+protected:
+    const char *port_;
+    uint32_t *test_buf_;
+    storage_session_t session_;
+    storage_session_t aux_session_;
+};
+
+INSTANTIATE_TEST_CASE_P(SS_TD_Tests, StorageServiceTest,   ::testing::Values(STORAGE_CLIENT_TD_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TDEA_Tests, StorageServiceTest, ::testing::Values(STORAGE_CLIENT_TDEA_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TP_Tests, StorageServiceTest,   ::testing::Values(STORAGE_CLIENT_TP_PORT));
+
+
+void StorageServiceTest::WriteZeroChunk(file_handle_t handle, storage_off_t off,
+                                       size_t chunk_len, bool complete)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    memset(data_buf, 0, chunk_len);
+
+    rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+                       complete ? STORAGE_OP_COMPLETE : 0);
+    ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePatternChunk(file_handle_t handle, storage_off_t off,
+                                           size_t chunk_len, bool complete)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    fill_pattern32(data_buf, chunk_len, off);
+
+    rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+                       complete ? STORAGE_OP_COMPLETE : 0);
+    ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePattern(file_handle_t handle, storage_off_t off,
+                                      size_t data_len, size_t chunk_len, bool complete)
+{
+    ASSERT_PRED1(is_valid_size, data_len);
+    ASSERT_PRED1(is_valid_size, chunk_len);
+
+    while (data_len) {
+        if (data_len < chunk_len)
+            chunk_len = data_len;
+        WritePatternChunk(handle, off, chunk_len, (chunk_len == data_len) && complete);
+        ASSERT_FALSE(HasFatalFailure());
+        off += chunk_len;
+        data_len -= chunk_len;
+    }
+}
+
+void StorageServiceTest::ReadChunk(file_handle_t handle,
+                                   storage_off_t off, size_t chunk_len,
+                                   size_t head_len, size_t pattern_len,
+                                   size_t tail_len)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+    uint8_t *data_ptr = (uint8_t *)data_buf;
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+    ASSERT_EQ(head_len + pattern_len + tail_len, chunk_len);
+
+    rc = storage_read(handle, off, data_buf, chunk_len);
+    ASSERT_EQ((int)chunk_len, rc);
+
+    if (head_len) {
+        ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, head_len, 0));
+        data_ptr += head_len;
+        off += head_len;
+    }
+
+    if (pattern_len) {
+        ASSERT_TRUE(check_pattern32((const uint32_t *)data_ptr, pattern_len, off));
+        data_ptr += pattern_len;
+    }
+
+    if (tail_len) {
+        ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, tail_len, 0));
+    }
+}
+
+void StorageServiceTest::ReadPattern(file_handle_t handle, storage_off_t off,
+                                     size_t data_len, size_t chunk_len)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_size, data_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    while (data_len) {
+        if (chunk_len > data_len)
+            chunk_len = data_len;
+        rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+        ASSERT_EQ((int)chunk_len, rc);
+        ASSERT_TRUE(check_pattern32(data_buf, chunk_len, off));
+        off += chunk_len;
+        data_len -= chunk_len;
+    }
+}
+
+void StorageServiceTest::ReadPatternEOF(file_handle_t handle, storage_off_t off,
+                                        size_t chunk_len, size_t exp_len)
+{
+    int rc;
+    size_t bytes_read = 0;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_32bit_aligned, exp_len);
+
+    while (true) {
+         rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+         ASSERT_GE(rc, 0);
+         if (rc == 0)
+             break; // end of file reached
+         ASSERT_PRED1(is_valid_size, (size_t)rc);
+         ASSERT_TRUE(check_pattern32(data_buf, rc, off));
+         off += rc;
+         bytes_read += rc;
+    }
+    ASSERT_EQ(bytes_read, exp_len);
+}
+
+TEST_P(StorageServiceTest, CreateDelete) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_create_delete_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT only)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // try to create it again while it is still opened (expect -EEXIST)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EEXIST, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // try to create it again while it is closed (expect -EEXIST)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EEXIST, rc);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, DeleteOpened) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "delete_opened_test_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // delete opened file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // close file
+    storage_close_file(handle);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenNoCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_open_no_create_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // open non-existing file (expect -ENOENT)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenOrCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_open_create_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // open/create a non-existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open/create an existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenCreateDeleteCharset) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz_01234.56789";
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open/create an existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, WriteReadSequential) {
+    int rc;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_write_read_sequential";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // create file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks (sequentially)
+    WritePattern(handle, 0, 32 * blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPattern(handle, 0, 32 * blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close file
+    storage_close_file(handle);
+
+    // open the same file again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // read data back (sequentially) and check pattern again
+    ReadPattern(handle, 0, 32 * blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenTruncate) {
+    int rc;
+    uint32_t val;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_open_truncate";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // create file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write some data and read it back
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPattern(handle, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+     // close file
+    storage_close_file(handle);
+
+    // reopen with truncate
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    /* try to read data back (expect no data) */
+    rc = storage_read(handle, 0LL, &val, sizeof(val));
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenSame) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    const char *fname = "test_open_same_file";
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle1, fname, STORAGE_FILE_OPEN_CREATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle1);
+
+    // open an existing file first time (expect 0)
+    rc = storage_open_file(session_, &handle1, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // open the same file second time (expect error)
+    rc = storage_open_file(session_, &handle2, fname, 0, 0);
+    ASSERT_NE(0, rc);
+
+    storage_close_file(handle1);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open deleted file (expect -ENOENT)
+    rc = storage_open_file(session_, &handle3, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenMany) {
+    int rc;
+    file_handle_t handles[10];
+    char filename[10];
+    const char *fname_fmt = "mf%d";
+
+    // open or create a bunch of files (expect 0)
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_open_file(session_, &handles[i], filename,
+                               STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+    }
+
+    // check that all handles are different
+    for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+        for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+            ASSERT_NE(handles[i], handles[j]);
+        }
+    }
+
+    // close them all
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        storage_close_file(handles[i]);
+    }
+
+    // open all files without CREATE flags (expect 0)
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_open_file(session_, &handles[i], filename, 0, 0);
+        ASSERT_EQ(0, rc);
+    }
+
+    // check that all handles are different
+    for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+        for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+            ASSERT_NE(handles[i], handles[j]);
+        }
+    }
+
+    // close and remove all test files
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        storage_close_file(handles[i]);
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_delete_file(session_, filename, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+    }
+}
+
+
+TEST_P(StorageServiceTest, ReadAtEOF) {
+    int rc;
+    uint32_t val;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_read_eof";
+
+    // open/create/truncate file
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write block at offset 0
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close file
+    storage_close_file(handle);
+
+    // open same file again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // read the whole block back and check pattern again
+    ReadPattern(handle, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read at end of file (expected 0 bytes)
+    rc = storage_read(handle, blk, &val, sizeof(val));
+    ASSERT_EQ(0, rc);
+
+    // partial read at end of the file (expected partial data)
+    ReadPatternEOF(handle, blk/2, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read past end of file
+    rc = storage_read(handle, blk + 2, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, GetFileSize) {
+    int rc;
+    size_t blk = 2048;
+    storage_off_t size;
+    file_handle_t handle;
+    const char *fname = "test_get_file_size";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size (expect success and size == 0)
+    size = 1;
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, size);
+
+    // write block
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    // write another block
+    WritePatternChunk(handle, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size again
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk*2, size);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, SetFileSize) {
+    int rc;
+    size_t blk = 2048;
+    storage_off_t size;
+    file_handle_t handle;
+    const char *fname = "test_set_file_size";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size (expect success and size == 0)
+    size = 1;
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, size);
+
+    // write block
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    storage_close_file(handle);
+
+    // reopen normally
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check size again
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    // set file size to half
+    rc = storage_set_file_size(handle, blk/2, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check size again (should be half of original size)
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk/2, size);
+
+    // read data back
+    ReadPatternEOF(handle, 0, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // set file size to 0
+    rc = storage_set_file_size(handle, 0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check size again (should be 0)
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0LL, size);
+
+    // try to read again
+    ReadPatternEOF(handle, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+void StorageServiceTest::WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete)
+{
+    storage_off_t off1 = blk;
+    storage_off_t off2 = blk * (cnt-1);
+
+    // write known pattern data at non-zero offset1
+    WritePatternChunk(handle, off1, blk, complete);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write known pattern data at non-zero offset2
+    WritePatternChunk(handle, off2, blk, complete);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data back at offset1
+    ReadPattern(handle, off1, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data back at offset2
+    ReadPattern(handle, off2, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data at end of file(expect to get data only, no padding)
+    ReadPatternEOF(handle, off2 + blk/2, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data at offset 0 (expect success and zero data)
+    ReadChunk(handle, 0, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data from gap (expect success and zero data)
+    ReadChunk(handle, off1 + blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data (start pointing within written data)
+    // (expect to get written data back and zeroes at the end)
+    ReadChunk(handle, off1 + blk/2, blk, 0, blk/2, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data (start pointing withing unwritten data)
+    // expect to get zeroes at the beginning and proper data at the end
+    ReadChunk(handle, off1 - blk/2, blk, blk/2, blk/2, 0);
+    ASSERT_FALSE(HasFatalFailure());
+}
+
+
+TEST_P(StorageServiceTest, WriteReadAtOffset) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t blk_cnt = 32;
+    const char *fname = "test_write_at_offset";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with zeroes
+    for (uint i = 0; i < blk_cnt; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    WriteReadAtOffsetHelper(handle, blk, blk_cnt, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, WriteSparse) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_write_sparse";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write value past en of file
+    uint32_t val = 0xDEADBEEF;
+    rc = storage_write(handle, 1, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Persistent 32k
+
+TEST_P(StorageServiceTest, CreatePersistent32K) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t file_size = 32768;
+    const char *fname = "test_persistent_32K_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent32k) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 32 * 1024;
+    const char *fname = "test_persistent_32K_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 2048, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle, 0, 1024, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle, 0,  332, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent32K) {
+    int rc;
+    const char *fname = "test_persistent_32K_file";
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+}
+
+// Persistent 1M
+TEST_P(StorageServiceTest, CreatePersistent1M_4040) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 4040, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_2032) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 2032, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+
+TEST_P(StorageServiceTest, CreatePersistent1M_496) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 496, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_240) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 240, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_4040) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 4040, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_2032) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 2032, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_496) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 496, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_240) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 240, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent1M) {
+    int rc;
+    const char *fname = "test_persistent_1M_file";
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, WriteReadLong) {
+    int rc;
+    file_handle_t handle;
+    size_t wc = 10000;
+    const char *fname = "test_write_read_long";
+
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    test_buf_ = new uint32_t[wc];
+    fill_pattern32(test_buf_, wc * sizeof(uint32_t), 0);
+    rc = storage_write(handle, 0, test_buf_, wc * sizeof(uint32_t), STORAGE_OP_COMPLETE);
+    ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+
+    rc = storage_read(handle, 0, test_buf_, wc * sizeof(uint32_t));
+    ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+    ASSERT_TRUE(check_pattern32(test_buf_, wc * sizeof(uint32_t), 0));
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Negative tests
+
+TEST_P(StorageServiceTest, OpenInvalidFileName) {
+    int rc;
+    file_handle_t handle;
+    const char *fname1 = "";
+    const char *fname2 = "ffff$ffff";
+    const char *fname3 = "ffff\\ffff";
+    char max_name[STORAGE_MAX_NAME_LENGTH_BYTES+1];
+
+    rc = storage_open_file(session_, &handle, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    rc = storage_open_file(session_, &handle, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    rc = storage_open_file(session_, &handle, fname3,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    /* max name */
+    memset(max_name, 'a', sizeof(max_name));
+    max_name[sizeof(max_name)-1] = 0;
+
+    rc = storage_open_file(session_, &handle, max_name,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    max_name[sizeof(max_name)-2] = 0;
+    rc = storage_open_file(session_, &handle, max_name,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    storage_close_file(handle);
+    storage_delete_file(session_, max_name, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, BadFileHnadle) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle1;
+    const char *fname = "test_invalid_file_handle";
+
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    handle1 = handle + 1;
+
+    // write to invalid file handle
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle1,  0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read from invalid handle
+    rc = storage_read(handle1,  0, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // set size
+    rc = storage_set_file_size(handle1,  0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // get size
+    storage_off_t fsize = (storage_off_t)(-1);
+    rc = storage_get_file_size(handle1,  &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close (there is no way to check errors here)
+    storage_close_file(handle1);
+
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, ClosedFileHnadle) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    const char *fname1 = "test_invalid_file_handle1";
+    const char *fname2 = "test_invalid_file_handle2";
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close first file handle
+    storage_close_file(handle1);
+
+    // write to invalid file handle
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle1,  0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read from invalid handle
+    rc = storage_read(handle1,  0, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // set size
+    rc = storage_set_file_size(handle1,  0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // get size
+    storage_off_t fsize = (storage_off_t)(-1);
+    rc = storage_get_file_size(handle1,  &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close (there is no way to check errors here)
+    storage_close_file(handle1);
+
+    // clean up
+    storage_close_file(handle2);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+// Transactions
+
+TEST_P(StorageServiceTest, TransactDiscardInactive) {
+    int rc;
+
+    // discard current transaction (there should not be any)
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try it again
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactCommitInactive) {
+    int rc;
+
+    // try to commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // try it again
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWrite) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_write";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // write (without commit)
+    WritePattern(handle, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // cleanup
+    storage_close_file( handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardWriteAppend) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_append";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data with commit
+    WritePattern(handle, 0, exp_len/2, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write data without commit
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size (should be exp_len)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // discard transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len/2
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // check file data
+    ReadPatternEOF(handle, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteRead) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_write_read";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // Fill with zeroes (with commit)
+    for (uint i = 0; i < 32; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    // check that test chunk is filled with zeroes
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back an check pattern
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // read same chunk back (should be filled with zeros)
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len1 = 32 * 1024;
+    size_t exp_len2 = 31 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_discard_write_file1";
+    const char *fname2 = "test_transact_discard_write_file2";
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // file1: fill file with pattern (without commit)
+    WritePattern(handle1, 0, exp_len1, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // file2: fill file with pattern (without commit)
+    WritePattern(handle2, 0, exp_len2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check data
+    ReadPatternEOF(handle1, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardTruncate) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_truncate";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // open truncate file (without commit)
+    rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an oruginal size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardSetSize) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_set_size";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to half of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/2, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // set file size to 1/3 of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/3, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_delete";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try to open it
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete2) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_delete";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try to open it
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_transact_discard_create_excl";
+
+    // delete test file just in case
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle, fname,
+                               STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                               0);
+    ASSERT_EQ(0, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitWrites) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_writes";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in aux session
+    rc = storage_open_file(aux_session_, &handle_aux, fname,  0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be 0
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // write data in primary session (without commit)
+    WritePattern(handle, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write more data in primary session (without commit)
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size in aux session, it should still be 0
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size of aux session, should fail
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session to recover
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size in aux session, it should be exp_len
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check file size in primary session, it should be exp_len
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check data in primary session
+    ReadPatternEOF(handle, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check data in aux session
+    ReadPatternEOF(handle_aux, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWrites2) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_writes2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // discard transaction in aux_session
+    rc = storage_end_transaction(aux_session_,  false);
+    ASSERT_EQ(0, rc);
+
+    // Fill with zeroes (with commit)
+    for (uint i = 0; i < 8; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    // check that test chunks are filled with zeroes
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, 2 * blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back and check pattern
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // In aux session it still should be empty
+    ReadChunk(handle_aux, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle_aux, 2 * blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // read same chunks back in primary session
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read same chunks back in aux session (should fail)
+    uint32_t val;
+    rc = storage_read(handle_aux, blk, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_read(handle_aux, 2 * blk, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_,  false);
+    ASSERT_EQ(0, rc);
+
+    // read same chunk again in aux session
+    ReadChunk(handle_aux, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle_aux, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitSetSize) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_set_size";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // same in aux session
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to half of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/2, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to 1/3 of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/3, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be 1/3 of an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // check file size from aux session
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux_session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check again
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDelete) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    const char *fname = "test_transact_commit_delete";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle_aux);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open the same file in separate session (should be fine)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle_aux);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // try to open it in primary session (still fails)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open the same file in aux session (should also fail)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitTruncate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_truncate";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // check from different session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // open truncate file (without commit)
+    rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be 0)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check file size in aux session (should be -EBUSY)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check again
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_create";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // delete test file just in case
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+    // check from aux session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // check from aux session (should fail)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check open from normal session
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check open from aux session (should succeed)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreateMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle1_aux;
+    file_handle_t handle2_aux;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_commit_create1";
+    const char *fname2 = "test_transact_commit_create2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // delete test file just in case
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // check file sizes
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // close files
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    // open files from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // open from primary session
+    rc = storage_open_file(session_, &handle1, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle2, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // open from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle1_aux);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_close_file(handle2_aux);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWriteMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle1_aux;
+    file_handle_t handle2_aux;
+    size_t blk = 2048;
+    size_t exp_len1 = 32 * 1024;
+    size_t exp_len2 = 31 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_commit_write_file1";
+    const char *fname2 = "test_transact_commit_write_file2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open same files from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // file1: fill file with pattern (without commit)
+    WritePattern(handle1, 0, exp_len1, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // file2: fill file with pattern (without commit)
+    WritePattern(handle2, 0, exp_len2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check file sizes from aux session (should be 0)
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle2_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check from aux session (should be -EBUSY)
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // and check again
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    rc = storage_get_file_size(handle2_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check data
+    ReadPatternEOF(handle1, 0, blk, exp_len1);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2, 0, blk, exp_len2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle1_aux, 0, blk, exp_len1);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2_aux, 0, blk, exp_len2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle1_aux);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_close_file(handle2_aux);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDeleteCreate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_delete_create";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // try to open it in aux session (should succeed)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // create file with the same name (no commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // write half of data (with commit)
+    WritePattern(handle, 0, exp_len/2, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size (should be half)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check data from primary session
+    ReadPatternEOF(handle, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check from aux session (should fail)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // abort trunsaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // and try again (should still fail)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close file and reopen it again
+    storage_close_file(handle_aux);
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // try it again (should succeed)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // check data
+    ReadPatternEOF(handle_aux, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactRewriteExistingTruncate) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    const char *fname = "test_transact_rewrite_existing_truncate";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // up
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // down
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, (32 - i) * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // cleanup
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactRewriteExistingSetSize) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    const char *fname = "test_transact_rewrite_existing_set_size";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // up
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, 0, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, i * blk, blk, false);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // update size (with commit)
+        rc = storage_set_file_size(handle, i * blk, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // down
+    for (uint i = 1; i < 32; i++) {
+        // open trancate (no commit)
+        rc = storage_open_file(session_, &handle, fname, 0, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, (32 - i) * blk, blk, false);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // update size (with commit)
+        rc = storage_set_file_size(handle, (32 - i) * blk, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // cleanup
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactResumeAfterNonFatalError) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle1;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_resume_writes";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write (without commit)
+    WritePattern(handle, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // issue some commands that should fail with non-fatal errors
+
+    // write past end of file
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle,  exp_len/2 + 1, &val, sizeof(val), 0);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read past end of file
+    rc = storage_read(handle, exp_len/2 + 1, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // try to extend file past end of file
+    rc = storage_set_file_size(handle, exp_len/2 + 1, 0);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // open non existing file
+    rc = storage_open_file(session_, &handle1, "foo",
+                           STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // delete non-existing file
+    rc = storage_delete_file(session_, "foo", STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // then resume writinga (without commit)
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check data
+    ReadPatternEOF(handle, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+// Transaction Collisions
+
+TEST_P(StorageServiceTest, Transact2_WriteNC) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    const char *fname1 = "test_transact_f1";
+    const char *fname2 = "test_transact_f2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // session 1
+    WritePattern(handle1, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle1, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // session 2
+    WritePattern(handle2, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle2, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(aux_session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_DeleteNC) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    const char *fname1 = "test_transact_delete_f1";
+    const char *fname2 = "test_transact_delete_f2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // session 1
+    WritePattern(handle1, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle1, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // session 2
+    WritePattern(handle2, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle2, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close files and delete them
+    storage_close_file(handle1);
+    storage_delete_file(session_, fname1, 0);
+
+    storage_close_file(handle2);
+    storage_delete_file(aux_session_, fname2, 0);
+
+    // commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Read) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_writeRead";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: read it back
+    ReadPatternEOF(handle1, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: check file size, it should be 0
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // S2: read it back (should no data)
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should fail
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: abort transaction
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size again, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Commit) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_commit_commit";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: read/write/get/set size/delete (all should fail)
+    uint32_t val = 0;
+    rc = storage_read(handle2, 0, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_set_file_size(handle2,  fsize, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_delete_file(aux_session_, fname, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_open_file(aux_session_, &handle3, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: commit (should fail, and failed state should be cleared)
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Discard) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_commit_discard";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: read/write/get/set size/delete (all should fail)
+    uint32_t val = 0;
+    rc = storage_read(handle2, 0, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_set_file_size(handle2,  fsize, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_delete_file(aux_session_, fname, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_open_file(aux_session_, &handle3, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: discard (should fail, and failed state should be cleared)
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Commit) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_discard_commit";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: discard
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: commit (should succeed)
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Discard) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_discard_Discard";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: discard
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: discard
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be 0
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // S2: read it again (should be 0)
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+