Merge "Remove libsuspend from VNDK."
diff --git a/adb/Android.bp b/adb/Android.bp
index a18dc1a..41e752f 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -353,7 +353,6 @@
         "libcutils",
         "libext4_utils",
         "libfec",
-        "libfec_rs",
         "libfs_mgr",
         "liblog",
         "libmdnssd",
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index da273fd..41ac663 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1326,9 +1326,9 @@
 }
 
 int adb_commandline(int argc, const char** argv) {
-    int no_daemon = 0;
-    int is_daemon = 0;
-    int is_server = 0;
+    bool no_daemon = false;
+    bool is_daemon = false;
+    bool is_server = false;
     int r;
     TransportType transport_type = kTransportAny;
     int ack_reply_fd = -1;
@@ -1348,12 +1348,12 @@
 
     while (argc > 0) {
         if (!strcmp(argv[0],"server")) {
-            is_server = 1;
+            is_server = true;
         } else if (!strcmp(argv[0],"nodaemon")) {
-            no_daemon = 1;
+            no_daemon = true;
         } else if (!strcmp(argv[0], "fork-server")) {
             /* this is a special flag used only when the ADB client launches the ADB Server */
-            is_daemon = 1;
+            is_daemon = true;
         } else if (!strcmp(argv[0], "--reply-fd")) {
             if (argc < 2) return syntax_error("--reply-fd requires an argument");
             const char* reply_fd_str = argv[1];
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index de6c723..095ad98 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -118,10 +118,20 @@
 
     init_transport_registration();
     init_reconnect_handler();
-    init_mdns_transport_discovery();
 
-    usb_init();
-    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    if (!getenv("ADB_MDNS") || strcmp(getenv("ADB_MDNS"), "0") != 0) {
+        init_mdns_transport_discovery();
+    }
+
+    if (!getenv("ADB_USB") || strcmp(getenv("ADB_USB"), "0") != 0) {
+        usb_init();
+    } else {
+        adb_notify_device_scan_complete();
+    }
+
+    if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) {
+        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    }
 
     std::string error;
 
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index dfcc52d..8417690 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 #include <thread>
@@ -96,41 +98,44 @@
 
 void reboot_service(unique_fd fd, const std::string& arg) {
     std::string reboot_arg = arg;
-    bool auto_reboot = false;
-
-    if (reboot_arg == "sideload-auto-reboot") {
-        auto_reboot = true;
-        reboot_arg = "sideload";
-    }
-
-    // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
-    // in the command file.
-    if (reboot_arg == "sideload") {
-        if (getuid() != 0) {
-            WriteFdExactly(fd.get(), "'adb root' is required for 'adb reboot sideload'.\n");
-            return;
-        }
-
-        const std::vector<std::string> options = {auto_reboot ? "--sideload_auto_reboot"
-                                                              : "--sideload"};
-        std::string err;
-        if (!write_bootloader_message(options, &err)) {
-            D("Failed to set bootloader message: %s", err.c_str());
-            return;
-        }
-
-        reboot_arg = "recovery";
-    }
-
     sync();
 
     if (reboot_arg.empty()) reboot_arg = "adb";
     std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
-    if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
-        WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
-        return;
-    }
 
+    if (reboot_arg == "fastboot" && access("/dev/socket/recovery", F_OK) == 0) {
+        LOG(INFO) << "Recovery specific reboot fastboot";
+        /*
+         * The socket is created to allow switching between recovery and
+         * fastboot.
+         */
+        android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+        if (sock < 0) {
+            WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
+            PLOG(ERROR) << "Creating recovery socket failed";
+            return;
+        }
+
+        sockaddr_un addr = {.sun_family = AF_UNIX};
+        strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+        if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+            WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't connect to recovery socket";
+            return;
+        }
+        const char msg_switch_to_fastboot = 'f';
+        auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
+        if (ret != sizeof(msg_switch_to_fastboot)) {
+            WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
+            return;
+        }
+    } else {
+        if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
+            WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
+            return;
+        }
+    }
     // Don't return early. Give the reboot command time to take effect
     // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
     while (true) {
diff --git a/adb/test_adb.py b/adb/test_adb.py
index d4c98e4..86c13d0 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -28,6 +28,7 @@
 import struct
 import subprocess
 import threading
+import time
 import unittest
 
 
@@ -90,7 +91,7 @@
     server_thread.start()
 
     try:
-        yield port
+        yield port, writesock
     finally:
         writesock.close()
         server_thread.join()
@@ -120,7 +121,7 @@
 def adb_server():
     """Context manager for an ADB server.
 
-    This creates an ADB server and returns the port it"s listening on.
+    This creates an ADB server and returns the port it's listening on.
     """
 
     port = 5038
@@ -342,7 +343,7 @@
         Bug: http://b/78991667
         """
         with adb_server() as server_port:
-            with fake_adbd() as port:
+            with fake_adbd() as (port, _):
                 serial = "emulator-{}".format(port - 1)
                 # Ensure that the emulator is not there.
                 try:
@@ -380,7 +381,7 @@
         """
         for protocol in (socket.AF_INET, socket.AF_INET6):
             try:
-                with fake_adbd(protocol=protocol) as port:
+                with fake_adbd(protocol=protocol) as (port, _):
                     serial = "localhost:{}".format(port)
                     with adb_connect(self, serial):
                         pass
@@ -391,7 +392,7 @@
     def test_already_connected(self):
         """Ensure that an already-connected device stays connected."""
 
-        with fake_adbd() as port:
+        with fake_adbd() as (port, _):
             serial = "localhost:{}".format(port)
             with adb_connect(self, serial):
                 # b/31250450: this always returns 0 but probably shouldn't.
@@ -403,7 +404,7 @@
     def test_reconnect(self):
         """Ensure that a disconnected device reconnects."""
 
-        with fake_adbd() as port:
+        with fake_adbd() as (port, _):
             serial = "localhost:{}".format(port)
             with adb_connect(self, serial):
                 output = subprocess.check_output(["adb", "-s", serial,
@@ -439,6 +440,46 @@
                         "error: device '{}' not found".format(serial).encode("utf8"))
 
 
+class DisconnectionTest(unittest.TestCase):
+    """Tests for adb disconnect."""
+
+    def test_disconnect(self):
+        """Ensure that `adb disconnect` takes effect immediately."""
+
+        def _devices(port):
+            output = subprocess.check_output(["adb", "-P", str(port), "devices"])
+            return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
+
+        with adb_server() as server_port:
+            with fake_adbd() as (port, sock):
+                device_name = "localhost:{}".format(port)
+                output = subprocess.check_output(["adb", "-P", str(server_port),
+                                                  "connect", device_name])
+                self.assertEqual(output.strip(),
+                                  "connected to {}".format(device_name).encode("utf8"))
+
+
+                self.assertEqual(_devices(server_port), [[device_name, "device"]])
+
+                # Send a deliberately malformed packet to make the device go offline.
+                packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0)
+                sock.sendall(packet)
+
+                # Wait a bit.
+                time.sleep(0.1)
+
+                self.assertEqual(_devices(server_port), [[device_name, "offline"]])
+
+                # Disconnect the device.
+                output = subprocess.check_output(["adb", "-P", str(server_port),
+                                                  "disconnect", device_name])
+
+                # Wait a bit.
+                time.sleep(0.1)
+
+                self.assertEqual(_devices(server_port), [])
+
+
 def main():
     """Main entrypoint."""
     random.seed(0)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 0e8db04..332e0f8 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -33,7 +33,7 @@
 #include <deque>
 #include <list>
 #include <mutex>
-#include <queue>
+#include <set>
 #include <thread>
 
 #include <android-base/logging.h>
@@ -97,6 +97,9 @@
     // Adds the atransport* to the queue of reconnect attempts.
     void TrackTransport(atransport* transport);
 
+    // Wake up the ReconnectHandler thread to have it check for kicked transports.
+    void CheckForKicked();
+
   private:
     // The main thread loop.
     void Run();
@@ -108,9 +111,11 @@
         size_t attempts_left;
 
         bool operator<(const ReconnectAttempt& rhs) const {
-            // std::priority_queue returns the largest element first, so we want attempts that have
-            // less time remaining (i.e. smaller time_points) to compare greater.
-            return reconnect_time > rhs.reconnect_time;
+            if (reconnect_time == rhs.reconnect_time) {
+                return reinterpret_cast<uintptr_t>(transport) <
+                       reinterpret_cast<uintptr_t>(rhs.transport);
+            }
+            return reconnect_time < rhs.reconnect_time;
         }
     };
 
@@ -123,7 +128,7 @@
     bool running_ GUARDED_BY(reconnect_mutex_) = true;
     std::thread handler_thread_;
     std::condition_variable reconnect_cv_;
-    std::priority_queue<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
+    std::set<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
 
     DISALLOW_COPY_AND_ASSIGN(ReconnectHandler);
 };
@@ -145,8 +150,8 @@
     // Drain the queue to free all resources.
     std::lock_guard<std::mutex> lock(reconnect_mutex_);
     while (!reconnect_queue_.empty()) {
-        ReconnectAttempt attempt = reconnect_queue_.top();
-        reconnect_queue_.pop();
+        ReconnectAttempt attempt = *reconnect_queue_.begin();
+        reconnect_queue_.erase(reconnect_queue_.begin());
         remove_transport(attempt.transport);
     }
 }
@@ -164,6 +169,10 @@
     reconnect_cv_.notify_one();
 }
 
+void ReconnectHandler::CheckForKicked() {
+    reconnect_cv_.notify_one();
+}
+
 void ReconnectHandler::Run() {
     while (true) {
         ReconnectAttempt attempt;
@@ -176,28 +185,38 @@
                 //        system_clock as its clock, so we're probably hosed if the clock changes,
                 //        even if we use steady_clock throughout. This problem goes away once we
                 //        switch to libc++.
-                reconnect_cv_.wait_until(lock, reconnect_queue_.top().reconnect_time);
+                reconnect_cv_.wait_until(lock, reconnect_queue_.begin()->reconnect_time);
             } else {
                 reconnect_cv_.wait(lock);
             }
 
             if (!running_) return;
+
+            // Scan the whole list for kicked transports, so that we immediately handle an explicit
+            // disconnect request.
+            bool kicked = false;
+            for (auto it = reconnect_queue_.begin(); it != reconnect_queue_.end();) {
+                if (it->transport->kicked()) {
+                    D("transport %s was kicked. giving up on it.", it->transport->serial.c_str());
+                    remove_transport(it->transport);
+                    it = reconnect_queue_.erase(it);
+                } else {
+                    ++it;
+                }
+                kicked = true;
+            }
+
             if (reconnect_queue_.empty()) continue;
 
-            // Go back to sleep in case |reconnect_cv_| woke up spuriously and we still
-            // have more time to wait for the current attempt.
+            // Go back to sleep if we either woke up spuriously, or we were woken up to remove
+            // a kicked transport, and the first transport isn't ready for reconnection yet.
             auto now = std::chrono::steady_clock::now();
-            if (reconnect_queue_.top().reconnect_time > now) {
+            if (reconnect_queue_.begin()->reconnect_time > now) {
                 continue;
             }
 
-            attempt = reconnect_queue_.top();
-            reconnect_queue_.pop();
-            if (attempt.transport->kicked()) {
-                D("transport %s was kicked. giving up on it.", attempt.transport->serial.c_str());
-                remove_transport(attempt.transport);
-                continue;
-            }
+            attempt = *reconnect_queue_.begin();
+            reconnect_queue_.erase(reconnect_queue_.begin());
         }
         D("attempting to reconnect %s", attempt.transport->serial.c_str());
 
@@ -446,6 +465,10 @@
     if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
         t->Kick();
     }
+
+#if ADB_HOST
+    reconnect_handler.CheckForKicked();
+#endif
 }
 
 static int transport_registration_send = -1;
@@ -1274,6 +1297,9 @@
             t->Kick();
         }
     }
+#if ADB_HOST
+    reconnect_handler.CheckForKicked();
+#endif
 }
 
 #endif
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
old mode 100755
new mode 100644
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 60c338c..a679143 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -82,6 +82,7 @@
 
 LOCAL_CFLAGS := $(fastboot_cflags)
 LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CPP_STD := c++17
 LOCAL_CXX_STL := $(fastboot_stl)
 LOCAL_HEADER_LIBRARIES := bootimg_headers
 LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index a5dead2..65cfea3 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -123,10 +123,14 @@
     }
     std::string slot_suffix = device->GetCurrentSlot();
     if (slot_suffix.empty()) {
-        return device->WriteFail("Invalid slot");
+        return device->WriteOkay("no");
     }
-    std::string result = (args[0] == "userdata" ? "no" : "yes");
-    return device->WriteOkay(result);
+    std::string partition_name = args[0] + slot_suffix;
+    if (FindPhysicalPartition(partition_name) ||
+        LogicalPartitionExists(partition_name, slot_suffix)) {
+        return device->WriteOkay("yes");
+    }
+    return device->WriteOkay("no");
 }
 
 bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args) {
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index e8711cb..dd199c0 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -57,7 +57,7 @@
 
 class FastBootDriver {
   public:
-    static constexpr int RESP_TIMEOUT = 10;  // 10 seconds
+    static constexpr int RESP_TIMEOUT = 30;  // 30 seconds
     static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits<uint32_t>::max();
     static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024;
 
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 6329d54..3cce0e8 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -31,6 +31,8 @@
 }
 
 cc_library {
+    // Do not ever allow this library to be vendor_available as a shared library.
+    // It does not have a stable interface.
     name: "libfs_mgr",
     defaults: ["fs_mgr_defaults"],
     recovery_available: true,
@@ -46,18 +48,15 @@
         "fs_mgr_overlayfs.cpp",
     ],
     shared_libs: [
-        "libfec",
-        "libfec_rs",
         "libbase",
-        "libcrypto_utils",
         "libcrypto",
+        "libcrypto_utils",
         "libcutils",
         "libext4_utils",
-        "libkeyutils",
+        "libfec",
         "liblog",
-        "libsquashfs_utils",
-        "libselinux",
         "liblp",
+        "libselinux",
     ],
     static_libs: [
         "libavb",
@@ -90,6 +89,8 @@
 }
 
 cc_library_static {
+    // Do not ever make this a shared library as long as it is vendor_available.
+    // It does not have a stable interface.
     name: "libfstab",
     vendor_available: true,
     recovery_available: true,
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 74dfc00..78151d5 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -65,11 +65,10 @@
 // acceptable overlayfs backing storage
 const auto kOverlayMountPoint = "/cache"s;
 
-// return true if everything is mounted, but before adb is started.  At
-// 'trigger firmware_mounts_complete' after 'trigger load_persist_props_action'.
+// Return true if everything is mounted, but before adb is started.  Right
+// after 'trigger load_persist_props_action' is done.
 bool fs_mgr_boot_completed() {
-    return !android::base::GetProperty("ro.boottime.init", "").empty() &&
-           !!access("/dev/.booting", F_OK);
+    return android::base::GetBoolProperty("ro.persistent_properties.ready", false);
 }
 
 bool fs_mgr_is_dir(const std::string& path) {
@@ -164,7 +163,9 @@
     // Overlayfs available in the kernel, and patched for override_creds?
     static signed char overlayfs_in_kernel = -1;  // cache for constant condition
     if (overlayfs_in_kernel == -1) {
+        auto save_errno = errno;
         overlayfs_in_kernel = !access("/sys/module/overlay/parameters/override_creds", F_OK);
+        errno = save_errno;
     }
     return overlayfs_in_kernel;
 }
@@ -430,7 +431,7 @@
     const auto newpath = oldpath + ".teardown";
     ret &= fs_mgr_rm_all(newpath);
     auto save_errno = errno;
-    if (rename(oldpath.c_str(), newpath.c_str())) {
+    if (!rename(oldpath.c_str(), newpath.c_str())) {
         if (change) *change = true;
     } else if (errno != ENOENT) {
         ret = false;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 7401857..2f88121 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -473,7 +473,21 @@
                                   "bootloader_message: "
                                << err;
                 }
+            } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
+                       reboot_target == "fastboot") {
+                std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
+                                                                          : reboot_target;
+                const std::vector<std::string> options = {
+                        "--" + arg,
+                };
+                std::string err;
+                if (!write_bootloader_message(options, &err)) {
+                    LOG(ERROR) << "Failed to set bootloader message: " << err;
+                    return false;
+                }
+                reboot_target = "recovery";
             }
+
             // If there is an additional parameter, pass it along
             if ((cmd_params.size() == 3) && cmd_params[2].size()) {
                 reboot_target += "," + cmd_params[2];
diff --git a/llkd/README.md b/llkd/README.md
index b2ba2a2..2314583 100644
--- a/llkd/README.md
+++ b/llkd/README.md
@@ -60,7 +60,7 @@
 Android Properties
 ------------------
 
-Android Properties llkd respond to (<prop>_ms parms are in milliseconds):
+Android Properties llkd respond to (*prop*_ms parms are in milliseconds):
 
 #### ro.config.low_ram
 default false, if true do not sysrq t (dump all threads).
@@ -99,19 +99,33 @@
 #### ro.llk.blacklist.process
 default 0,1,2 (kernel, init and [kthreadd]) plus process names
 init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,
-[watchdogd],[watchdogd/0],...,[watchdogd/<get_nprocs-1>].
+[watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*].
+The string false is the equivalent to an empty list.
+Do not watch these processes.  A process can be comm, cmdline or pid reference.
+NB: automated default here can be larger than the current maximum property
+size of 92.
+NB: false is a very very very unlikely process to want to blacklist.
 
 #### ro.llk.blacklist.parent
 default 0,2 (kernel and [kthreadd]).
+The string false is the equivalent to an empty list.
+Do not watch processes that have this parent.
+A parent process can be comm, cmdline or pid reference.
 
 #### ro.llk.blacklist.uid
-default <empty>, comma separated list of uid numbers or names.
+default *empty* or false, comma separated list of uid numbers or names.
+The string false is the equivalent to an empty list.
+Do not watch processes that match this uid.
 
 Architectural Concerns
 ----------------------
 
+- built-in [khungtask] daemon is too generic and trips on driver code that
+  sits around in D state too much.  To switch to S instead makes the task(s)
+  killable, so the drivers should be able to resurrect them if needed.
+- Properties are limited to 92 characters.
 - Create kernel module and associated gTest to actually test panic.
-- Create gTest to test out blacklist (ro.llk.blacklist.<properties> generally
+- Create gTest to test out blacklist (ro.llk.blacklist.*properties* generally
   not be inputs).  Could require more test-only interfaces to libllkd.
-- Speed up gTest using something else than ro.llk.<properties>, which should
-  not be inputs.
+- Speed up gTest using something else than ro.llk.*properties*, which should
+  not be inputs as they should be baked into the product.
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 3b28775..48551f2 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -285,7 +285,7 @@
           schedUpdate(0),
           nrSwitches(0),
           update(llkUpdate),
-          count(0),
+          count(0ms),
           pid(pid),
           ppid(ppid),
           uid(-1),
@@ -574,15 +574,19 @@
 
 // We only officially support comma separators, but wetware being what they
 // are will take some liberty and I do not believe they should be punished.
-std::unordered_set<std::string> llkSplit(const std::string& s,
-                                         const std::string& delimiters = ", \t:") {
+std::unordered_set<std::string> llkSplit(const std::string& s) {
     std::unordered_set<std::string> result;
 
+    // Special case, allow boolean false to empty the list, otherwise expected
+    // source of input from android::base::GetProperty will supply the default
+    // value on empty content in the property.
+    if (s == "false") return result;
+
     size_t base = 0;
-    size_t found;
-    while (true) {
-        found = s.find_first_of(delimiters, base);
-        result.emplace(s.substr(base, found - base));
+    while (s.size() > base) {
+        auto found = s.find_first_of(", \t:", base);
+        // Only emplace content, empty entries are not an option
+        if (found != base) result.emplace(s.substr(base, found - base));
         if (found == s.npos) break;
         base = found + 1;
     }
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 1369b8b..903d0e2 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -20,6 +20,7 @@
             ],
         },
     },
+    logtags: ["event.logtags"],
 }
 
 cc_library_static {
diff --git a/lmkd/event.logtags b/lmkd/event.logtags
new file mode 100644
index 0000000..7c2cd18
--- /dev/null
+++ b/lmkd/event.logtags
@@ -0,0 +1,38 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# s: Number of seconds (monotonic time)
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+# for meminfo logs
+10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 3b45db7..02534f2 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -37,6 +37,7 @@
 #include <cutils/sockets.h>
 #include <lmkd.h>
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #ifdef LMKD_LOG_STATS
 #include "statslog.h"
@@ -72,6 +73,9 @@
 #define MEMINFO_PATH "/proc/meminfo"
 #define LINE_MAX 128
 
+/* Android Logger event logtags (see event.logtags) */
+#define MEMINFO_LOG_TAG 10195355
+
 /* gid containing AID_SYSTEM required */
 #define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
 #define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
@@ -85,6 +89,8 @@
 #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
 #define STRINGIFY_INTERNAL(x) #x
 
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
 /* default to old in-kernel interface if no memory pressure events */
 static bool use_inkernel_interface = true;
 static bool has_inkernel_module;
@@ -119,6 +125,9 @@
 static unsigned long kill_timeout_ms;
 static bool use_minfree_levels;
 static bool per_app_memcg;
+static int swap_free_low_percentage;
+
+static android_log_context ctx;
 
 /* data required to handle events */
 struct event_handler_info {
@@ -197,8 +206,19 @@
     MI_BUFFERS,
     MI_SHMEM,
     MI_UNEVICTABLE,
+    MI_TOTAL_SWAP,
     MI_FREE_SWAP,
-    MI_DIRTY,
+    MI_ACTIVE_ANON,
+    MI_INACTIVE_ANON,
+    MI_ACTIVE_FILE,
+    MI_INACTIVE_FILE,
+    MI_SRECLAIMABLE,
+    MI_SUNRECLAIM,
+    MI_KERNEL_STACK,
+    MI_PAGE_TABLES,
+    MI_ION_HELP,
+    MI_ION_HELP_POOL,
+    MI_CMA_FREE,
     MI_FIELD_COUNT
 };
 
@@ -209,8 +229,19 @@
     "Buffers:",
     "Shmem:",
     "Unevictable:",
+    "SwapTotal:",
     "SwapFree:",
-    "Dirty:",
+    "Active(anon):",
+    "Inactive(anon):",
+    "Active(file):",
+    "Inactive(file):",
+    "SReclaimable:",
+    "SUnreclaim:",
+    "KernelStack:",
+    "PageTables:",
+    "ION_heap:",
+    "ION_heap_pool:",
+    "CmaFree:",
 };
 
 union meminfo {
@@ -221,8 +252,19 @@
         int64_t buffers;
         int64_t shmem;
         int64_t unevictable;
+        int64_t total_swap;
         int64_t free_swap;
-        int64_t dirty;
+        int64_t active_anon;
+        int64_t inactive_anon;
+        int64_t active_file;
+        int64_t inactive_file;
+        int64_t sreclaimable;
+        int64_t sunreclaimable;
+        int64_t kernel_stack;
+        int64_t page_tables;
+        int64_t ion_heap;
+        int64_t ion_heap_pool;
+        int64_t cma_free;
         /* fields below are calculated rather than read from the file */
         int64_t nr_file_pages;
     } field;
@@ -922,6 +964,15 @@
     return 0;
 }
 
+static void meminfo_log(union meminfo *mi) {
+    for (int field_idx = 0; field_idx < MI_FIELD_COUNT; field_idx++) {
+        android_log_write_int32(ctx, (int32_t)min(mi->arr[field_idx] * page_k, INT32_MAX));
+    }
+
+    android_log_write_list(ctx, LOG_ID_EVENTS);
+    android_log_reset(ctx);
+}
+
 static int proc_get_size(int pid) {
     char path[PATH_MAX];
     char line[LINE_MAX];
@@ -1306,20 +1357,24 @@
         }
     }
 
-    // If the pressure is larger than downgrade_pressure lmk will not
-    // kill any process, since enough memory is available.
-    if (mem_pressure > downgrade_pressure) {
-        if (debug_process_killing) {
-            ALOGI("Ignore %s memory pressure", level_name[level]);
+    // If we still have enough swap space available, check if we want to
+    // ignore/downgrade pressure events.
+    if (mi.field.free_swap >=
+        mi.field.total_swap * swap_free_low_percentage / 100) {
+        // If the pressure is larger than downgrade_pressure lmk will not
+        // kill any process, since enough memory is available.
+        if (mem_pressure > downgrade_pressure) {
+            if (debug_process_killing) {
+                ALOGI("Ignore %s memory pressure", level_name[level]);
+            }
+            return;
+        } else if (level == VMPRESS_LEVEL_CRITICAL && mem_pressure > upgrade_pressure) {
+            if (debug_process_killing) {
+                ALOGI("Downgrade critical memory pressure");
+            }
+            // Downgrade event, since enough memory available.
+            level = downgrade_level(level);
         }
-        return;
-    } else if (level == VMPRESS_LEVEL_CRITICAL &&
-               mem_pressure > upgrade_pressure) {
-        if (debug_process_killing) {
-            ALOGI("Downgrade critical memory pressure");
-        }
-        // Downgrade event, since enough memory available.
-        level = downgrade_level(level);
     }
 
 do_kill:
@@ -1329,6 +1384,8 @@
             if (debug_process_killing) {
                 ALOGI("Nothing to kill");
             }
+        } else {
+            meminfo_log(&mi);
         }
     } else {
         int pages_freed;
@@ -1377,6 +1434,9 @@
                   pages_to_free, pages_freed);
             gettimeofday(&last_report_tm, NULL);
         }
+        if (pages_freed > 0) {
+            meminfo_log(&mi);
+        }
     }
 }
 
@@ -1590,6 +1650,10 @@
         property_get_bool("ro.lmk.use_minfree_levels", false);
     per_app_memcg =
         property_get_bool("ro.config.per_app_memcg", low_ram_device);
+    swap_free_low_percentage =
+        property_get_int32("ro.lmk.swap_free_low_percentage", 10);
+
+    ctx = create_android_logger(MEMINFO_LOG_TAG);
 
 #ifdef LMKD_LOG_STATS
     statslog_init(&log_ctx, &enable_stats_log);
@@ -1626,6 +1690,8 @@
     statslog_destroy(&log_ctx);
 #endif
 
+    android_log_destroy(&ctx);
+
     ALOGI("exiting");
     return 0;
 }
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 4ea7877..fc8c960 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/prctl.h>
@@ -344,8 +345,7 @@
 
         rc = logbuf->log(
             LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
-            (message_len <= USHRT_MAX) ? (unsigned short)message_len
-                                       : USHRT_MAX);
+            (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
         if (rc >= 0) {
             notify |= 1 << LOG_ID_EVENTS;
         }
@@ -399,9 +399,9 @@
         strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
                 denial_metadata.c_str(), denial_metadata.length());
 
-        rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
-                         (message_len <= USHRT_MAX) ? (unsigned short)message_len
-                                                    : USHRT_MAX);
+        rc = logbuf->log(
+            LOG_ID_MAIN, now, uid, pid, tid, newstr,
+            (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
 
         if (rc >= 0) {
             notify |= 1 << LOG_ID_MAIN;
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 9b04363..fd1b8b2 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -199,7 +199,7 @@
 }
 
 int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                   pid_t tid, const char* msg, unsigned short len) {
+                   pid_t tid, const char* msg, uint16_t len) {
     if (log_id >= LOG_ID_MAX) {
         return -EINVAL;
     }
@@ -240,7 +240,7 @@
     LogBufferElement* currentLast = lastLoggedElements[log_id];
     if (currentLast) {
         LogBufferElement* dropped = droppedElements[log_id];
-        unsigned short count = dropped ? dropped->getDropped() : 0;
+        uint16_t count = dropped ? dropped->getDropped() : 0;
         //
         // State Init
         //     incoming:
@@ -584,13 +584,13 @@
     LogBufferElementMap map;
 
    public:
-    bool coalesce(LogBufferElement* element, unsigned short dropped) {
+    bool coalesce(LogBufferElement* element, uint16_t dropped) {
         LogBufferElementKey key(element->getUid(), element->getPid(),
                                 element->getTid());
         LogBufferElementMap::iterator it = map.find(key.getKey());
         if (it != map.end()) {
             LogBufferElement* found = it->second;
-            unsigned short moreDropped = found->getDropped();
+            uint16_t moreDropped = found->getDropped();
             if ((dropped + moreDropped) > USHRT_MAX) {
                 map.erase(it);
             } else {
@@ -847,7 +847,7 @@
                 mLastSet[id] = true;
             }
 
-            unsigned short dropped = element->getDropped();
+            uint16_t dropped = element->getDropped();
 
             // remove any leading drops
             if (leading && dropped) {
@@ -927,7 +927,7 @@
 
             kick = true;
 
-            unsigned short len = element->getMsgLen();
+            uint16_t len = element->getMsgLen();
 
             // do not create any leading drops
             if (leading) {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 0942987..774d4ab 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -115,7 +115,7 @@
     }
 
     int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
-            const char* msg, unsigned short len) override;
+            const char* msg, uint16_t len) override;
     // lastTid is an optional context to help detect if the last previous
     // valid message was from the same source so we can differentiate chatty
     // filter types (identical or expired)
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 2d627b9..19e6d68 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -35,7 +35,7 @@
 
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
-                                   const char* msg, unsigned short len)
+                                   const char* msg, uint16_t len)
     : mUid(uid),
       mPid(pid),
       mTid(tid),
@@ -71,7 +71,7 @@
                : 0;
 }
 
-unsigned short LogBufferElement::setDropped(unsigned short value) {
+uint16_t LogBufferElement::setDropped(uint16_t value) {
     // The tag information is saved in mMsg data, if the tag is non-zero
     // save only the information needed to get the tag.
     if (getTag() != 0) {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index b168645..57b0a95 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -18,6 +18,7 @@
 #define _LOGD_LOG_BUFFER_ELEMENT_H__
 
 #include <stdatomic.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 
@@ -56,7 +57,7 @@
 
    public:
     LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                     pid_t tid, const char* msg, unsigned short len);
+                     pid_t tid, const char* msg, uint16_t len);
     LogBufferElement(const LogBufferElement& elem);
     ~LogBufferElement();
 
@@ -77,11 +78,11 @@
         return mTid;
     }
     uint32_t getTag() const;
-    unsigned short getDropped(void) const {
+    uint16_t getDropped(void) const {
         return mDropped ? mDroppedCount : 0;
     }
-    unsigned short setDropped(unsigned short value);
-    unsigned short getMsgLen() const {
+    uint16_t setDropped(uint16_t value);
+    uint16_t getMsgLen() const {
         return mDropped ? 0 : mMsgLen;
     }
     const char* getMsg() const {
diff --git a/logd/LogBufferInterface.h b/logd/LogBufferInterface.h
index ff73a22..f31e244 100644
--- a/logd/LogBufferInterface.h
+++ b/logd/LogBufferInterface.h
@@ -31,7 +31,7 @@
     // Handles a log entry when available in LogListener.
     // Returns the size of the handled log message.
     virtual int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                    pid_t tid, const char* msg, unsigned short len) = 0;
+                    pid_t tid, const char* msg, uint16_t len) = 0;
 
     virtual uid_t pidToUid(pid_t pid);
     virtual pid_t tidToPid(pid_t tid);
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index ab980ac..e4393a3 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -821,8 +821,7 @@
     }
 
     // Log message
-    int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
-                         (unsigned short)n);
+    int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
 
     // notify readers
     if (rc > 0) {
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index e568ddc..2f22778 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -136,7 +136,7 @@
     if (logbuf != nullptr) {
         int res = logbuf->log(
             logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
-            ((size_t)n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
+            ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
         if (res > 0 && reader != nullptr) {
             reader->notifyNewLog(static_cast<log_mask_t>(1 << logId));
         }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index cefacf7..116e08e 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -83,7 +83,7 @@
     if (element->getDropped()) return;
 
     log_id_t log_id = element->getLogId();
-    unsigned short size = element->getMsgLen();
+    uint16_t size = element->getMsgLen();
     mSizesTotal[log_id] += size;
     SizesTotal += size;
     ++mElementsTotal[log_id];
@@ -91,7 +91,7 @@
 
 void LogStatistics::add(LogBufferElement* element) {
     log_id_t log_id = element->getLogId();
-    unsigned short size = element->getMsgLen();
+    uint16_t size = element->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
 
@@ -161,7 +161,7 @@
 
 void LogStatistics::subtract(LogBufferElement* element) {
     log_id_t log_id = element->getLogId();
-    unsigned short size = element->getMsgLen();
+    uint16_t size = element->getMsgLen();
     mSizes[log_id] -= size;
     --mElements[log_id];
     if (element->getDropped()) {
@@ -206,7 +206,7 @@
 // entry->setDropped(1) must follow this call, caller should do this explicitly.
 void LogStatistics::drop(LogBufferElement* element) {
     log_id_t log_id = element->getLogId();
-    unsigned short size = element->getMsgLen();
+    uint16_t size = element->getMsgLen();
     mSizes[log_id] -= size;
     ++mDroppedElements[log_id];
 
@@ -613,13 +613,13 @@
 
 std::string LogStatistics::format(uid_t uid, pid_t pid,
                                   unsigned int logMask) const {
-    static const unsigned short spaces_total = 19;
+    static const uint16_t spaces_total = 19;
 
     // Report on total logging, current and for all time
 
     std::string output = "size/num";
     size_t oldLength;
-    short spaces = 1;
+    int16_t spaces = 1;
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) continue;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index ac3cf9a..d6b8ab3 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -520,7 +520,7 @@
             return;
         }
         ++msg;
-        unsigned short len = element->getMsgLen();
+        uint16_t len = element->getMsgLen();
         len = (len <= 1) ? 0 : strnlen(msg, len - 1);
         if (!len) {
             name = std::string_view("<NULL>", strlen("<NULL>"));
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3a6a5e8..2429b49 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -162,66 +162,6 @@
 )
 endef
 
-# Update namespace configuration file with library lists and VNDK version
-#
-# $(1): Input source file (ld.config.txt)
-# $(2): Output built module
-# $(3): VNDK version suffix
-# $(4): true if libz must be included in llndk not in vndk-sp
-define update_and_install_ld_config
-# If $(4) is true, move libz to llndk from vndk-sp.
-$(if $(filter true,$(4)),\
-  $(eval llndk_libraries_list := $(LLNDK_LIBRARIES) libz) \
-  $(eval vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))),\
-  $(eval llndk_libraries_list := $(LLNDK_LIBRARIES)) \
-  $(eval vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)))
-
-llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
-private_llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(filter $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
-vndk_sameprocess_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(vndksp_libraries_list))))
-vndk_core_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(UBSAN_RUNTIME_LIBRARY) \
-  $(TSAN_RUNTIME_LIBRARY) \
-  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_UBSAN_RUNTIME_LIBRARY) \
-  $(2ND_TSAN_RUNTIME_LIBRARY)))
-# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used.
-vndk_version_suffix := $(if $(strip $(3)),-$(strip $(3)))
-
-$(2): PRIVATE_LLNDK_LIBRARIES := $$(llndk_libraries)
-$(2): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $$(private_llndk_libraries)
-$(2): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $$(vndk_sameprocess_libraries)
-$(2): PRIVATE_VNDK_CORE_LIBRARIES := $$(vndk_core_libraries)
-$(2): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $$(sanitizer_runtime_libraries)
-$(2): PRIVATE_VNDK_VERSION := $$(vndk_version_suffix)
-$(2): $(1)
-	@echo "Generate: $$< -> $$@"
-	@mkdir -p $$(dir $$@)
-	$$(hide) sed -e 's?%LLNDK_LIBRARIES%?$$(PRIVATE_LLNDK_LIBRARIES)?g' $$< >$$@
-	$$(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $$@
-	$$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $$@
-	$$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $$@
-	$$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@
-	$$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@
-	$$(hide) sed -i -e 's?%PRODUCT%?$$(TARGET_COPY_OUT_PRODUCT)?g' $$@
-	$$(hide) sed -i -e 's?%PRODUCTSERVICES%?$$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $$@
-
-llndk_libraries_list :=
-vndksp_libraries_list :=
-llndk_libraries :=
-private_llndk_libraries :=
-vndk_sameprocess_libraries :=
-vndk_core_libraries :=
-sanitizer_runtime_libraries :=
-vndk_version_suffix :=
-endef # update_and_install_ld_config
-
 
 #######################################
 # ld.config.txt selection variables
@@ -265,21 +205,19 @@
 # for VNDK enforced devices
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.txt,\
-  $(LOCAL_BUILT_MODULE),\
-  $(PLATFORM_VNDK_VERSION)))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
 
 else ifeq ($(_enforce_vndk_lite_at_runtime),true)
 
 # for treblized but VNDK lightly enforced devices
 LOCAL_MODULE_STEM := ld.config.vndk_lite.txt
 include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
-  $(LOCAL_BUILT_MODULE),\
-  $(PLATFORM_VNDK_VERSION),\
-  true))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+libz_is_llndk := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
 
 else
 
@@ -290,6 +228,37 @@
 
 endif  # ifeq ($(_enforce_vndk_at_runtime),true)
 
+# ld.config.txt for VNDK versions older than PLATFORM_VNDK_VERSION
+# are built with the VNDK libraries lists under /prebuilts/vndk.
+#
+# ld.config.$(VER).txt is built and installed for all VNDK versions
+# listed in PRODUCT_EXTRA_VNDK_VERSIONS.
+#
+# $(1): VNDK version
+define build_versioned_ld_config
+include $(CLEAR_VARS)
+LOCAL_MODULE := ld.config.$(1).txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $$(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
+vndk_version := $(1)
+lib_list_from_prebuilts := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
+endef
+
+# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the
+# prebuilt under /prebuilts/vndk
+vndk_snapshots := $(wildcard prebuilts/vndk/*)
+supported_vndk_snapshot_versions := \
+  $(strip $(foreach ver,$(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)),\
+    $(if $(call math_gt_or_eq,$(ver),28),$(ver),)))
+$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\
+  $(call build_versioned_ld_config,$(ver))))
+
+vndk_snapshots :=
+supported_vndk_snapshot_versions :=
 
 #######################################
 # ld.config.vndk_lite.txt
@@ -304,11 +273,10 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
-  $(LOCAL_BUILT_MODULE),\
-  $(PLATFORM_VNDK_VERSION),\
-  true))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+libz_is_llndk := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
 
 endif  # ifeq ($(_enforce_vndk_lite_at_runtime),false)
 
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
new file mode 100644
index 0000000..1b42c32
--- /dev/null
+++ b/rootdir/update_and_install_ld_config.mk
@@ -0,0 +1,125 @@
+#####################################################################
+# Builds linker config file, ld.config.txt, from the specified template
+# under $(LOCAL_PATH)/etc/*.
+#
+# Inputs:
+#   (expected to follow an include of $(BUILD_SYSTEM)/base_rules.mk)
+#   ld_config_template: template linker config file to use,
+#                       e.g. $(LOCAL_PATH)/etc/ld.config.txt
+#   vndk_version: version of the VNDK library lists used to update the
+#                 template linker config file, e.g. 28
+#   lib_list_from_prebuilts: should be set to 'true' if the VNDK library
+#                            lists should be read from /prebuilts/vndk/*
+#   libz_is_llndk: should be set to 'true' if libz must be included in
+#                  llndk and not in vndk-sp
+# Outputs:
+#   Builds and installs ld.config.$VER.txt or ld.config.vndk_lite.txt
+#####################################################################
+
+# Read inputs
+ld_config_template := $(strip $(ld_config_template))
+vndk_version := $(strip $(vndk_version))
+lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts))
+libz_is_llndk := $(strip $(libz_is_llndk))
+
+intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE))
+library_lists_dir := $(intermediates_dir)
+ifeq ($(lib_list_from_prebuilts),true)
+  library_lists_dir := prebuilts/vndk/v$(vndk_version)/$(TARGET_ARCH)/configs
+endif
+
+llndk_libraries_file := $(library_lists_dir)/llndk.libraries.$(vndk_version).txt
+vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
+vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
+vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY) \
+  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(2ND_UBSAN_RUNTIME_LIBRARY) \
+  $(2ND_TSAN_RUNTIME_LIBRARY)))
+# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used.
+vndk_version_suffix := $(if $(vndk_version),-$(vndk_version))
+
+ifneq ($(lib_list_from_prebuilts),true)
+ifeq ($(libz_is_llndk),true)
+  llndk_libraries_list := $(LLNDK_LIBRARIES) libz
+  vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))
+else
+  llndk_libraries_list := $(LLNDK_LIBRARIES)
+  vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)
+endif
+
+# $(1): list of libraries
+# $(2): output file to write the list of libraries to
+define write-libs-to-file
+$(2): PRIVATE_LIBRARIES := $(1)
+$(2):
+	echo -n > $$@ && $$(foreach lib,$$(PRIVATE_LIBRARIES),echo $$(lib).so >> $$@;)
+endef
+$(eval $(call write-libs-to-file,$(llndk_libraries_list),$(llndk_libraries_file)))
+$(eval $(call write-libs-to-file,$(vndksp_libraries_list),$(vndksp_libraries_file)))
+$(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),$(vndkcore_libraries_file)))
+$(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),$(vndkprivate_libraries_file)))
+endif # ifneq ($(lib_list_from_prebuilts),true)
+
+# Given a file with a list of libs, filter-out the VNDK private libraries
+# and write resulting list to a new file in "a:b:c" format
+#
+# $(1): libs file from which to filter-out VNDK private libraries
+# $(2): output file with the filtered list of lib names
+$(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \
+  paste -sd ":" $(1) > $(2) && \
+  cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i.bak 's/privatelib//' $(2)" && \
+  sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) && \
+  rm -f $(2).bak
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE := $(vndkprivate_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
+$(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
+deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
+  $(vndkprivate_libraries_file)
+
+$(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps)
+	@echo "Generate: $< -> $@"
+	@mkdir -p $(dir $@)
+	$(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
+	$(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@
+	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)
+	$(hide) sed -i.bak -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@
+	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)
+	$(hide) sed -i.bak -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@
+
+	$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
+	cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \
+	xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \
+	paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
+	sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
+
+	$(hide) sed -i.bak -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
+	$(hide) sed -i.bak -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@
+	$(hide) sed -i.bak -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@
+	$(hide) sed -i.bak -e 's?%PRODUCTSERVICES%?$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $@
+	$(hide) rm -f $@.bak
+
+ld_config_template :=
+vndk_version :=
+lib_list_from_prebuilts :=
+libz_is_llndk :=
+intermediates_dir :=
+library_lists_dir :=
+llndk_libraries_file :=
+vndksp_libraries_file :=
+vndkcore_libraries_file :=
+vndkprivate_libraries_file :=
+deps :=
+sanitizer_runtime_libraries :=
+vndk_version_suffix :=
+llndk_libraries_list :=
+vndksp_libraries_list :=
+write-libs-to-file :=
diff --git a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
new file mode 100644
index 0000000..8e3b3b1
--- /dev/null
+++ b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
@@ -0,0 +1,448 @@
+/*
+ **
+ ** Copyright 2018, 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.
+ */
+
+#define LOG_TAG "android.hardware.keymaster@3.0-impl.trusty"
+
+#include <authorization_set.h>
+#include <cutils/log.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <trusty_keymaster/TrustyKeymaster3Device.h>
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::AddEntropyRequest;
+using ::keymaster::AddEntropyResponse;
+using ::keymaster::AttestKeyRequest;
+using ::keymaster::AttestKeyResponse;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::BeginOperationRequest;
+using ::keymaster::BeginOperationResponse;
+using ::keymaster::ExportKeyRequest;
+using ::keymaster::ExportKeyResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::GenerateKeyRequest;
+using ::keymaster::GenerateKeyResponse;
+using ::keymaster::GetKeyCharacteristicsRequest;
+using ::keymaster::GetKeyCharacteristicsResponse;
+using ::keymaster::ImportKeyRequest;
+using ::keymaster::ImportKeyResponse;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using ::keymaster::ng::Tag;
+
+namespace keymaster {
+
+namespace {
+
+inline keymaster_tag_t legacy_enum_conversion(const Tag value) {
+    return keymaster_tag_t(value);
+}
+inline Tag legacy_enum_conversion(const keymaster_tag_t value) {
+    return Tag(value);
+}
+inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+    return keymaster_purpose_t(value);
+}
+inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+    return keymaster_key_format_t(value);
+}
+inline ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+    return ErrorCode(value);
+}
+
+inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+    return keymaster_tag_get_type(tag);
+}
+
+class KmParamSet : public keymaster_key_param_set_t {
+  public:
+    KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+        params = new keymaster_key_param_t[keyParams.size()];
+        length = keyParams.size();
+        for (size_t i = 0; i < keyParams.size(); ++i) {
+            auto tag = legacy_enum_conversion(keyParams[i].tag);
+            switch (typeFromTag(tag)) {
+                case KM_ENUM:
+                case KM_ENUM_REP:
+                    params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+                    break;
+                case KM_UINT:
+                case KM_UINT_REP:
+                    params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+                    break;
+                case KM_ULONG:
+                case KM_ULONG_REP:
+                    params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+                    break;
+                case KM_DATE:
+                    params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+                    break;
+                case KM_BOOL:
+                    if (keyParams[i].f.boolValue)
+                        params[i] = keymaster_param_bool(tag);
+                    else
+                        params[i].tag = KM_TAG_INVALID;
+                    break;
+                case KM_BIGNUM:
+                case KM_BYTES:
+                    params[i] = keymaster_param_blob(tag, &keyParams[i].blob[0],
+                                                     keyParams[i].blob.size());
+                    break;
+                case KM_INVALID:
+                default:
+                    params[i].tag = KM_TAG_INVALID;
+                    /* just skip */
+                    break;
+            }
+        }
+    }
+    KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+        other.length = 0;
+        other.params = nullptr;
+    }
+    KmParamSet(const KmParamSet&) = delete;
+    ~KmParamSet() { delete[] params; }
+};
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
+    return result;
+}
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
+    return result;
+}
+
+inline hidl_vec<uint8_t> kmBuffer2hidlVec(const ::keymaster::Buffer& buf) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(buf.peek_read()), buf.available_read());
+    return result;
+}
+
+inline static hidl_vec<hidl_vec<uint8_t>> kmCertChain2Hidl(
+        const keymaster_cert_chain_t& cert_chain) {
+    hidl_vec<hidl_vec<uint8_t>> result;
+    if (!cert_chain.entry_count || !cert_chain.entries) return result;
+
+    result.resize(cert_chain.entry_count);
+    for (size_t i = 0; i < cert_chain.entry_count; ++i) {
+        result[i] = kmBlob2hidlVec(cert_chain.entries[i]);
+    }
+
+    return result;
+}
+
+static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
+    hidl_vec<KeyParameter> result;
+    if (set.length == 0 || set.params == nullptr) return result;
+
+    result.resize(set.length);
+    keymaster_key_param_t* params = set.params;
+    for (size_t i = 0; i < set.length; ++i) {
+        auto tag = params[i].tag;
+        result[i].tag = legacy_enum_conversion(tag);
+        switch (typeFromTag(tag)) {
+            case KM_ENUM:
+            case KM_ENUM_REP:
+                result[i].f.integer = params[i].enumerated;
+                break;
+            case KM_UINT:
+            case KM_UINT_REP:
+                result[i].f.integer = params[i].integer;
+                break;
+            case KM_ULONG:
+            case KM_ULONG_REP:
+                result[i].f.longInteger = params[i].long_integer;
+                break;
+            case KM_DATE:
+                result[i].f.dateTime = params[i].date_time;
+                break;
+            case KM_BOOL:
+                result[i].f.boolValue = params[i].boolean;
+                break;
+            case KM_BIGNUM:
+            case KM_BYTES:
+                result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
+                                             params[i].blob.data_length);
+                break;
+            case KM_INVALID:
+            default:
+                params[i].tag = KM_TAG_INVALID;
+                /* just skip */
+                break;
+        }
+    }
+    return result;
+}
+
+void addClientAndAppData(const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                         ::keymaster::AuthorizationSet* params) {
+    params->Clear();
+    if (clientId.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_ID, clientId.data(), clientId.size());
+    }
+    if (appData.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
+    }
+}
+
+}  // anonymous namespace
+
+TrustyKeymaster3Device::TrustyKeymaster3Device(TrustyKeymaster* impl) : impl_(impl) {}
+
+TrustyKeymaster3Device::~TrustyKeymaster3Device() {}
+
+Return<void> TrustyKeymaster3Device::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) {
+    _hidl_cb(true /* is_secure */, true /* supports_ec */,
+             true /* supports_symmetric_cryptography */, true /* supports_attestation */,
+             true /* supportsAllDigests */, "TrustyKeymaster", "Google");
+    return Void();
+}
+
+Return<ErrorCode> TrustyKeymaster3Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
+    if (data.size() == 0) return ErrorCode::OK;
+    AddEntropyRequest request;
+    request.random_data.Reinitialize(data.data(), data.size());
+
+    AddEntropyResponse response;
+    impl_->AddRngEntropy(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<void> TrustyKeymaster3Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
+                                                 generateKey_cb _hidl_cb) {
+    GenerateKeyRequest request;
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+
+    GenerateKeyResponse response;
+    impl_->GenerateKey(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+        resultCharacteristics.teeEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                                           const hidl_vec<uint8_t>& clientId,
+                                                           const hidl_vec<uint8_t>& appData,
+                                                           getKeyCharacteristics_cb _hidl_cb) {
+    GetKeyCharacteristicsRequest request;
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(clientId, appData, &request.additional_params);
+
+    GetKeyCharacteristicsResponse response;
+    impl_->GetKeyCharacteristics(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    if (response.error == KM_ERROR_OK) {
+        resultCharacteristics.teeEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultCharacteristics);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::importKey(const hidl_vec<KeyParameter>& params,
+                                               KeyFormat keyFormat,
+                                               const hidl_vec<uint8_t>& keyData,
+                                               importKey_cb _hidl_cb) {
+    ImportKeyRequest request;
+    request.key_description.Reinitialize(KmParamSet(params));
+    request.key_format = legacy_enum_conversion(keyFormat);
+    request.SetKeyMaterial(keyData.data(), keyData.size());
+
+    ImportKeyResponse response;
+    impl_->ImportKey(request, &response);
+
+    KeyCharacteristics resultCharacteristics;
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+        resultCharacteristics.teeEnforced = kmParamSet2Hidl(response.enforced);
+        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::exportKey(KeyFormat exportFormat,
+                                               const hidl_vec<uint8_t>& keyBlob,
+                                               const hidl_vec<uint8_t>& clientId,
+                                               const hidl_vec<uint8_t>& appData,
+                                               exportKey_cb _hidl_cb) {
+    ExportKeyRequest request;
+    request.key_format = legacy_enum_conversion(exportFormat);
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(clientId, appData, &request.additional_params);
+
+    ExportKeyResponse response;
+    impl_->ExportKey(request, &response);
+
+    hidl_vec<uint8_t> resultKeyBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultKeyBlob.setToExternal(response.key_data, response.key_data_length);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                                               const hidl_vec<KeyParameter>& attestParams,
+                                               attestKey_cb _hidl_cb) {
+    AttestKeyRequest request;
+    request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
+    request.attest_params.Reinitialize(KmParamSet(attestParams));
+
+    AttestKeyResponse response;
+    impl_->AttestKey(request, &response);
+
+    hidl_vec<hidl_vec<uint8_t>> resultCertChain;
+    if (response.error == KM_ERROR_OK) {
+        resultCertChain = kmCertChain2Hidl(response.certificate_chain);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultCertChain);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                                                const hidl_vec<KeyParameter>& upgradeParams,
+                                                upgradeKey_cb _hidl_cb) {
+    UpgradeKeyRequest request;
+    request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+    request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+    UpgradeKeyResponse response;
+    impl_->UpgradeKey(request, &response);
+
+    if (response.error == KM_ERROR_OK) {
+        _hidl_cb(ErrorCode::OK, kmBlob2hidlVec(response.upgraded_key));
+    } else {
+        _hidl_cb(legacy_enum_conversion(response.error), hidl_vec<uint8_t>());
+    }
+    return Void();
+}
+
+Return<ErrorCode> TrustyKeymaster3Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+    DeleteKeyRequest request;
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+    DeleteKeyResponse response;
+    impl_->DeleteKey(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> TrustyKeymaster3Device::deleteAllKeys() {
+    DeleteAllKeysRequest request;
+    DeleteAllKeysResponse response;
+    impl_->DeleteAllKeys(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> TrustyKeymaster3Device::destroyAttestationIds() {
+    return ErrorCode::UNIMPLEMENTED;
+}
+
+Return<void> TrustyKeymaster3Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                                           const hidl_vec<KeyParameter>& inParams,
+                                           begin_cb _hidl_cb) {
+    BeginOperationRequest request;
+    request.purpose = legacy_enum_conversion(purpose);
+    request.SetKeyMaterial(key.data(), key.size());
+    request.additional_params.Reinitialize(KmParamSet(inParams));
+
+    BeginOperationResponse response;
+    impl_->BeginOperation(request, &response);
+
+    hidl_vec<KeyParameter> resultParams;
+    if (response.error == KM_ERROR_OK) {
+        resultParams = kmParamSet2Hidl(response.output_params);
+    }
+
+    _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::update(uint64_t operationHandle,
+                                            const hidl_vec<KeyParameter>& inParams,
+                                            const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
+    UpdateOperationRequest request;
+    request.op_handle = operationHandle;
+    request.input.Reinitialize(input.data(), input.size());
+    request.additional_params.Reinitialize(KmParamSet(inParams));
+
+    UpdateOperationResponse response;
+    impl_->UpdateOperation(request, &response);
+
+    uint32_t resultConsumed = 0;
+    hidl_vec<KeyParameter> resultParams;
+    hidl_vec<uint8_t> resultBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultConsumed = response.input_consumed;
+        resultParams = kmParamSet2Hidl(response.output_params);
+        resultBlob = kmBuffer2hidlVec(response.output);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultConsumed, resultParams, resultBlob);
+    return Void();
+}
+
+Return<void> TrustyKeymaster3Device::finish(uint64_t operationHandle,
+                                            const hidl_vec<KeyParameter>& inParams,
+                                            const hidl_vec<uint8_t>& input,
+                                            const hidl_vec<uint8_t>& signature,
+                                            finish_cb _hidl_cb) {
+    FinishOperationRequest request;
+    request.op_handle = operationHandle;
+    request.input.Reinitialize(input.data(), input.size());
+    request.signature.Reinitialize(signature.data(), signature.size());
+    request.additional_params.Reinitialize(KmParamSet(inParams));
+
+    FinishOperationResponse response;
+    impl_->FinishOperation(request, &response);
+
+    hidl_vec<KeyParameter> resultParams;
+    hidl_vec<uint8_t> resultBlob;
+    if (response.error == KM_ERROR_OK) {
+        resultParams = kmParamSet2Hidl(response.output_params);
+        resultBlob = kmBuffer2hidlVec(response.output);
+    }
+    _hidl_cb(legacy_enum_conversion(response.error), resultParams, resultBlob);
+    return Void();
+}
+
+Return<ErrorCode> TrustyKeymaster3Device::abort(uint64_t operationHandle) {
+    AbortOperationRequest request;
+    request.op_handle = operationHandle;
+
+    AbortOperationResponse response;
+    impl_->AbortOperation(request, &response);
+
+    return legacy_enum_conversion(response.error);
+}
+}  // namespace keymaster
diff --git a/trusty/keymaster/3.0/android.hardware.keymaster@3.0-service.trusty.rc b/trusty/keymaster/3.0/android.hardware.keymaster@3.0-service.trusty.rc
new file mode 100644
index 0000000..e9d3054
--- /dev/null
+++ b/trusty/keymaster/3.0/android.hardware.keymaster@3.0-service.trusty.rc
@@ -0,0 +1,4 @@
+service vendor.keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service.trusty
+    class early_hal
+    user nobody
+    group system drmrpc
diff --git a/trusty/keymaster/3.0/service.cpp b/trusty/keymaster/3.0/service.cpp
new file mode 100644
index 0000000..0d8436e
--- /dev/null
+++ b/trusty/keymaster/3.0/service.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** Copyright 2018, 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 <android-base/logging.h>
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <hidl/HidlTransportSupport.h>
+#include <trusty_keymaster/TrustyKeymaster.h>
+#include <trusty_keymaster/TrustyKeymaster3Device.h>
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true);
+    auto trustyKeymaster = new keymaster::TrustyKeymaster();
+    int err = trustyKeymaster->Initialize();
+    if (err != 0) {
+        LOG(FATAL) << "Could not initialize TrustyKeymaster (" << err << ")";
+        return -1;
+    }
+
+    auto keymaster = new ::keymaster::TrustyKeymaster3Device(trustyKeymaster);
+
+    auto status = keymaster->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for Keymaster 3.0 (" << status << ")";
+        return -1;
+    }
+
+    android::hardware::joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 52a879e..819851f 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -77,3 +77,34 @@
     ],
     header_libs: ["libhardware_headers"],
 }
+
+cc_binary {
+    name: "android.hardware.keymaster@3.0-service.trusty",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["3.0/android.hardware.keymaster@3.0-service.trusty.rc"],
+    srcs: [
+        "3.0/service.cpp",
+        "3.0/TrustyKeymaster3Device.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+        "TrustyKeymaster.cpp",
+    ],
+
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libdl",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libtrusty",
+        "libkeymaster_messages",
+        "libkeymaster3device",
+        "android.hardware.keymaster@3.0"
+    ],
+}
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
new file mode 100644
index 0000000..7f5e87f
--- /dev/null
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2018 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 <cutils/log.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/keymaster_configuration.h>
+#include <trusty_keymaster/TrustyKeymaster.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+namespace keymaster {
+
+int TrustyKeymaster::Initialize() {
+    int err;
+
+    err = trusty_keymaster_connect();
+    if (err) {
+        ALOGE("Failed to connect to trusty keymaster %d", err);
+        return err;
+    }
+
+    ConfigureRequest req;
+    req.os_version = GetOsVersion();
+    req.os_patchlevel = GetOsPatchlevel();
+
+    ConfigureResponse rsp;
+    Configure(req, &rsp);
+
+    if (rsp.error != KM_ERROR_OK) {
+        ALOGE("Failed to configure keymaster %d", rsp.error);
+        return -1;
+    }
+
+    return 0;
+}
+
+TrustyKeymaster::TrustyKeymaster() {}
+
+TrustyKeymaster::~TrustyKeymaster() {
+    trusty_keymaster_disconnect();
+}
+
+static void ForwardCommand(enum keymaster_command command, const Serializable& req,
+                           KeymasterResponse* rsp) {
+    keymaster_error_t err;
+    err = trusty_keymaster_send(command, req, rsp);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Failed to send cmd %d err: %d", command, err);
+        rsp->error = err;
+    }
+}
+
+void TrustyKeymaster::GetVersion(const GetVersionRequest& request, GetVersionResponse* response) {
+    ForwardCommand(KM_GET_VERSION, request, response);
+}
+
+void TrustyKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                                          SupportedAlgorithmsResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_ALGORITHMS, request, response);
+}
+
+void TrustyKeymaster::SupportedBlockModes(const SupportedBlockModesRequest& request,
+                                          SupportedBlockModesResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_BLOCK_MODES, request, response);
+}
+
+void TrustyKeymaster::SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                                            SupportedPaddingModesResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_PADDING_MODES, request, response);
+}
+
+void TrustyKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+                                       SupportedDigestsResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_DIGESTS, request, response);
+}
+
+void TrustyKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                             SupportedImportFormatsResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_IMPORT_FORMATS, request, response);
+}
+
+void TrustyKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                             SupportedExportFormatsResponse* response) {
+    ForwardCommand(KM_GET_SUPPORTED_EXPORT_FORMATS, request, response);
+}
+
+void TrustyKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+                                    AddEntropyResponse* response) {
+    ForwardCommand(KM_ADD_RNG_ENTROPY, request, response);
+}
+
+void TrustyKeymaster::Configure(const ConfigureRequest& request, ConfigureResponse* response) {
+    ForwardCommand(KM_CONFIGURE, request, response);
+}
+
+void TrustyKeymaster::GenerateKey(const GenerateKeyRequest& request,
+                                  GenerateKeyResponse* response) {
+    GenerateKeyRequest datedRequest(request.message_version);
+    datedRequest.key_description = request.key_description;
+
+    if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+        datedRequest.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+    }
+
+    ForwardCommand(KM_GENERATE_KEY, datedRequest, response);
+}
+
+void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                                            GetKeyCharacteristicsResponse* response) {
+    ForwardCommand(KM_GET_KEY_CHARACTERISTICS, request, response);
+}
+
+void TrustyKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
+    ForwardCommand(KM_IMPORT_KEY, request, response);
+}
+
+void TrustyKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                                       ImportWrappedKeyResponse* response) {
+    ForwardCommand(KM_IMPORT_WRAPPED_KEY, request, response);
+}
+
+void TrustyKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
+    ForwardCommand(KM_EXPORT_KEY, request, response);
+}
+
+void TrustyKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
+    ForwardCommand(KM_ATTEST_KEY, request, response);
+}
+
+void TrustyKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
+    ForwardCommand(KM_UPGRADE_KEY, request, response);
+}
+
+void TrustyKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
+    ForwardCommand(KM_DELETE_KEY, request, response);
+}
+
+void TrustyKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request,
+                                    DeleteAllKeysResponse* response) {
+    ForwardCommand(KM_DELETE_ALL_KEYS, request, response);
+}
+
+void TrustyKeymaster::BeginOperation(const BeginOperationRequest& request,
+                                     BeginOperationResponse* response) {
+    ForwardCommand(KM_BEGIN_OPERATION, request, response);
+}
+
+void TrustyKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+                                      UpdateOperationResponse* response) {
+    ForwardCommand(KM_UPDATE_OPERATION, request, response);
+}
+
+void TrustyKeymaster::FinishOperation(const FinishOperationRequest& request,
+                                      FinishOperationResponse* response) {
+    ForwardCommand(KM_FINISH_OPERATION, request, response);
+}
+
+void TrustyKeymaster::AbortOperation(const AbortOperationRequest& request,
+                                     AbortOperationResponse* response) {
+    ForwardCommand(KM_ABORT_OPERATION, request, response);
+}
+
+/* Methods for Keymaster 4.0 functionality -- not yet implemented */
+GetHmacSharingParametersResponse TrustyKeymaster::GetHmacSharingParameters() {
+    GetHmacSharingParametersResponse response;
+    response.error = KM_ERROR_UNIMPLEMENTED;
+    return response;
+}
+
+ComputeSharedHmacResponse TrustyKeymaster::ComputeSharedHmac(
+        const ComputeSharedHmacRequest& /* request */) {
+    ComputeSharedHmacResponse response;
+    response.error = KM_ERROR_UNIMPLEMENTED;
+    return response;
+}
+
+VerifyAuthorizationResponse TrustyKeymaster::VerifyAuthorization(
+        const VerifyAuthorizationRequest& /* request */) {
+    VerifyAuthorizationResponse response;
+    response.error = KM_ERROR_UNIMPLEMENTED;
+    return response;
+}
+
+}  // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
new file mode 100644
index 0000000..030b645
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TRUSTY_KEYMASTER_H_
+#define TRUSTY_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+
+namespace keymaster {
+
+class TrustyKeymaster {
+  public:
+    TrustyKeymaster();
+    ~TrustyKeymaster();
+    int Initialize();
+    void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
+    void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                             SupportedAlgorithmsResponse* response);
+    void SupportedBlockModes(const SupportedBlockModesRequest& request,
+                             SupportedBlockModesResponse* response);
+    void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                               SupportedPaddingModesResponse* response);
+    void SupportedDigests(const SupportedDigestsRequest& request,
+                          SupportedDigestsResponse* response);
+    void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                SupportedImportFormatsResponse* response);
+    void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                SupportedExportFormatsResponse* response);
+    void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
+    void Configure(const ConfigureRequest& request, ConfigureResponse* response);
+    void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+    void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                               GetKeyCharacteristicsResponse* response);
+    void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+    void ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                          ImportWrappedKeyResponse* response);
+    void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+    void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+    void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
+    void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+    void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+    void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
+    void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
+    void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
+    void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
+    GetHmacSharingParametersResponse GetHmacSharingParameters();
+    ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
+    VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
+};
+
+}  // namespace keymaster
+
+#endif  // TRUSTY_KEYMASTER_H_
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster3Device.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster3Device.h
new file mode 100644
index 0000000..6fc79ce
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster3Device.h
@@ -0,0 +1,84 @@
+/*
+ **
+ ** Copyright 2018, 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 HIDL_android_hardware_keymaster_V3_0_TrustyKeymaster3Device_H_
+#define HIDL_android_hardware_keymaster_V3_0_TrustyKeymaster3Device_H_
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace keymaster {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::keymaster::V3_0::ErrorCode;
+using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V3_0::KeyFormat;
+using ::android::hardware::keymaster::V3_0::KeyParameter;
+using ::android::hardware::keymaster::V3_0::KeyPurpose;
+
+class TrustyKeymaster3Device : public IKeymasterDevice {
+  public:
+    TrustyKeymaster3Device(TrustyKeymaster* impl);
+    virtual ~TrustyKeymaster3Device();
+
+    Return<void> getHardwareFeatures(getHardwareFeatures_cb _hidl_cb);
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override;
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override;
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override;
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override;
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override;
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+    Return<ErrorCode> deleteAllKeys() override;
+    Return<ErrorCode> destroyAttestationIds() override;
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) override;
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, update_cb _hidl_cb) override;
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        finish_cb _hidl_cb) override;
+    Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+  private:
+    std::unique_ptr<TrustyKeymaster> impl_;
+};
+
+}  // namespace keymaster
+
+#endif  // HIDL_android_hardware_keymaster_V3_0_TrustyKeymaster3Device_H_
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index d63757b..13e6725 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -46,6 +46,13 @@
     KM_ATTEST_KEY                   = (16 << KEYMASTER_REQ_SHIFT),
     KM_UPGRADE_KEY                  = (17 << KEYMASTER_REQ_SHIFT),
     KM_CONFIGURE                    = (18 << KEYMASTER_REQ_SHIFT),
+    KM_GET_HMAC_SHARING_PARAMETERS  = (19 << KEYMASTER_REQ_SHIFT),
+    KM_COMPUTE_SHARED_HMAC          = (20 << KEYMASTER_REQ_SHIFT),
+    KM_VERIFY_AUTHORIZATION         = (21 << KEYMASTER_REQ_SHIFT),
+    KM_DELETE_KEY                   = (22 << KEYMASTER_REQ_SHIFT),
+    KM_DELETE_ALL_KEYS              = (23 << KEYMASTER_REQ_SHIFT),
+    KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
+    KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
index 9c3a7df..0a0ecec 100644
--- a/trusty/trusty-base.mk
+++ b/trusty/trusty-base.mk
@@ -20,7 +20,7 @@
 #
 
 PRODUCT_PACKAGES += \
-	keystore.trusty \
+	android.hardware.keymaster@3.0-service.trusty \
 	gatekeeper.trusty
 
 PRODUCT_PROPERTY_OVERRIDES += \