Merge "Add boot animation progress system property."
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d7067ca..2f1b693 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -370,14 +370,12 @@
           return "SEGV_ADIDERR";
         case SEGV_ADIPERR:
           return "SEGV_ADIPERR";
-#if defined(ANDROID_EXPERIMENTAL_MTE)
         case SEGV_MTEAERR:
           return "SEGV_MTEAERR";
         case SEGV_MTESERR:
           return "SEGV_MTESERR";
-#endif
       }
-      static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
+      static_assert(NSIGSEGV == SEGV_MTESERR, "missing SEGV_* si_code");
       break;
     case SIGSYS:
       switch (si->si_code) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 8addcb6..458a7a1 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -168,6 +168,19 @@
     return exec_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
 }
 
+enum {
+    // clang-format off
+    FSCK_SUCCESS                 = 0,
+    FSCK_ERROR_CORRECTED         = 1 << 0,
+    FSCK_SYSTEM_SHOULD_REBOOT    = 1 << 1,
+    FSCK_ERRORS_LEFT_UNCORRECTED = 1 << 2,
+    FSCK_OPERATIONAL_ERROR       = 1 << 3,
+    FSCK_USAGE_OR_SYNTAX_ERROR   = 1 << 4,
+    FSCK_USER_CANCELLED          = 1 << 5,
+    FSCK_SHARED_LIB_ERROR        = 1 << 7,
+    // clang-format on
+};
+
 static int generate_f2fs_image(const char* fileName, long long partSize,
                                const std::string& initial_dir, unsigned /* unused */,
                                unsigned /* unused */, const unsigned fsOptions) {
@@ -216,7 +229,11 @@
     std::vector<const char*> sload_args = {sload_path.c_str(), "-S",
                                        "-f", initial_dir.c_str(), fileName, nullptr};
 
-    return exec_cmd(sload_args[0], sload_args.data(), nullptr);
+    ret = exec_cmd(sload_args[0], sload_args.data(), nullptr);
+    if (ret != 0 && ret != FSCK_ERROR_CORRECTED) {
+        return -1;
+    }
+    return 0;
 }
 
 static const struct fs_generator {
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index ca782b9..94b2f8c 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -8,8 +8,8 @@
 system partition as read-write and then add or modify any number of files
 without reflashing the system image, which is efficient for a development cycle.
 
-Limited memory systems use read-only types of file systems or logical resizable
-Android partitions (LRAPs). These file systems land system partition images
+Limited memory systems use read-only types of file systems or dynamic
+Android partitions (DAPs). These file systems land system partition images
 right-sized, and have been deduped at the block level to compress the content.
 This means that a remount either isn’t possible, or isn't useful because of
 space limitations or support logistics.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4c9fd9b..2876094 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1324,6 +1324,7 @@
     int error_count = 0;
     CheckpointManager checkpoint_manager;
     AvbUniquePtr avb_handle(nullptr);
+    bool wiped = false;
 
     bool userdata_mounted = false;
     if (fstab->empty()) {
@@ -1457,7 +1458,8 @@
                 encryptable = status;
                 if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
                     if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
-                                   attempted_entry.mount_point},
+                                   attempted_entry.mount_point, wiped ? "true" : "false",
+                                   attempted_entry.fs_type},
                                   nullptr)) {
                         LERROR << "Encryption failed";
                         set_type_property(encryptable);
@@ -1474,7 +1476,7 @@
         }
 
         // Mounting failed, understand why and retry.
-        bool wiped = partition_wiped(current_entry.blk_device.c_str());
+        wiped = partition_wiped(current_entry.blk_device.c_str());
         bool crypt_footer = false;
         if (mount_errno != EBUSY && mount_errno != EACCES &&
             current_entry.fs_mgr_flags.formattable && wiped) {
@@ -1499,6 +1501,27 @@
             } else if (current_entry.is_encryptable() && current_entry.key_loc == KEY_IN_FOOTER) {
                 crypt_footer = true;
             }
+
+            // EncryptInplace will be used when vdc gives an error or needs to format partitions
+            // other than /data
+            if (should_use_metadata_encryption(current_entry) &&
+                current_entry.mount_point == "/data") {
+
+                // vdc->Format requires "ro.crypto.type" to set an encryption flag
+                encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
+                set_type_property(encryptable);
+
+                if (!call_vdc({"cryptfs", "encryptFstab", current_entry.blk_device,
+                               current_entry.mount_point, "true" /* shouldFormat */,
+                               current_entry.fs_type},
+                              nullptr)) {
+                    LERROR << "Encryption failed";
+                } else {
+                    userdata_mounted = true;
+                    continue;
+                }
+            }
+
             if (fs_mgr_do_format(current_entry, crypt_footer) == 0) {
                 // Let's replay the mount actions.
                 i = top_idx - 1;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index e32fde0..d36a7f0 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -24,6 +24,7 @@
     ],
     shared_libs: [
         "libbase",
+        "libchrome",
         "libcutils",
         "liblog",
     ],
@@ -44,7 +45,6 @@
         "libz",
     ],
     header_libs: [
-        "libchrome",
         "libfiemap_headers",
         "libstorage_literals_headers",
         "libupdate_engine_headers",
@@ -351,6 +351,7 @@
     static_libs: [
         "libbase",
         "libbrotli",
+        "libchrome",
         "libcrypto_static",
         "libcutils",
         "libext2_uuid",
@@ -367,7 +368,6 @@
         "libz",
     ],
     header_libs: [
-        "libchrome",
         "libfiemap_headers",
         "libstorage_literals_headers",
         "libupdate_engine_headers",
@@ -423,10 +423,11 @@
         "libbase",
         "libbrotli",
         "libcutils_sockets",
-        "liblog",
         "libdm",
-        "libz",
+        "libgflags",
+        "liblog",
         "libsnapshot_cow",
+        "libz",
     ],
 }
 
@@ -440,6 +441,7 @@
     system_shared_libs: [],
     ramdisk_available: true,
     vendor_ramdisk_available: true,
+    recovery_available: true,
 }
 
 cc_test {
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 35020f4..defe8d4 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -171,6 +171,70 @@
     ASSERT_TRUE(iter->Done());
 }
 
+TEST_F(CowTest, ClusterCompressGz) {
+    CowOptions options;
+    options.compression = "gz";
+    options.cluster_ops = 2;
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+
+    std::string data2 = "More data!";
+    data2.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer.AddRawBlocks(51, data2.data(), data2.size()));
+
+    ASSERT_TRUE(writer.Finalize());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+
+    StringSink sink;
+
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_EQ(op->compression, kCowCompressGz);
+    ASSERT_EQ(op->data_length, 56);  // compressed!
+    ASSERT_EQ(op->new_block, 50);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    ASSERT_EQ(op->type, kCowClusterOp);
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    sink.Reset();
+    ASSERT_EQ(op->compression, kCowCompressGz);
+    ASSERT_EQ(op->data_length, 41);  // compressed!
+    ASSERT_EQ(op->new_block, 51);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data2);
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    ASSERT_EQ(op->type, kCowClusterOp);
+
+    iter->Next();
+    ASSERT_TRUE(iter->Done());
+}
+
 TEST_F(CowTest, CompressTwoBlocks) {
     CowOptions options;
     options.compression = "gz";
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 16d9313..ed67a1c 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -169,7 +169,7 @@
     ASSERT_GE(pid, 0);
     if (pid == 0) {
         std::string arg0 = "/system/bin/snapuserd";
-        std::string arg1 = kSnapuserdSocketTest;
+        std::string arg1 = "-socket="s + kSnapuserdSocketTest;
         char* const argv[] = {arg0.data(), arg1.data(), nullptr};
         ASSERT_GE(execv(arg0.c_str(), argv), 0);
     } else {
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 8535252..c1a5f32 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -433,11 +433,6 @@
 }
 
 bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t size) {
-    // If there isn't room for this op and the cluster end op, end the current cluster
-    if (cluster_size_ && op.type != kCowClusterOp &&
-        cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
-        if (!EmitCluster()) return false;
-    }
     if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
         PLOG(ERROR) << "lseek failed for writing operation.";
         return false;
@@ -449,6 +444,11 @@
         if (!WriteRawData(data, size)) return false;
     }
     AddOperation(op);
+    // If there isn't room for another op and the cluster end op, end the current cluster
+    if (cluster_size_ && op.type != kCowClusterOp &&
+        cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
+        if (!EmitCluster()) return false;
+    }
     return true;
 }
 
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 5ad61f3..453b5c6 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -36,10 +36,30 @@
 }
 
 static void usage(void) {
-    LOG(ERROR) << "Usage: inspect_cow [-s] <COW_FILE>";
+    LOG(ERROR) << "Usage: inspect_cow [-sd] <COW_FILE>";
+    LOG(ERROR) << "\t -s Run Silent";
+    LOG(ERROR) << "\t -d Attempt to decompress\n";
 }
 
-static bool Inspect(const std::string& path, bool silent) {
+// Sink that always appends to the end of a string.
+class StringSink : public IByteSink {
+  public:
+    void* GetBuffer(size_t requested, size_t* actual) override {
+        size_t old_size = stream_.size();
+        stream_.resize(old_size + requested, '\0');
+        *actual = requested;
+        return stream_.data() + old_size;
+    }
+    bool ReturnData(void*, size_t) override { return true; }
+    void Reset() { stream_.clear(); }
+
+    std::string& stream() { return stream_; }
+
+  private:
+    std::string stream_;
+};
+
+static bool Inspect(const std::string& path, bool silent, bool decompress) {
     android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
     if (fd < 0) {
         PLOG(ERROR) << "open failed: " << path;
@@ -76,15 +96,25 @@
     }
 
     auto iter = reader.GetOpIter();
+    StringSink sink;
+    bool success = true;
     while (!iter->Done()) {
         const CowOperation& op = iter->Get();
 
         if (!silent) std::cout << op << "\n";
 
+        if (decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
+            if (!reader.ReadData(op, &sink)) {
+                std::cerr << "Failed to decompress for :" << op << "\n";
+                success = false;
+            }
+            sink.Reset();
+        }
+
         iter->Next();
     }
 
-    return true;
+    return success;
 }
 
 }  // namespace snapshot
@@ -93,11 +123,15 @@
 int main(int argc, char** argv) {
     int ch;
     bool silent = false;
-    while ((ch = getopt(argc, argv, "s")) != -1) {
+    bool decompress = false;
+    while ((ch = getopt(argc, argv, "sd")) != -1) {
         switch (ch) {
             case 's':
                 silent = true;
                 break;
+            case 'd':
+                decompress = true;
+                break;
             default:
                 android::snapshot::usage();
         }
@@ -109,7 +143,7 @@
         return 1;
     }
 
-    if (!android::snapshot::Inspect(argv[optind], silent)) {
+    if (!android::snapshot::Inspect(argv[optind], silent, decompress)) {
         return 1;
     }
     return 0;
diff --git a/fs_mgr/libsnapshot/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
index 08b5bff..7fa01b7 100644
--- a/fs_mgr/libsnapshot/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
@@ -17,18 +17,41 @@
 #include "snapuserd_daemon.h"
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gflags/gflags.h>
 #include <libsnapshot/snapuserd_client.h>
 
 #include "snapuserd_server.h"
 
+DEFINE_string(socket, android::snapshot::kSnapuserdSocket, "Named socket or socket path.");
+DEFINE_bool(no_socket, false,
+            "If true, no socket is used. Each additional argument is an INIT message.");
+
 namespace android {
 namespace snapshot {
 
-bool Daemon::StartServer(const std::string& socketname) {
-    if (!server_.Start(socketname)) {
-        LOG(ERROR) << "Snapuserd daemon failed to start...";
-        exit(EXIT_FAILURE);
+bool Daemon::StartServer(int argc, char** argv) {
+    int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+    if (!FLAGS_no_socket) {
+        return server_.Start(FLAGS_socket);
     }
+
+    for (int i = arg_start; i < argc; i++) {
+        auto parts = android::base::Split(argv[i], ",");
+        if (parts.size() != 3) {
+            LOG(ERROR) << "Malformed message, expected three sub-arguments.";
+            return false;
+        }
+        auto handler = server_.AddHandler(parts[0], parts[1], parts[2]);
+        if (!handler || !server_.StartHandler(handler)) {
+            return false;
+        }
+    }
+
+    // Skip the accept() call to avoid spurious log spam. The server will still
+    // run until all handlers have completed.
+    server_.SetTerminating();
     return true;
 }
 
@@ -94,16 +117,15 @@
 }  // namespace snapshot
 }  // namespace android
 
-int main([[maybe_unused]] int argc, char** argv) {
+int main(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::KernelLogger);
 
     android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
 
-    std::string socket = android::snapshot::kSnapuserdSocket;
-    if (argc >= 2) {
-        socket = argv[1];
+    if (!daemon.StartServer(argc, argv)) {
+        LOG(ERROR) << "Snapuserd daemon failed to start.";
+        exit(EXIT_FAILURE);
     }
-    daemon.StartServer(socket);
     daemon.Run();
 
     return 0;
diff --git a/fs_mgr/libsnapshot/snapuserd_daemon.h b/fs_mgr/libsnapshot/snapuserd_daemon.h
index fc107a3..f8afac5 100644
--- a/fs_mgr/libsnapshot/snapuserd_daemon.h
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.h
@@ -16,6 +16,9 @@
 
 #include <poll.h>
 
+#include <string>
+#include <vector>
+
 #include "snapuserd_server.h"
 
 namespace android {
@@ -32,7 +35,7 @@
         return instance;
     }
 
-    bool StartServer(const std::string& socketname);
+    bool StartServer(int argc, char** argv);
     void Run();
     void Interrupt();
 
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 9f460c1..8351155 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -116,7 +116,7 @@
     switch (op) {
         case DaemonOperations::INIT: {
             // Message format:
-            // init,<misc_name>,<cow_device_path>,<control_device>
+            // init,<misc_name>,<cow_device_path>,<backing_device>
             //
             // Reads the metadata and send the number of sectors
             if (out.size() != 4) {
@@ -124,24 +124,12 @@
                 return Sendmsg(fd, "fail");
             }
 
-            auto snapuserd = std::make_unique<Snapuserd>(out[1], out[2], out[3]);
-            if (!snapuserd->InitCowDevice()) {
-                LOG(ERROR) << "Failed to initialize Snapuserd";
+            auto handler = AddHandler(out[1], out[2], out[3]);
+            if (!handler) {
                 return Sendmsg(fd, "fail");
             }
 
-            std::string retval = "success," + std::to_string(snapuserd->GetNumSectors());
-
-            auto handler = std::make_unique<DmUserHandler>(std::move(snapuserd));
-            {
-                std::lock_guard<std::mutex> lock(lock_);
-                if (FindHandler(&lock, out[1]) != dm_users_.end()) {
-                    LOG(ERROR) << "Handler already exists: " << out[1];
-                    return Sendmsg(fd, "fail");
-                }
-                dm_users_.push_back(std::move(handler));
-            }
-
+            auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
             return Sendmsg(fd, retval);
         }
         case DaemonOperations::START: {
@@ -164,11 +152,9 @@
                 LOG(ERROR) << "Tried to re-attach control device: " << out[1];
                 return Sendmsg(fd, "fail");
             }
-            if (!((*iter)->snapuserd()->InitBackingAndControlDevice())) {
-                LOG(ERROR) << "Failed to initialize control device: " << out[1];
+            if (!StartHandler(*iter)) {
                 return Sendmsg(fd, "fail");
             }
-            (*iter)->thread() = std::thread(std::bind(&SnapuserdServer::RunThread, this, *iter));
             return Sendmsg(fd, "success");
         }
         case DaemonOperations::STOP: {
@@ -340,6 +326,39 @@
     SetTerminating();
 }
 
+std::shared_ptr<DmUserHandler> SnapuserdServer::AddHandler(const std::string& misc_name,
+                                                           const std::string& cow_device_path,
+                                                           const std::string& backing_device) {
+    auto snapuserd = std::make_unique<Snapuserd>(misc_name, cow_device_path, backing_device);
+    if (!snapuserd->InitCowDevice()) {
+        LOG(ERROR) << "Failed to initialize Snapuserd";
+        return nullptr;
+    }
+
+    auto handler = std::make_shared<DmUserHandler>(std::move(snapuserd));
+    {
+        std::lock_guard<std::mutex> lock(lock_);
+        if (FindHandler(&lock, misc_name) != dm_users_.end()) {
+            LOG(ERROR) << "Handler already exists: " << misc_name;
+            return nullptr;
+        }
+        dm_users_.push_back(handler);
+    }
+    return handler;
+}
+
+bool SnapuserdServer::StartHandler(const std::shared_ptr<DmUserHandler>& handler) {
+    CHECK(!handler->snapuserd()->IsAttached());
+
+    if (!handler->snapuserd()->InitBackingAndControlDevice()) {
+        LOG(ERROR) << "Failed to initialize control device: " << handler->GetMiscName();
+        return false;
+    }
+
+    handler->thread() = std::thread(std::bind(&SnapuserdServer::RunThread, this, handler));
+    return true;
+}
+
 auto SnapuserdServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
                                   const std::string& misc_name) -> HandlerList::iterator {
     CHECK(proof_of_lock);
diff --git a/fs_mgr/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd_server.h
index 6e897aa..01e2365 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd_server.h
@@ -103,7 +103,6 @@
     std::string GetDaemonStatus();
     void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
 
-    void SetTerminating() { terminating_ = true; }
     bool IsTerminating() { return terminating_; }
 
     void RunThread(std::shared_ptr<DmUserHandler> handler);
@@ -120,6 +119,13 @@
     bool Start(const std::string& socketname);
     bool Run();
     void Interrupt();
+
+    std::shared_ptr<DmUserHandler> AddHandler(const std::string& misc_name,
+                                              const std::string& cow_device_path,
+                                              const std::string& backing_device);
+    bool StartHandler(const std::shared_ptr<DmUserHandler>& handler);
+
+    void SetTerminating() { terminating_ = true; }
 };
 
 }  // namespace snapshot
diff --git a/init/firmware_handler_test.cpp b/init/firmware_handler_test.cpp
index 7bb603c..5124a6f 100644
--- a/init/firmware_handler_test.cpp
+++ b/init/firmware_handler_test.cpp
@@ -79,6 +79,8 @@
 }
 
 int HandleAbort(int argc, char** argv) {
+    // Since this is an expected failure, disable debuggerd to not generate a tombstone.
+    signal(SIGABRT, SIG_DFL);
     abort();
     return 0;
 }
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 59cc140..ec48cde 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -115,22 +115,29 @@
         return {};
     }
     dirent* entry;
+    std::vector<std::string> entries;
+
     while ((entry = readdir(dir.get())) != nullptr) {
         if (entry->d_name[0] == '.') continue;
         if (entry->d_type == DT_DIR) {
-            const std::string apex_path = from_dir + "/" + entry->d_name;
-            const auto apex_manifest = GetApexManifest(apex_path);
-            if (!apex_manifest.ok()) {
-                LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_manifest.error();
-                continue;
-            }
-            const std::string mount_path = to_dir + "/" + apex_manifest->name();
-            if (auto result = MountDir(apex_path, mount_path); !result.ok()) {
-                return result;
-            }
-            on_activate(apex_path, *apex_manifest);
+            entries.push_back(entry->d_name);
         }
     }
+
+    std::sort(entries.begin(), entries.end());
+    for (const auto& name : entries) {
+        const std::string apex_path = from_dir + "/" + name;
+        const auto apex_manifest = GetApexManifest(apex_path);
+        if (!apex_manifest.ok()) {
+            LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_manifest.error();
+            continue;
+        }
+        const std::string mount_path = to_dir + "/" + apex_manifest->name();
+        if (auto result = MountDir(apex_path, mount_path); !result.ok()) {
+            return result;
+        }
+        on_activate(apex_path, *apex_manifest);
+    }
     return {};
 }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index f4e12b9..e3aaa38 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -854,7 +854,7 @@
         sub_reason = "apex";
         return result;
     }
-    if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP)) {
+    if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP).ok()) {
         sub_reason = "ns_switch";
         return Error() << "Failed to switch to bootstrap namespace";
     }
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index ee765a7..da1f455 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -202,6 +202,8 @@
 
     // For RecoverAfterAbort
     auto do_cause_log_fatal = [](const BuiltinArguments& args) -> Result<void> {
+        // Since this is an expected failure, disable debuggerd to not generate a tombstone.
+        signal(SIGABRT, SIG_DFL);
         return Error() << std::string(4097, 'f');
     };
     auto do_generate_sane_error = [](const BuiltinArguments& args) -> Result<void> {
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
index 98e3665..ea98ae2 100644
--- a/libappfuse/tests/FuseAppLoopTest.cc
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -167,7 +167,7 @@
   EXPECT_EQ(0u, response_.entry_out.attr.gid);
   EXPECT_EQ(0u, response_.entry_out.attr.rdev);
   EXPECT_EQ(0u, response_.entry_out.attr.blksize);
-  EXPECT_EQ(0u, response_.entry_out.attr.padding);
+  EXPECT_EQ(0u, response_.entry_out.attr.flags);
 }
 
 TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
@@ -226,7 +226,7 @@
   EXPECT_EQ(0u, response_.attr_out.attr.gid);
   EXPECT_EQ(0u, response_.attr_out.attr.rdev);
   EXPECT_EQ(0u, response_.attr_out.attr.blksize);
-  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+  EXPECT_EQ(0u, response_.attr_out.attr.flags);
 }
 
 TEST_F(FuseAppLoopTest, GetAttr_Root) {
@@ -259,7 +259,7 @@
   EXPECT_EQ(0u, response_.attr_out.attr.gid);
   EXPECT_EQ(0u, response_.attr_out.attr.rdev);
   EXPECT_EQ(0u, response_.attr_out.attr.blksize);
-  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+  EXPECT_EQ(0u, response_.attr_out.attr.flags);
 }
 
 TEST_F(FuseAppLoopTest, Open) {
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp
index 65371fa..eec2415 100644
--- a/libnetutils/Android.bp
+++ b/libnetutils/Android.bp
@@ -21,6 +21,11 @@
     cflags: ["-Werror"],
 
     export_include_dirs: ["include"],
+    // TODO: remove connectivity module dependency, or have this lib build against the ndk
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
 
 cc_library_static {
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 792af6f..5b7a28a 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -42,7 +42,7 @@
     "Controllers": [
       {
         "Controller": "freezer",
-        "Path": ".",
+        "Path": "freezer",
         "Mode": "0755",
         "UID": "system",
         "GID": "system"
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 628098b..5b57bdd 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -46,7 +46,7 @@
       "File": "cpu.uclamp.latency_sensitive"
     },
     {
-      "Name": "Freezer",
+      "Name": "FreezerState",
       "Controller": "freezer",
       "File": "cgroup.freeze"
     }
@@ -70,11 +70,11 @@
       "Name": "Frozen",
       "Actions": [
         {
-          "Name": "SetAttribute",
+          "Name": "JoinCgroup",
           "Params":
           {
-            "Name": "Freezer",
-            "Value": "1"
+            "Controller": "freezer",
+            "Path": ""
           }
         }
       ]
@@ -83,11 +83,11 @@
       "Name": "Unfrozen",
       "Actions": [
         {
-          "Name": "SetAttribute",
+          "Name": "JoinCgroup",
           "Params":
           {
-            "Name": "Freezer",
-            "Value": "0"
+            "Controller": "freezer",
+            "Path": "../"
           }
         }
       ]
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 860b9ae..5b6ce41 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -28,6 +28,10 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
 cc_binary {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 17d71f7..73d1101 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -69,7 +69,7 @@
 
 EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS :=
 ifeq ($(CLANG_COVERAGE),true)
-  EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%p-%m.profraw
+  EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw
 endif
 
 # Put it here instead of in init.rc module definition,
diff --git a/rootdir/avb/Android.bp b/rootdir/avb/Android.bp
index 85d2786..8c7caf3 100644
--- a/rootdir/avb/Android.bp
+++ b/rootdir/avb/Android.bp
@@ -18,3 +18,10 @@
         "s-gsi.avbpubkey",
     ],
 }
+
+filegroup {
+    name: "qcar-gsi_avbpubkey",
+    srcs: [
+        "qcar-gsi.avbpubkey",
+    ],
+}
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index c8fc1d6..f71f205 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -80,4 +80,15 @@
 
 include $(BUILD_PREBUILT)
 
+#######################################
+# qcar-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := qcar-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(my_gsi_avb_keys_path)
+
+include $(BUILD_PREBUILT)
+
 my_gsi_avb_keys_path :=
diff --git a/rootdir/avb/qcar-gsi.avbpubkey b/rootdir/avb/qcar-gsi.avbpubkey
new file mode 100644
index 0000000..ce56646
--- /dev/null
+++ b/rootdir/avb/qcar-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a233fbe..b305eb2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -635,20 +635,21 @@
     mkdir /data/bootchart 0755 shell shell encryption=Require
     bootchart start
 
-    # Make sure that apexd is started in the default namespace
-    enter_default_mount_ns
-
     mkdir /data/vendor 0771 root root encryption=Require
     mkdir /data/vendor_ce 0771 root root encryption=None
     mkdir /data/vendor_de 0771 root root encryption=None
     mkdir /data/vendor/hardware 0771 root root
 
     # Start tombstoned early to be able to store tombstones.
+    mkdir /data/anr 0775 system system encryption=Require
     mkdir /data/tombstones 0771 system system encryption=Require
     mkdir /data/vendor/tombstones 0771 root root
     mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
     start tombstoned
 
+    # Make sure that apexd is started in the default namespace
+    enter_default_mount_ns
+
     # /data/apex is now available. Start apexd to scan and activate APEXes.
     mkdir /data/apex 0755 root system encryption=None
     mkdir /data/apex/active 0755 root system
@@ -781,8 +782,6 @@
     # the following directory.
     mkdir /data/mediadrm 0770 mediadrm mediadrm encryption=Require
 
-    mkdir /data/anr 0775 system system encryption=Require
-
     # NFC: create data/nfc for nv storage
     mkdir /data/nfc 0770 nfc nfc encryption=Require
     mkdir /data/nfc/param 0770 nfc nfc
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 1147315..a1e9b12 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,6 +1,6 @@
 import /vendor/ueventd.rc
 import /odm/ueventd.rc
-import /ueventd.{ro.hardware}.rc
+import /ueventd.${ro.hardware}.rc
 
 firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
 uevent_socket_rcvbuf_size 16M
diff --git a/trusty/coverage/Android.bp b/trusty/coverage/Android.bp
index a4adf81..6038d44 100644
--- a/trusty/coverage/Android.bp
+++ b/trusty/coverage/Android.bp
@@ -14,6 +14,7 @@
 
 cc_library {
     name: "libtrusty_coverage",
+    vendor_available: true,
     srcs: [
         "coverage.cpp",
     ],
@@ -21,8 +22,9 @@
         "include",
     ],
     static_libs: [
-        "libtrusty_test",
+        "libtrusty",
     ],
+
     shared_libs: [
         "libbase",
         "liblog",
@@ -36,10 +38,11 @@
     ],
     static_libs: [
         "libtrusty_coverage",
-        "libtrusty_test",
+        "libtrusty",
     ],
     shared_libs: [
         "libbase",
         "liblog",
     ],
+    require_root: true,
 }
diff --git a/trusty/coverage/coverage.cpp b/trusty/coverage/coverage.cpp
index 1162f42..f383dd1 100644
--- a/trusty/coverage/coverage.cpp
+++ b/trusty/coverage/coverage.cpp
@@ -16,12 +16,15 @@
 
 #define LOG_TAG "coverage"
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <assert.h>
+#include <stdio.h>
 #include <sys/mman.h>
 #include <sys/uio.h>
 #include <trusty/coverage/coverage.h>
+#include <trusty/coverage/record.h>
 #include <trusty/coverage/tipc.h>
 #include <trusty/tipc.h>
 
@@ -137,12 +140,59 @@
     return {};
 }
 
-void CoverageRecord::Reset() {
-    for (size_t i = 0; i < shm_len_; i++) {
+void CoverageRecord::ResetFullRecord() {
+    auto header_region = GetRegionBounds(COV_START);
+    if (!header_region.ok()) {
+        // If the header cannot be parsed, we can't reset the proper region yet.
+        return;
+    }
+
+    for (size_t i = header_region->second; i < shm_len_; i++) {
         *((volatile uint8_t*)shm_ + i) = 0;
     }
 }
 
+void CoverageRecord::ResetCounts() {
+    volatile uint8_t* begin = nullptr;
+    volatile uint8_t* end = nullptr;
+    GetRawCounts(&begin, &end);
+
+    for (volatile uint8_t* x = begin; x < end; x++) {
+        *x = 0;
+    }
+}
+
+void CoverageRecord::ResetPCs() {
+    volatile uintptr_t* begin = nullptr;
+    volatile uintptr_t* end = nullptr;
+    GetRawPCs(&begin, &end);
+
+    for (volatile uintptr_t* x = begin; x < end; x++) {
+        *x = 0;
+    }
+}
+
+Result<std::pair<size_t, size_t>> CoverageRecord::GetRegionBounds(uint32_t region_type) {
+    assert(shm_);
+
+    auto header = (volatile struct coverage_record_header*)shm_;
+
+    if (header->type != COV_START) {
+        return Error() << "Header not yet valid";
+    }
+
+    for (++header; header->type != COV_TOTAL_LENGTH; ++header) {
+        if (header->type == region_type) {
+            // Coverage record must end with a COV_TOTAL_LENGTH header entry, so
+            // it is always safe to read the next entry since we don't iterate
+            // over the COV_TOTAL_LENGTH entry.
+            return {{header->offset, (header + 1)->offset}};
+        }
+    }
+
+    return Error() << "Could not find coverage region type: " << region_type;
+}
+
 void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) {
     assert(shm_);
 
@@ -150,7 +200,35 @@
     *end = (uint8_t*)(*begin) + record_len_;
 }
 
-uint64_t CoverageRecord::CountEdges() {
+void CoverageRecord::GetRawCounts(volatile uint8_t** begin, volatile uint8_t** end) {
+    auto region = GetRegionBounds(COV_8BIT_COUNTERS);
+    if (!region.ok()) {
+        *begin = 0;
+        *end = 0;
+        return;
+    }
+
+    assert(region->second <= record_len_);
+
+    *begin = (volatile uint8_t*)shm_ + region->first;
+    *end = (volatile uint8_t*)shm_ + region->second;
+}
+
+void CoverageRecord::GetRawPCs(volatile uintptr_t** begin, volatile uintptr_t** end) {
+    auto region = GetRegionBounds(COV_INSTR_PCS);
+    if (!region.ok()) {
+        *begin = 0;
+        *end = 0;
+        return;
+    }
+
+    assert(region->second <= record_len_);
+
+    *begin = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->first);
+    *end = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->second);
+}
+
+uint64_t CoverageRecord::TotalEdgeCounts() {
     assert(shm_);
 
     uint64_t counter = 0;
@@ -158,7 +236,7 @@
     volatile uint8_t* begin = NULL;
     volatile uint8_t* end = NULL;
 
-    GetRawData((volatile void**)&begin, (volatile void**)&end);
+    GetRawCounts(&begin, &end);
 
     for (volatile uint8_t* x = begin; x < end; x++) {
         counter += *x;
@@ -167,6 +245,35 @@
     return counter;
 }
 
+Result<void> CoverageRecord::SaveSancovFile(const std::string& filename) {
+    android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644)));
+    if (!output_fd.ok()) {
+        return ErrnoError() << "Could not open sancov file";
+    }
+
+    uint64_t magic;
+    if (sizeof(uintptr_t) == 8) {
+        magic = 0xC0BFFFFFFFFFFF64;
+    } else if (sizeof(uintptr_t) == 4) {
+        magic = 0xC0BFFFFFFFFFFF32;
+    }
+    WriteFully(output_fd, &magic, sizeof(magic));
+
+    volatile uintptr_t* begin = nullptr;
+    volatile uintptr_t* end = nullptr;
+
+    GetRawPCs(&begin, &end);
+
+    for (volatile uintptr_t* pc_ptr = begin; pc_ptr < end; pc_ptr++) {
+        uintptr_t pc = *pc_ptr;
+        if (pc) {
+            WriteFully(output_fd, &pc, sizeof(pc));
+        }
+    }
+
+    return {};
+}
+
 }  // namespace coverage
 }  // namespace trusty
 }  // namespace android
diff --git a/trusty/coverage/coverage_test.cpp b/trusty/coverage/coverage_test.cpp
index d8df7a4..c1efca6 100644
--- a/trusty/coverage/coverage_test.cpp
+++ b/trusty/coverage/coverage_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 #include <trusty/coverage/coverage.h>
 #include <trusty/tipc.h>
@@ -27,6 +28,7 @@
 
 #define TIPC_DEV "/dev/trusty-ipc-dev0"
 #define TEST_SRV_PORT "com.android.trusty.sancov.test.srv"
+#define TEST_SRV_MODULE "srv.syms.elf"
 
 namespace android {
 namespace trusty {
@@ -54,8 +56,8 @@
 };
 
 TEST_F(CoverageTest, CoverageReset) {
-    record_->Reset();
-    auto counter = record_->CountEdges();
+    record_->ResetFullRecord();
+    auto counter = record_->TotalEdgeCounts();
     ASSERT_EQ(counter, 0);
 }
 
@@ -69,7 +71,7 @@
 
     for (size_t i = 1; i < sizeof(magic) * 8; i++) {
         /* Reset coverage */
-        record_->Reset();
+        record_->ResetCounts();
 
         /* Send message to test server */
         uint32_t msg = magic & ~(mask << i);
@@ -81,10 +83,15 @@
         ASSERT_EQ(rc, sizeof(msg));
 
         /* Count number of non-unique blocks executed */
-        auto counter = record_->CountEdges();
+        auto counter = record_->TotalEdgeCounts();
         /* Each consecutive input should exercise more or same blocks */
         ASSERT_GE(counter, high_watermark);
         high_watermark = counter;
+
+        auto sancov_filename = android::base::StringPrintf(
+                "/data/local/tmp/" TEST_SRV_MODULE ".%d.sancov", getpid());
+        auto res = record_->SaveSancovFile(sancov_filename);
+        ASSERT_TRUE(res.ok());
     }
 
     ASSERT_GT(high_watermark, 0);
diff --git a/trusty/coverage/include/trusty/coverage/coverage.h b/trusty/coverage/include/trusty/coverage/coverage.h
index b61b959..b6d46eb 100644
--- a/trusty/coverage/include/trusty/coverage/coverage.h
+++ b/trusty/coverage/include/trusty/coverage/coverage.h
@@ -35,13 +35,26 @@
     CoverageRecord(std::string tipc_dev, struct uuid* uuid);
     ~CoverageRecord();
     Result<void> Open();
-    void Reset();
+    void ResetFullRecord();
+    void ResetCounts();
+    void ResetPCs();
     void GetRawData(volatile void** begin, volatile void** end);
-    uint64_t CountEdges();
+    void GetRawCounts(volatile uint8_t** begin, volatile uint8_t** end);
+    void GetRawPCs(volatile uintptr_t** begin, volatile uintptr_t** end);
+    uint64_t TotalEdgeCounts();
+
+    /**
+     * Save the current set of observed PCs to the given filename.
+     * The resulting .sancov file can be parsed via the LLVM sancov tool to see
+     * coverage statistics and visualize coverage.
+     */
+    Result<void> SaveSancovFile(const std::string& filename);
 
   private:
     Result<void> Rpc(coverage_client_req* req, int req_fd, coverage_client_resp* resp);
 
+    Result<std::pair<size_t, size_t>> GetRegionBounds(uint32_t region_type);
+
     std::string tipc_dev_;
     unique_fd coverage_srv_fd_;
     struct uuid uuid_;
diff --git a/trusty/coverage/include/trusty/coverage/record.h b/trusty/coverage/include/trusty/coverage/record.h
new file mode 100644
index 0000000..bfe06f3
--- /dev/null
+++ b/trusty/coverage/include/trusty/coverage/record.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This file needs to be kept in-sync with its counterpart on Trusty side:
+ * trusty/user/base/lib/coverage/common/include/lib/coverage/common/record.h */
+
+#pragma once
+
+#include <stdint.h>
+
+/**
+ * enum coverage_record_type - Coverage region header type
+ * @COV_START: Magic header start marker
+ * @COV_8BIT_COUNTERS: 8bit counter for each instrumentation point
+ * @COV_INSTR_PCS: Pointer length offset of each instrumentation point from the
+ *                 start of the binary
+ * @COV_TOTAL_LENGTH: Total length of the entire coverage record, must be the
+ *                    last header item.
+ *
+ * Describes the type of a region of the coverage record. See &struct
+ * coverage_record_header.
+ */
+enum coverage_record_type {
+    COV_START = 0x434f5652,
+    COV_8BIT_COUNTERS = 1,
+    COV_INSTR_PCS = 2,
+    COV_TOTAL_LENGTH = 0,
+};
+
+/**
+ * struct coverage_record_header - Header entry describing a region of the
+ * coverage record.
+ * @type: type of the region, must be one of @enum coverage_record_type
+ * @offset: offset from the beginning of the header to the start of the region
+ *
+ * Coverage records start with a header which is a list of struct
+ * coverage_record_header, beginning with an entry with type COV_START and
+ * terminated with an entry with type COV_TOTAL_LENGTH. Each of these header
+ * entries corresponds to a region of the record, with the offset indicating the
+ * offset of the start of that region from the beginning of the record (i.e. the
+ * beginning of the header). Each record type and offset is 32-bit field with
+ * native endianness. The first header item must be COV_START with a 0 offset.
+ * The COV_START entry should be initialized when the coverage header is
+ * complete and ready for consumption by the client, because coverage record
+ * initialization happens asynchronously. The final header item,
+ * COV_TOTAL_LENGTH, which must always be present, indicates the total length of
+ * the coverage record, including the header.
+ *
+ * Coverage regions should be contiguous, so the end of one region is the start
+ * of the next, and the coverage header must be in the same order as the regions
+ * in the record body. Thus we can compute the length of a region by subtracting
+ * the region's offset from the offset of the next header item.
+ */
+struct coverage_record_header {
+    uint32_t type;
+    uint32_t offset;
+};
diff --git a/trusty/fuzz/Android.bp b/trusty/fuzz/Android.bp
index 4df77af..ad13816 100644
--- a/trusty/fuzz/Android.bp
+++ b/trusty/fuzz/Android.bp
@@ -39,7 +39,7 @@
     export_include_dirs: ["include"],
     static_libs: [
         "libFuzzer",
-        "libtrusty_test",
+        "libtrusty",
     ],
     shared_libs: [
         "libtrusty_coverage",
diff --git a/trusty/fuzz/counters.cpp b/trusty/fuzz/counters.cpp
index 3fc9f48..8c79475 100644
--- a/trusty/fuzz/counters.cpp
+++ b/trusty/fuzz/counters.cpp
@@ -42,9 +42,9 @@
     assert(fuzzer::ExtraCountersBegin());
     assert(fuzzer::ExtraCountersEnd());
 
-    uint8_t* begin = NULL;
-    uint8_t* end = NULL;
-    record_->GetRawData((volatile void**)&begin, (volatile void**)&end);
+    volatile uint8_t* begin = NULL;
+    volatile uint8_t* end = NULL;
+    record_->GetRawCounts(&begin, &end);
     assert(end - begin <= sizeof(counters));
 }
 
@@ -53,7 +53,7 @@
 }
 
 void ExtraCounters::Reset() {
-    record_->Reset();
+    record_->ResetCounts();
     fuzzer::ClearExtraCounters();
 }
 
@@ -61,7 +61,7 @@
     volatile uint8_t* begin = NULL;
     volatile uint8_t* end = NULL;
 
-    record_->GetRawData((volatile void**)&begin, (volatile void**)&end);
+    record_->GetRawCounts(&begin, &end);
 
     size_t num_counters = end - begin;
     for (size_t i = 0; i < num_counters; i++) {
diff --git a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
index 98cbcc3..7184e4d 100644
--- a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
+++ b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
@@ -221,10 +221,10 @@
 
 Return<ErrorCode> TrustyKeymaster3Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
     if (data.size() == 0) return ErrorCode::OK;
-    AddEntropyRequest request;
+    AddEntropyRequest request(impl_->message_version());
     request.random_data.Reinitialize(data.data(), data.size());
 
-    AddEntropyResponse response;
+    AddEntropyResponse response(impl_->message_version());
     impl_->AddRngEntropy(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -232,10 +232,10 @@
 
 Return<void> TrustyKeymaster3Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
                                                  generateKey_cb _hidl_cb) {
-    GenerateKeyRequest request;
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(keyParams));
 
-    GenerateKeyResponse response;
+    GenerateKeyResponse response(impl_->message_version());
     impl_->GenerateKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -253,11 +253,11 @@
                                                            const hidl_vec<uint8_t>& clientId,
                                                            const hidl_vec<uint8_t>& appData,
                                                            getKeyCharacteristics_cb _hidl_cb) {
-    GetKeyCharacteristicsRequest request;
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    GetKeyCharacteristicsResponse response;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
     impl_->GetKeyCharacteristics(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -273,12 +273,12 @@
                                                KeyFormat keyFormat,
                                                const hidl_vec<uint8_t>& keyData,
                                                importKey_cb _hidl_cb) {
-    ImportKeyRequest request;
+    ImportKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(params));
     request.key_format = legacy_enum_conversion(keyFormat);
     request.SetKeyMaterial(keyData.data(), keyData.size());
 
-    ImportKeyResponse response;
+    ImportKeyResponse response(impl_->message_version());
     impl_->ImportKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -297,12 +297,12 @@
                                                const hidl_vec<uint8_t>& clientId,
                                                const hidl_vec<uint8_t>& appData,
                                                exportKey_cb _hidl_cb) {
-    ExportKeyRequest request;
+    ExportKeyRequest request(impl_->message_version());
     request.key_format = legacy_enum_conversion(exportFormat);
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    ExportKeyResponse response;
+    ExportKeyResponse response(impl_->message_version());
     impl_->ExportKey(request, &response);
 
     hidl_vec<uint8_t> resultKeyBlob;
@@ -316,11 +316,11 @@
 Return<void> TrustyKeymaster3Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
                                                const hidl_vec<KeyParameter>& attestParams,
                                                attestKey_cb _hidl_cb) {
-    AttestKeyRequest request;
+    AttestKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
     request.attest_params.Reinitialize(KmParamSet(attestParams));
 
-    AttestKeyResponse response;
+    AttestKeyResponse response(impl_->message_version());
     impl_->AttestKey(request, &response);
 
     hidl_vec<hidl_vec<uint8_t>> resultCertChain;
@@ -334,11 +334,11 @@
 Return<void> TrustyKeymaster3Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
                                                 const hidl_vec<KeyParameter>& upgradeParams,
                                                 upgradeKey_cb _hidl_cb) {
-    UpgradeKeyRequest request;
+    UpgradeKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
     request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
 
-    UpgradeKeyResponse response;
+    UpgradeKeyResponse response(impl_->message_version());
     impl_->UpgradeKey(request, &response);
 
     if (response.error == KM_ERROR_OK) {
@@ -350,18 +350,18 @@
 }
 
 Return<ErrorCode> TrustyKeymaster3Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
-    DeleteKeyRequest request;
+    DeleteKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
 
-    DeleteKeyResponse response;
+    DeleteKeyResponse response(impl_->message_version());
     impl_->DeleteKey(request, &response);
 
     return legacy_enum_conversion(response.error);
 }
 
 Return<ErrorCode> TrustyKeymaster3Device::deleteAllKeys() {
-    DeleteAllKeysRequest request;
-    DeleteAllKeysResponse response;
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
     impl_->DeleteAllKeys(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -374,15 +374,15 @@
 Return<void> TrustyKeymaster3Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
                                            const hidl_vec<KeyParameter>& inParams,
                                            begin_cb _hidl_cb) {
-    BeginOperationRequest request;
+    BeginOperationRequest request(impl_->message_version());
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    BeginOperationResponse response;
+    BeginOperationResponse response(impl_->message_version());
     impl_->BeginOperation(request, &response);
 
-    hidl_vec<KeyParameter> resultParams;
+    hidl_vec<KeyParameter> resultParams(impl_->message_version());
     if (response.error == KM_ERROR_OK) {
         resultParams = kmParamSet2Hidl(response.output_params);
     }
@@ -394,8 +394,8 @@
 Return<void> TrustyKeymaster3Device::update(uint64_t operationHandle,
                                             const hidl_vec<KeyParameter>& inParams,
                                             const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
-    UpdateOperationRequest request;
-    UpdateOperationResponse response;
+    UpdateOperationRequest request(impl_->message_version());
+    UpdateOperationResponse response(impl_->message_version());
     hidl_vec<KeyParameter> resultParams;
     hidl_vec<uint8_t> resultBlob;
     uint32_t resultConsumed = 0;
@@ -431,13 +431,13 @@
                                             const hidl_vec<uint8_t>& input,
                                             const hidl_vec<uint8_t>& signature,
                                             finish_cb _hidl_cb) {
-    FinishOperationRequest request;
+    FinishOperationRequest request(impl_->message_version());
     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;
+    FinishOperationResponse response(impl_->message_version());
     impl_->FinishOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -451,10 +451,10 @@
 }
 
 Return<ErrorCode> TrustyKeymaster3Device::abort(uint64_t operationHandle) {
-    AbortOperationRequest request;
+    AbortOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
 
-    AbortOperationResponse response;
+    AbortOperationResponse response(impl_->message_version());
     impl_->AbortOperation(request, &response);
 
     return legacy_enum_conversion(response.error);
diff --git a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
index ec2ba12..73ad6ae 100644
--- a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
+++ b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
@@ -284,7 +284,7 @@
 
 Return<void> TrustyKeymaster4Device::computeSharedHmac(
         const hidl_vec<HmacSharingParameters>& params, computeSharedHmac_cb _hidl_cb) {
-    ComputeSharedHmacRequest request;
+    ComputeSharedHmacRequest request(impl_->message_version());
     request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
     request.params_array.num_params = params.size();
     for (size_t i = 0; i < params.size(); ++i) {
@@ -309,7 +309,7 @@
 Return<void> TrustyKeymaster4Device::verifyAuthorization(
         uint64_t challenge, const hidl_vec<KeyParameter>& parametersToVerify,
         const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) {
-    VerifyAuthorizationRequest request;
+    VerifyAuthorizationRequest request(impl_->message_version());
     request.challenge = challenge;
     request.parameters_to_verify.Reinitialize(KmParamSet(parametersToVerify));
     request.auth_token.challenge = authToken.challenge;
@@ -336,10 +336,10 @@
 
 Return<ErrorCode> TrustyKeymaster4Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
     if (data.size() == 0) return ErrorCode::OK;
-    AddEntropyRequest request;
+    AddEntropyRequest request(impl_->message_version());
     request.random_data.Reinitialize(data.data(), data.size());
 
-    AddEntropyResponse response;
+    AddEntropyResponse response(impl_->message_version());
     impl_->AddRngEntropy(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -347,10 +347,10 @@
 
 Return<void> TrustyKeymaster4Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
                                                  generateKey_cb _hidl_cb) {
-    GenerateKeyRequest request;
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(keyParams));
 
-    GenerateKeyResponse response;
+    GenerateKeyResponse response(impl_->message_version());
     impl_->GenerateKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -368,11 +368,11 @@
                                                            const hidl_vec<uint8_t>& clientId,
                                                            const hidl_vec<uint8_t>& appData,
                                                            getKeyCharacteristics_cb _hidl_cb) {
-    GetKeyCharacteristicsRequest request;
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    GetKeyCharacteristicsResponse response;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
     impl_->GetKeyCharacteristics(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -388,12 +388,12 @@
                                                KeyFormat keyFormat,
                                                const hidl_vec<uint8_t>& keyData,
                                                importKey_cb _hidl_cb) {
-    ImportKeyRequest request;
+    ImportKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(params));
     request.key_format = legacy_enum_conversion(keyFormat);
     request.SetKeyMaterial(keyData.data(), keyData.size());
 
-    ImportKeyResponse response;
+    ImportKeyResponse response(impl_->message_version());
     impl_->ImportKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -411,7 +411,7 @@
         const hidl_vec<uint8_t>& wrappedKeyData, const hidl_vec<uint8_t>& wrappingKeyBlob,
         const hidl_vec<uint8_t>& maskingKey, const hidl_vec<KeyParameter>& unwrappingParams,
         uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) {
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(impl_->message_version());
     request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
     request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
     request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
@@ -419,7 +419,7 @@
     request.password_sid = passwordSid;
     request.biometric_sid = biometricSid;
 
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(impl_->message_version());
     impl_->ImportWrappedKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -438,12 +438,12 @@
                                                const hidl_vec<uint8_t>& clientId,
                                                const hidl_vec<uint8_t>& appData,
                                                exportKey_cb _hidl_cb) {
-    ExportKeyRequest request;
+    ExportKeyRequest request(impl_->message_version());
     request.key_format = legacy_enum_conversion(exportFormat);
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    ExportKeyResponse response;
+    ExportKeyResponse response(impl_->message_version());
     impl_->ExportKey(request, &response);
 
     hidl_vec<uint8_t> resultKeyBlob;
@@ -457,11 +457,11 @@
 Return<void> TrustyKeymaster4Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
                                                const hidl_vec<KeyParameter>& attestParams,
                                                attestKey_cb _hidl_cb) {
-    AttestKeyRequest request;
+    AttestKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
     request.attest_params.Reinitialize(KmParamSet(attestParams));
 
-    AttestKeyResponse response;
+    AttestKeyResponse response(impl_->message_version());
     impl_->AttestKey(request, &response);
 
     hidl_vec<hidl_vec<uint8_t>> resultCertChain;
@@ -475,11 +475,11 @@
 Return<void> TrustyKeymaster4Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
                                                 const hidl_vec<KeyParameter>& upgradeParams,
                                                 upgradeKey_cb _hidl_cb) {
-    UpgradeKeyRequest request;
+    UpgradeKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
     request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
 
-    UpgradeKeyResponse response;
+    UpgradeKeyResponse response(impl_->message_version());
     impl_->UpgradeKey(request, &response);
 
     if (response.error == KM_ERROR_OK) {
@@ -491,18 +491,18 @@
 }
 
 Return<ErrorCode> TrustyKeymaster4Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
-    DeleteKeyRequest request;
+    DeleteKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
 
-    DeleteKeyResponse response;
+    DeleteKeyResponse response(impl_->message_version());
     impl_->DeleteKey(request, &response);
 
     return legacy_enum_conversion(response.error);
 }
 
 Return<ErrorCode> TrustyKeymaster4Device::deleteAllKeys() {
-    DeleteAllKeysRequest request;
-    DeleteAllKeysResponse response;
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
     impl_->DeleteAllKeys(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -516,12 +516,12 @@
                                            const hidl_vec<KeyParameter>& inParams,
                                            const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
     hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
-    BeginOperationRequest request;
+    BeginOperationRequest request(impl_->message_version());
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
     request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
-    BeginOperationResponse response;
+    BeginOperationResponse response(impl_->message_version());
     impl_->BeginOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -540,8 +540,8 @@
                                             const VerificationToken& verificationToken,
                                             update_cb _hidl_cb) {
     (void)verificationToken;
-    UpdateOperationRequest request;
-    UpdateOperationResponse response;
+    UpdateOperationRequest request(impl_->message_version());
+    UpdateOperationResponse response(impl_->message_version());
     hidl_vec<KeyParameter> resultParams;
     hidl_vec<uint8_t> resultBlob;
     hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
@@ -581,14 +581,14 @@
                                             const VerificationToken& verificationToken,
                                             finish_cb _hidl_cb) {
     (void)verificationToken;
-    FinishOperationRequest request;
+    FinishOperationRequest request(impl_->message_version());
     hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.signature.Reinitialize(signature.data(), signature.size());
     request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
-    FinishOperationResponse response;
+    FinishOperationResponse response(impl_->message_version());
     impl_->FinishOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -602,10 +602,10 @@
 }
 
 Return<ErrorCode> TrustyKeymaster4Device::abort(uint64_t operationHandle) {
-    AbortOperationRequest request;
+    AbortOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
 
-    AbortOperationResponse response;
+    AbortOperationResponse response(impl_->message_version());
     impl_->AbortOperation(request, &response);
 
     return legacy_enum_conversion(response.error);
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index 750a9d7..5690031 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -31,11 +31,35 @@
         return err;
     }
 
-    ConfigureRequest req;
+    // Try GetVersion2 first.
+    GetVersion2Request versionReq;
+    GetVersion2Response versionRsp = GetVersion2(versionReq);
+    if (versionRsp.error != KM_ERROR_OK) {
+        ALOGW("TA appears not to support GetVersion2, falling back (err = %d)", versionRsp.error);
+
+        GetVersionRequest versionReq;
+        GetVersionResponse versionRsp;
+        GetVersion(versionReq, &versionRsp);
+        if (versionRsp.error != KM_ERROR_OK) {
+            ALOGE("Failed to get TA version %d", versionRsp.error);
+            return -1;
+        } else {
+            keymaster_error_t error;
+            message_version_ = NegotiateMessageVersion(versionRsp, &error);
+            if (error != KM_ERROR_OK) {
+                ALOGE("Failed to negotiate message version %d", error);
+                return -1;
+            }
+        }
+    } else {
+        message_version_ = NegotiateMessageVersion(versionReq, versionRsp);
+    }
+
+    ConfigureRequest req(message_version());
     req.os_version = GetOsVersion();
     req.os_patchlevel = GetOsPatchlevel();
 
-    ConfigureResponse rsp;
+    ConfigureResponse rsp(message_version());
     Configure(req, &rsp);
 
     if (rsp.error != KM_ERROR_OK) {
@@ -52,7 +76,7 @@
     trusty_keymaster_disconnect();
 }
 
-static void ForwardCommand(enum keymaster_command command, const Serializable& req,
+static void ForwardCommand(enum keymaster_command command, const KeymasterMessage& req,
                            KeymasterResponse* rsp) {
     keymaster_error_t err;
     err = trusty_keymaster_send(command, req, rsp);
@@ -173,25 +197,30 @@
 }
 
 GetHmacSharingParametersResponse TrustyKeymaster::GetHmacSharingParameters() {
-    // Empty buffer to allow ForwardCommand to have something to serialize
-    Buffer request;
-    GetHmacSharingParametersResponse response;
+    GetHmacSharingParametersRequest request(message_version());
+    GetHmacSharingParametersResponse response(message_version());
     ForwardCommand(KM_GET_HMAC_SHARING_PARAMETERS, request, &response);
     return response;
 }
 
 ComputeSharedHmacResponse TrustyKeymaster::ComputeSharedHmac(
         const ComputeSharedHmacRequest& request) {
-    ComputeSharedHmacResponse response;
+    ComputeSharedHmacResponse response(message_version());
     ForwardCommand(KM_COMPUTE_SHARED_HMAC, request, &response);
     return response;
 }
 
 VerifyAuthorizationResponse TrustyKeymaster::VerifyAuthorization(
         const VerifyAuthorizationRequest& request) {
-    VerifyAuthorizationResponse response;
+    VerifyAuthorizationResponse response(message_version());
     ForwardCommand(KM_VERIFY_AUTHORIZATION, request, &response);
     return response;
 }
 
+GetVersion2Response TrustyKeymaster::GetVersion2(const GetVersion2Request& request) {
+    GetVersion2Response response(message_version());
+    ForwardCommand(KM_GET_VERSION_2, request, &response);
+    return response;
+}
+
 }  // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 030b645..bec2a2a 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -59,6 +59,12 @@
     GetHmacSharingParametersResponse GetHmacSharingParameters();
     ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
     VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
+    GetVersion2Response GetVersion2(const GetVersion2Request& request);
+
+    uint32_t message_version() const { return message_version_; }
+
+  private:
+    uint32_t message_version_;
 };
 
 }  // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index ce2cc2e..419c96f 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -53,6 +53,7 @@
     KM_DELETE_ALL_KEYS              = (23 << KEYMASTER_REQ_SHIFT),
     KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
     KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
+    KM_GET_VERSION_2                = (28 << KEYMASTER_REQ_SHIFT),
 
     // Bootloader/provisioning calls.
     KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/libtrusty/Android.bp b/trusty/libtrusty/Android.bp
index 708fdbd..e0161a5 100644
--- a/trusty/libtrusty/Android.bp
+++ b/trusty/libtrusty/Android.bp
@@ -26,13 +26,8 @@
 
 cc_library {
     name: "libtrusty",
-    vendor: true,
-    defaults: ["libtrusty_defaults"],
-}
-
-// TODO(b/170753563): cc_fuzz can't deal with vendor components. Build libtrusty
-// for system.
-cc_test_library {
-    name: "libtrusty_test",
+    // TODO(b/170753563): cc_fuzz can't deal with vendor components. Build
+    // libtrusty for system and vendor.
+    vendor_available: true,
     defaults: ["libtrusty_defaults"],
 }