Merge "trusty: Increase maximum number of coverage counters"
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index a152740..5bb1d75 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -32,6 +32,7 @@
 #include <set>
 #include <vector>
 
+#include <android-base/errno_restorer.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -67,8 +68,9 @@
 #include "protocol.h"
 #include "util.h"
 
-using android::base::unique_fd;
+using android::base::ErrnoRestorer;
 using android::base::StringPrintf;
+using android::base::unique_fd;
 
 static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
   struct stat st;
@@ -89,10 +91,11 @@
 static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error, int flags = 0) {
   if (ptrace(PTRACE_SEIZE, tid, 0, flags) != 0) {
     if (errno == EPERM) {
-      pid_t tracer = get_tracer(tid);
-      if (tracer != -1) {
+      ErrnoRestorer errno_restorer;  // In case get_tracer() fails and we fall through.
+      pid_t tracer_pid = get_tracer(tid);
+      if (tracer_pid > 0) {
         *error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid,
-                              tracer, get_process_name(tracer).c_str());
+                              tracer_pid, get_process_name(tracer_pid).c_str());
         return false;
       }
     }
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index feafa73..baf994f 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -1,29 +1,17 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2017 The Android Open Source Project
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
+ * 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
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ *     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 <dirent.h>
@@ -87,6 +75,12 @@
 
     // TODO: Create this once and store it in a global?
     unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
+    // Do not use the thread cache here because it will call pthread_key_create
+    // which doesn't work in linker code. See b/189803009.
+    // Use a normal cached object because the process is stopped, and there
+    // is no chance of data changing between reads.
+    auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+    unwinder.SetProcessMemory(process_memory);
     dump_backtrace_thread(output_fd, &unwinder, thread);
   }
   __linker_disable_fallback_allocator();
diff --git a/debuggerd/handler/debuggerd_fallback_nop.cpp b/debuggerd/handler/debuggerd_fallback_nop.cpp
index 331301f..5666d98 100644
--- a/debuggerd/handler/debuggerd_fallback_nop.cpp
+++ b/debuggerd/handler/debuggerd_fallback_nop.cpp
@@ -1,29 +1,17 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2017 The Android Open Source Project
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
+ * 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
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ *     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.
  */
 
 extern "C" void debuggerd_fallback_handler(struct siginfo_t*, struct ucontext_t*, void*) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index b607397..375dbed 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -1,29 +1,17 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2008 The Android Open Source Project
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
+ * 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
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ *     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 "debuggerd/handler.h"
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ad903ce..9c01f15 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -593,6 +593,9 @@
   };
 
   unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
+  auto process_memory =
+      unwindstack::Memory::CreateProcessMemoryCached(getpid());
+  unwinder.SetProcessMemory(process_memory);
   if (!unwinder.Init()) {
     async_safe_fatal("failed to init unwinder object");
   }
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index c39f4e4..fc43f4e 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -5,4 +5,4 @@
     socket tombstoned_crash seqpacket 0666 system system
     socket tombstoned_intercept seqpacket 0666 system system
     socket tombstoned_java_trace seqpacket 0666 system system
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e5319a5..c87ce60 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -104,8 +104,6 @@
 static bool g_disable_verity = false;
 static bool g_disable_verification = false;
 
-static const std::string convert_fbe_marker_filename("convert_fbe");
-
 fastboot::FastBootDriver* fb = nullptr;
 
 enum fb_buffer_type {
@@ -166,6 +164,11 @@
                                       "vbmeta_system.sig",
                                                       "vbmeta_system",
                                                                   true,  ImageType::BootCritical },
+    { "vbmeta_vendor",
+                  "vbmeta_vendor.img",
+                                      "vbmeta_vendor.sig",
+                                                      "vbmeta_vendor",
+                                                                  true,  ImageType::BootCritical },
     { "vendor",   "vendor.img",       "vendor.sig",   "vendor",   true,  ImageType::Normal },
     { "vendor_boot",
                   "vendor_boot.img",  "vendor_boot.sig",
@@ -424,7 +427,7 @@
             " snapshot-update merge      On devices that support snapshot-based updates, finish\n"
             "                            an in-progress update if it is in the \"merging\"\n"
             "                            phase.\n"
-            " fetch PARTITION            Fetch a partition image from the device."
+            " fetch PARTITION OUT_FILE   Fetch a partition image from the device."
             "\n"
             "boot image:\n"
             " boot KERNEL [RAMDISK [SECOND]]\n"
@@ -468,9 +471,6 @@
             " --disable-verification     Sets disable-verification when flashing vbmeta.\n"
             " --fs-options=OPTION[,OPTION]\n"
             "                            Enable filesystem features. OPTION supports casefold, projid, compress\n"
-#if !defined(_WIN32)
-            " --wipe-and-use-fbe         Enable file-based encryption, wiping userdata.\n"
-#endif
             // TODO: remove --unbuffered?
             " --unbuffered               Don't buffer input or output.\n"
             " --verbose, -v              Verbose output.\n"
@@ -588,10 +588,6 @@
 
 #define tmpfile win32_tmpfile
 
-static std::string make_temporary_directory() {
-    die("make_temporary_directory not supported under Windows, sorry!");
-}
-
 static int make_temporary_fd(const char* /*what*/) {
     // TODO: reimplement to avoid leaking a FILE*.
     return fileno(tmpfile());
@@ -605,15 +601,6 @@
     return std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
 }
 
-static std::string make_temporary_directory() {
-    std::string result(make_temporary_template());
-    if (mkdtemp(&result[0]) == nullptr) {
-        die("unable to create temporary directory with template %s: %s",
-            result.c_str(), strerror(errno));
-    }
-    return result;
-}
-
 static int make_temporary_fd(const char* what) {
     std::string path_template(make_temporary_template());
     int fd = mkstemp(&path_template[0]);
@@ -627,32 +614,6 @@
 
 #endif
 
-static std::string create_fbemarker_tmpdir() {
-    std::string dir = make_temporary_directory();
-    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
-    int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
-    if (fd == -1) {
-        die("unable to create FBE marker file %s locally: %s",
-            marker_file.c_str(), strerror(errno));
-    }
-    close(fd);
-    return dir;
-}
-
-static void delete_fbemarker_tmpdir(const std::string& dir) {
-    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
-    if (unlink(marker_file.c_str()) == -1) {
-        fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
-            marker_file.c_str(), errno, strerror(errno));
-        return;
-    }
-    if (rmdir(dir.c_str()) == -1) {
-        fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
-            dir.c_str(), errno, strerror(errno));
-        return;
-    }
-}
-
 static unique_fd unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
     unique_fd fd(make_temporary_fd(entry_name));
 
@@ -1890,7 +1851,6 @@
     bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
-    bool set_fbe_marker = false;
     bool force_flash = false;
     unsigned fs_options = 0;
     int longindex;
@@ -1928,9 +1888,6 @@
         {"unbuffered", no_argument, 0, 0},
         {"verbose", no_argument, 0, 'v'},
         {"version", no_argument, 0, 0},
-#if !defined(_WIN32)
-        {"wipe-and-use-fbe", no_argument, 0, 0},
-#endif
         {0, 0, 0, 0}
     };
 
@@ -1984,11 +1941,6 @@
                 fprintf(stdout, "fastboot version %s-%s\n", PLATFORM_TOOLS_VERSION, android::build::GetBuildNumber().c_str());
                 fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
                 return 0;
-#if !defined(_WIN32)
-            } else if (name == "wipe-and-use-fbe") {
-                wants_wipe = true;
-                set_fbe_marker = true;
-#endif
             } else {
                 die("unknown option %s", longopts[longindex].name);
             }
@@ -2300,14 +2252,7 @@
             }
             if (partition_type.empty()) continue;
             fb->Erase(partition);
-            if (partition == "userdata" && set_fbe_marker) {
-                fprintf(stderr, "setting FBE marker on initial userdata...\n");
-                std::string initial_userdata_dir = create_fbemarker_tmpdir();
-                fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir, fs_options);
-                delete_fbemarker_tmpdir(initial_userdata_dir);
-            } else {
-                fb_perform_format(partition, 1, partition_type, "", "", fs_options);
-            }
+            fb_perform_format(partition, 1, partition_type, "", "", fs_options);
         }
     }
     if (wants_set_active) {
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 5356b00..3d63a44 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -141,6 +141,7 @@
     // Do not ever allow this library to be vendor_available as a shared library.
     // It does not have a stable interface.
     name: "libfs_mgr",
+    ramdisk_available: true,
     recovery_available: true,
     defaults: [
         "libfs_mgr_defaults",
@@ -165,6 +166,7 @@
     // It does not have a stable interface.
     name: "libfstab",
     vendor_available: true,
+    ramdisk_available: true,
     recovery_available: true,
     host_supported: true,
     defaults: ["fs_mgr_defaults"],
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index af71fe6..01c8ad3 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2092,7 +2092,7 @@
         }
 
         if (entry.zram_size > 0) {
-	    if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
+            if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
                 LERROR << "Failure of zram backing device file for '" << entry.blk_device << "'";
             }
             // A zram_size was specified, so we need to configure the
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index e685070..5411aca 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -420,7 +420,8 @@
                 break;
             }
             // Find overlayfs mount point?
-            if ((mount_point == "/") && (rentry.mount_point == "/system")) {
+            if ((mount_point == "/" && rentry.mount_point == "/system")  ||
+                (mount_point == "/system" && rentry.mount_point == "/")) {
                 blk_device = rentry.blk_device;
                 mount_point = "/system";
                 found = true;
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index b0639e6..90d91a0 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -109,6 +109,10 @@
     optional_args_.emplace_back("ignore_zero_blocks");
 }
 
+void DmTargetVerity::CheckAtMostOnce() {
+    optional_args_.emplace_back("check_at_most_once");
+}
+
 std::string DmTargetVerity::GetParameterString() const {
     std::string base = android::base::Join(base_args_, " ");
     if (optional_args_.empty()) {
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 478a3c6..9543058 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -127,6 +127,7 @@
     void UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks, uint32_t start);
     void SetVerityMode(const std::string& mode);
     void IgnoreZeroBlocks();
+    void CheckAtMostOnce();
 
     std::string name() const override { return "verity"; }
     std::string GetParameterString() const override;
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 1c5872e..b62e33f 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -20,6 +20,7 @@
 
 cc_library_headers {
     name: "libfiemap_headers",
+    ramdisk_available: true,
     recovery_available: true,
     export_include_dirs: ["include"],
 }
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 6892025..62493eb 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -27,6 +27,7 @@
 cc_library_static {
     name: "libfs_avb",
     defaults: ["fs_mgr_defaults"],
+    ramdisk_available: true,
     recovery_available: true,
     host_supported: true,
     export_include_dirs: ["include"],
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 31494c1..e913d50 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -92,6 +92,10 @@
     // Always use ignore_zero_blocks.
     target.IgnoreZeroBlocks();
 
+    if (hashtree_desc.flags & AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE) {
+        target.CheckAtMostOnce();
+    }
+
     LINFO << "Built verity table: '" << target.GetParameterString() << "'";
 
     return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
index 1827566..0288d85 100644
--- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -755,6 +755,7 @@
     std::string out_public_key_data;
     std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
             fd, "system", "" /*expected_public_key_blob */, &out_public_key_data, &verify_result);
+    ASSERT_EQ(0, close(fd.release()));
     EXPECT_NE(nullptr, vbmeta);
     EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
 
@@ -776,6 +777,7 @@
     // Should return ErrorVerification.
     vbmeta = VerifyVBMetaData(hash_modified_fd, "system", "" /*expected_public_key_blob */,
                               nullptr /* out_public_key_data */, &verify_result);
+    ASSERT_EQ(0, close(hash_modified_fd.release()));
     EXPECT_NE(nullptr, vbmeta);
     EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
     EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
@@ -791,6 +793,7 @@
     // Should return ErrorVerification.
     vbmeta = VerifyVBMetaData(aux_modified_fd, "system", "" /*expected_public_key_blob */,
                               nullptr /* out_public_key_data */, &verify_result);
+    ASSERT_EQ(0, close(aux_modified_fd.release()));
     EXPECT_NE(nullptr, vbmeta);
     EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
     EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
@@ -802,6 +805,7 @@
     // Should return ResultOK..
     vbmeta = VerifyVBMetaData(ok_fd, "system", "" /*expected_public_key_blob */,
                               nullptr /* out_public_key_data */, &verify_result);
+    ASSERT_EQ(0, close(ok_fd.release()));
     EXPECT_NE(nullptr, vbmeta);
     EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
     EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 7e528b1..86ca8f3 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -30,6 +30,7 @@
 cc_library {
     name: "liblp",
     host_supported: true,
+    ramdisk_available: true,
     recovery_available: true,
     defaults: ["fs_mgr_defaults"],
     cppflags: [
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 6a764e4..aa1f415 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -118,6 +118,7 @@
     native_coverage : true,
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
+    ramdisk_available: true,
     recovery_available: true,
     cflags: [
         "-DLIBSNAPSHOT_NO_COW_WRITE",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 77ed92c..c0649ca 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -158,6 +158,13 @@
     ExpectedMergeTarget = 11;
     UnmergedSectorsAfterCompletion = 12;
     UnexpectedMergeState = 13;
+    GetCowPathConsistencyCheck = 14;
+    OpenCowConsistencyCheck = 15;
+    ParseCowConsistencyCheck = 16;
+    OpenCowDirectConsistencyCheck = 17;
+    MemAlignConsistencyCheck = 18;
+    DirectReadConsistencyCheck = 19;
+    WrongMergeCountConsistencyCheck = 20;
 };
 
 // Next: 8
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 51c00a9..0a7ceab 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -58,6 +58,12 @@
     return EmitRawBlocks(new_block_start, data, size);
 }
 
+bool AddXorBlocks(uint32_t /*new_block_start*/, const void* /*data*/, size_t /*size*/,
+                  uint32_t /*old_block*/, uint16_t /*offset*/) {
+    LOG(ERROR) << "AddXorBlocks not yet implemented";
+    return false;
+}
+
 bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
     uint64_t last_block = new_block_start + num_blocks - 1;
     if (!ValidateNewBlock(last_block)) {
@@ -70,6 +76,11 @@
     return EmitLabel(label);
 }
 
+bool AddSequenceData(size_t /*num_ops*/, const uint32_t* /*data*/) {
+    LOG(ERROR) << "AddSequenceData not yet implemented";
+    return false;
+}
+
 bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
     if (options_.max_blocks && new_block >= options_.max_blocks.value()) {
         LOG(ERROR) << "New block " << new_block << " exceeds maximum block count "
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 9ebcfd9..669e58a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -143,12 +143,11 @@
 
     void InitializeMerge();
 
+    // Number of copy, replace, and zero ops. Set if InitializeMerge is called.
     void set_total_data_ops(uint64_t size) { total_data_ops_ = size; }
-
     uint64_t total_data_ops() { return total_data_ops_; }
-
+    // Number of copy ops. Set if InitializeMerge is called.
     void set_copy_ops(uint64_t size) { copy_ops_ = size; }
-
     uint64_t total_copy_ops() { return copy_ops_; }
 
     void CloseCowFd() { owned_fd_ = {}; }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index f43ea68..fbe6461 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -55,12 +55,19 @@
     // Encode a sequence of raw blocks. |size| must be a multiple of the block size.
     bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
 
+    // Add a sequence of xor'd blocks. |size| must be a multiple of the block size.
+    bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
+                      uint16_t offset);
+
     // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
     bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks);
 
     // Add a label to the op sequence.
     bool AddLabel(uint64_t label);
 
+    // Add sequence data for op merging. Data is a list of the destination block numbers.
+    bool AddSequenceData(size_t num_ops, const uint32_t* data);
+
     // Flush all pending writes. This must be called before closing the writer
     // to ensure that the correct headers and footers are written.
     virtual bool Finalize() = 0;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 603e896..65034f7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -603,6 +603,8 @@
     MergeResult CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel);
     MergeResult CheckTargetMergeState(LockedFile* lock, const std::string& name,
                                       const SnapshotUpdateStatus& update_status);
+    MergeFailureCode CheckMergeConsistency(LockedFile* lock, const std::string& name,
+                                           const SnapshotStatus& update_status);
 
     // Interact with status files under /metadata/ota/snapshots.
     bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 4a84fba..1dc61af 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -106,6 +106,8 @@
         std::cout << "Header size: " << header.header_size << "\n";
         std::cout << "Footer size: " << header.footer_size << "\n";
         std::cout << "Block size: " << header.block_size << "\n";
+        std::cout << "Num merge ops: " << header.num_merge_ops << "\n";
+        std::cout << "RA buffer size: " << header.buffer_size << "\n";
         std::cout << "\n";
         if (has_footer) {
             std::cout << "Total Ops size: " << footer.op.ops_size << "\n";
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e2c03ae..be732ec 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1126,6 +1126,11 @@
         return MergeResult(UpdateState::Merging);
     }
 
+    auto code = CheckMergeConsistency(lock, name, snapshot_status);
+    if (code != MergeFailureCode::Ok) {
+        return MergeResult(UpdateState::MergeFailed, code);
+    }
+
     // Merging is done. First, update the status file to indicate the merge
     // is complete. We do this before calling OnSnapshotMergeComplete, even
     // though this means the write is potentially wasted work (since in the
@@ -1144,6 +1149,91 @@
     return MergeResult(UpdateState::MergeCompleted, MergeFailureCode::Ok);
 }
 
+// This returns the backing device, not the dm-user layer.
+static std::string GetMappedCowDeviceName(const std::string& snapshot,
+                                          const SnapshotStatus& status) {
+    // If no partition was created (the COW exists entirely on /data), the
+    // device-mapper layering is different than if we had a partition.
+    if (status.cow_partition_size() == 0) {
+        return GetCowImageDeviceName(snapshot);
+    }
+    return GetCowName(snapshot);
+}
+
+MergeFailureCode SnapshotManager::CheckMergeConsistency(LockedFile* lock, const std::string& name,
+                                                        const SnapshotStatus& status) {
+    CHECK(lock);
+
+    if (!status.compression_enabled()) {
+        // Do not try to verify old-style COWs yet.
+        return MergeFailureCode::Ok;
+    }
+
+    auto& dm = DeviceMapper::Instance();
+
+    std::string cow_image_name = GetMappedCowDeviceName(name, status);
+    std::string cow_image_path;
+    if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_path)) {
+        LOG(ERROR) << "Failed to get path for cow device: " << cow_image_name;
+        return MergeFailureCode::GetCowPathConsistencyCheck;
+    }
+
+    // First pass, count # of ops.
+    size_t num_ops = 0;
+    {
+        unique_fd fd(open(cow_image_path.c_str(), O_RDONLY | O_CLOEXEC));
+        if (fd < 0) {
+            PLOG(ERROR) << "Failed to open " << cow_image_name;
+            return MergeFailureCode::OpenCowConsistencyCheck;
+        }
+
+        CowReader reader;
+        if (!reader.Parse(std::move(fd))) {
+            LOG(ERROR) << "Failed to parse cow " << cow_image_path;
+            return MergeFailureCode::ParseCowConsistencyCheck;
+        }
+
+        for (auto iter = reader.GetOpIter(); !iter->Done(); iter->Next()) {
+            if (!IsMetadataOp(iter->Get())) {
+                num_ops++;
+            }
+        }
+    }
+
+    // Second pass, try as hard as we can to get the actual number of blocks
+    // the system thinks is merged.
+    unique_fd fd(open(cow_image_path.c_str(), O_RDONLY | O_DIRECT | O_SYNC | O_CLOEXEC));
+    if (fd < 0) {
+        PLOG(ERROR) << "Failed to open direct " << cow_image_name;
+        return MergeFailureCode::OpenCowDirectConsistencyCheck;
+    }
+
+    void* addr;
+    size_t page_size = getpagesize();
+    if (posix_memalign(&addr, page_size, page_size) < 0) {
+        PLOG(ERROR) << "posix_memalign with page size " << page_size;
+        return MergeFailureCode::MemAlignConsistencyCheck;
+    }
+
+    // COWs are always at least 2MB, this is guaranteed in snapshot creation.
+    std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
+    if (!android::base::ReadFully(fd, buffer.get(), page_size)) {
+        PLOG(ERROR) << "Direct read failed " << cow_image_name;
+        return MergeFailureCode::DirectReadConsistencyCheck;
+    }
+
+    auto header = reinterpret_cast<CowHeader*>(buffer.get());
+    if (header->num_merge_ops != num_ops) {
+        LOG(ERROR) << "COW consistency check failed, expected " << num_ops << " to be merged, "
+                   << "but " << header->num_merge_ops << " were actually recorded.";
+        LOG(ERROR) << "Aborting merge progress for snapshot " << name
+                   << ", will try again next boot";
+        return MergeFailureCode::WrongMergeCountConsistencyCheck;
+    }
+
+    return MergeFailureCode::Ok;
+}
+
 MergeFailureCode SnapshotManager::MergeSecondPhaseSnapshots(LockedFile* lock) {
     std::vector<std::string> snapshots;
     if (!ListSnapshots(lock, &snapshots)) {
@@ -1429,14 +1519,7 @@
             continue;
         }
 
-        // If no partition was created (the COW exists entirely on /data), the
-        // device-mapper layering is different than if we had a partition.
-        std::string cow_image_name;
-        if (snapshot_status.cow_partition_size() == 0) {
-            cow_image_name = GetCowImageDeviceName(snapshot);
-        } else {
-            cow_image_name = GetCowName(snapshot);
-        }
+        std::string cow_image_name = GetMappedCowDeviceName(snapshot, snapshot_status);
 
         std::string cow_image_device;
         if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
diff --git a/fs_mgr/libstorage_literals/Android.bp b/fs_mgr/libstorage_literals/Android.bp
index 5b07168..fd7ea04 100644
--- a/fs_mgr/libstorage_literals/Android.bp
+++ b/fs_mgr/libstorage_literals/Android.bp
@@ -6,6 +6,7 @@
 cc_library_headers {
     name: "libstorage_literals_headers",
     host_supported: true,
+    ramdisk_available: true,
     recovery_available: true,
     export_include_dirs: ["."],
     target: {
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index 8b126d5..f572b11 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,4 +1,4 @@
 service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
     class late_start
     user system
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
diff --git a/init/Android.bp b/init/Android.bp
index 1381c1d..3e8d4e3 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -253,11 +253,32 @@
     visibility: ["//packages/modules/Virtualization/microdroid"],
 }
 
-// This currently is only for the VM usecase.
-// TODO(jiyong): replace init_first_stage in Android.mk with this
+soong_config_module_type {
+    name: "init_first_stage_cc_defaults",
+    module_type: "cc_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: ["BOARD_BUILD_SYSTEM_ROOT_IMAGE", "BOARD_USES_RECOVERY_AS_BOOT"],
+    properties: ["installable"],
+}
+
+// Do not install init_first_stage even with mma if we're system-as-root.
+// Otherwise, it will overwrite the symlink.
+init_first_stage_cc_defaults {
+    name: "init_first_stage_defaults",
+    soong_config_variables: {
+        BOARD_BUILD_SYSTEM_ROOT_IMAGE: {
+            installable: false,
+        },
+        BOARD_USES_RECOVERY_AS_BOOT: {
+            installable: false,
+        },
+    },
+}
+
 cc_binary {
-    name: "init_first_stage_soong",
-    stem: "init_vendor",
+    name: "init_first_stage",
+    stem: "init",
+    defaults: ["init_first_stage_defaults"],
 
     srcs: [
         "block_dev_initializer.cpp",
@@ -313,6 +334,7 @@
     ],
 
     static_executable: true,
+    system_shared_libs: [],
 
     cflags: [
         "-Wall",
@@ -363,8 +385,23 @@
 
     sanitize: {
         misc_undefined: ["signed-integer-overflow"],
+
+        // First stage init is weird: it may start without stdout/stderr, and no /proc.
         hwaddress: false,
     },
+
+    // Install adb_debug.prop into debug ramdisk.
+    // This allows adb root on a user build, when debug ramdisk is used.
+    required: ["adb_debug.prop"],
+
+    ramdisk: true,
+
+    install_in_root: true,
+}
+
+phony {
+    name: "init_system",
+    required: ["init_second_stage"],
 }
 
 // Tests
diff --git a/init/Android.mk b/init/Android.mk
index 3c7d95a..c08fe03 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -2,153 +2,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
--include system/sepolicy/policy_version.mk
-
-# --
-
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-init_options += \
-    -DALLOW_FIRST_STAGE_CONSOLE=1 \
-    -DALLOW_LOCAL_PROP_OVERRIDE=1 \
-    -DALLOW_PERMISSIVE_SELINUX=1 \
-    -DREBOOT_BOOTLOADER_ON_PANIC=1 \
-    -DWORLD_WRITABLE_KMSG=1 \
-    -DDUMP_ON_UMOUNT_FAILURE=1
-else
-init_options += \
-    -DALLOW_FIRST_STAGE_CONSOLE=0 \
-    -DALLOW_LOCAL_PROP_OVERRIDE=0 \
-    -DALLOW_PERMISSIVE_SELINUX=0 \
-    -DREBOOT_BOOTLOADER_ON_PANIC=0 \
-    -DWORLD_WRITABLE_KMSG=0 \
-    -DDUMP_ON_UMOUNT_FAILURE=0
-endif
-
-ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
-init_options += \
-    -DSHUTDOWN_ZERO_TIMEOUT=1
-else
-init_options += \
-    -DSHUTDOWN_ZERO_TIMEOUT=0
-endif
-
-init_options += -DLOG_UEVENTS=0 \
-    -DSEPOLICY_VERSION=$(POLICYVERS)
-
-init_cflags += \
-    $(init_options) \
-    -Wall -Wextra \
-    -Wno-unused-parameter \
-    -Werror \
-
-# --
-
-# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
-ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-include $(CLEAR_VARS)
-LOCAL_CPPFLAGS := $(init_cflags)
-LOCAL_SRC_FILES := \
-    block_dev_initializer.cpp \
-    devices.cpp \
-    first_stage_console.cpp \
-    first_stage_init.cpp \
-    first_stage_main.cpp \
-    first_stage_mount.cpp \
-    reboot_utils.cpp \
-    selabel.cpp \
-    selinux.cpp \
-    service_utils.cpp \
-    snapuserd_transition.cpp \
-    switch_root.cpp \
-    uevent_listener.cpp \
-    util.cpp \
-
-LOCAL_MODULE := init_first_stage
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_MODULE_STEM := init
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
-
-# Install adb_debug.prop into debug ramdisk.
-# This allows adb root on a user build, when debug ramdisk is used.
-LOCAL_REQUIRED_MODULES := \
-   adb_debug.prop \
-
-# Set up the directories that first stage init mounts on.
-
-my_ramdisk_dirs := \
-    debug_ramdisk \
-    dev \
-    metadata \
-    mnt \
-    proc \
-    second_stage_resources \
-    sys \
-
-LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_RAMDISK_OUT)/,$(my_ramdisk_dirs))
-ifeq (true,$(BOARD_USES_GENERIC_KERNEL_IMAGE))
-    LOCAL_POST_INSTALL_CMD += $(addprefix $(TARGET_RAMDISK_OUT)/first_stage_ramdisk/,$(my_ramdisk_dirs))
-endif
-
-my_ramdisk_dirs :=
-
-LOCAL_STATIC_LIBRARIES := \
-    libc++fs \
-    libfs_avb \
-    libfs_mgr \
-    libfec \
-    libfec_rs \
-    libsquashfs_utils \
-    liblogwrap \
-    libext4_utils \
-    libcrypto_utils \
-    libsparse \
-    libavb \
-    libkeyutils \
-    liblp \
-    libcutils \
-    libbase \
-    liblog \
-    libcrypto_static \
-    libdl \
-    libz \
-    libselinux \
-    libcap \
-    libgsi \
-    libcom.android.sysprop.apex \
-    liblzma \
-    libunwindstack_no_dex \
-    libbacktrace_no_dex \
-    libmodprobe \
-    libext2_uuid \
-    libprotobuf-cpp-lite \
-    libsnapshot_cow \
-    libsnapshot_init \
-    update_metadata-protos \
-    libprocinfo \
-
-LOCAL_SANITIZE := signed-integer-overflow
-# First stage init is weird: it may start without stdout/stderr, and no /proc.
-LOCAL_NOSANITIZE := hwaddress
-include $(BUILD_EXECUTABLE)
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := init_system
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_REQUIRED_MODULES := \
-   init_second_stage \
-
-include $(BUILD_PHONY_PACKAGE)
-
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := init_vendor
@@ -156,8 +9,10 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
 LOCAL_REQUIRED_MODULES := \
    init_first_stage \
 
-endif
+endif  # BOARD_USES_RECOVERY_AS_BOOT
+endif  # BOARD_BUILD_SYSTEM_ROOT_IMAGE
 include $(BUILD_PHONY_PACKAGE)
diff --git a/init/README.md b/init/README.md
index 75dc328..4b04628 100644
--- a/init/README.md
+++ b/init/README.md
@@ -406,6 +406,33 @@
    3. Any time that property c transitions to value d, while property a already equals b.
 
 
+Trigger Sequence
+----------------
+
+Init uses the following sequence of triggers during early boot. These are the
+built-in triggers defined in init.cpp.
+
+   1. `early-init` - The first in the sequence, triggered after cgroups has been configured
+      but before ueventd's coldboot is complete.
+   2. `init` - Triggered after coldboot is complete.
+   3. `charger` - Triggered if `ro.bootmode == "charger"`.
+   4. `late-init` - Triggered if `ro.bootmode != "charger"`, or via healthd triggering a boot
+      from charging mode.
+
+Remaining triggers are configured in `init.rc` and are not built-in. The default sequence for
+these is specified under the "on late-init" event in `init.rc`. Actions internal to `init.rc`
+have been omitted.
+
+   1. `early-fs` - Start vold.
+   2. `fs` - Vold is up. Mount partitions not marked as first-stage or latemounted.
+   3. `post-fs` - Configure anything dependent on early mounts.
+   4. `late-fs` - Mount partitions marked as latemounted.
+   5. `post-fs-data` - Mount and configure `/data`; set up encryption. `/metadata` is
+      reformatted here if it couldn't mount in first-stage init.
+   6. `zygote-start` - Start the zygote.
+   7. `early-boot` - After zygote has started.
+   8. `boot` - After `early-boot` actions have completed.
+
 Commands
 --------
 
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 76f5193..2401da3 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -163,3 +163,13 @@
 from enabling the parallelization option:
 
     parallel_restorecon enabled
+
+Do parallel restorecon to speed up boot process, subdirectories under `/sys`
+can be sliced by ueventd.rc, and run on multiple process.
+    parallel_restorecon_dir <directory>
+
+For example
+    parallel_restorecon_dir /sys
+    parallel_restorecon_dir /sys/devices
+    parallel_restorecon_dir /sys/devices/platform
+    parallel_restorecon_dir /sys/devices/platform/soc
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 98f6857..b3fa9fd 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -31,6 +31,7 @@
 
 #include "capabilities.h"
 #include "reboot_utils.h"
+#include "util.h"
 
 namespace android {
 namespace init {
@@ -38,31 +39,51 @@
 static std::string init_fatal_reboot_target = "bootloader";
 static bool init_fatal_panic = false;
 
+// this needs to read the /proc/* files directly because it is called before
+// ro.boot.* properties are initialized
 void SetFatalRebootTarget(const std::optional<std::string>& reboot_target) {
     std::string cmdline;
     android::base::ReadFileToString("/proc/cmdline", &cmdline);
     cmdline = android::base::Trim(cmdline);
 
-    const char kInitFatalPanicString[] = "androidboot.init_fatal_panic=true";
-    init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos;
+    const std::string kInitFatalPanicParamString = "androidboot.init_fatal_panic";
+    if (cmdline.find(kInitFatalPanicParamString) == std::string::npos) {
+        init_fatal_panic = false;
+        ImportBootconfig(
+                [kInitFatalPanicParamString](const std::string& key, const std::string& value) {
+                    if (key == kInitFatalPanicParamString && value == "true") {
+                        init_fatal_panic = true;
+                    }
+                });
+    } else {
+        const std::string kInitFatalPanicString = kInitFatalPanicParamString + "=true";
+        init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos;
+    }
 
     if (reboot_target) {
         init_fatal_reboot_target = *reboot_target;
         return;
     }
 
-    const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target=";
+    const std::string kRebootTargetString = "androidboot.init_fatal_reboot_target";
     auto start_pos = cmdline.find(kRebootTargetString);
     if (start_pos == std::string::npos) {
-        return;  // We already default to bootloader if no setting is provided.
-    }
-    start_pos += sizeof(kRebootTargetString) - 1;
+        ImportBootconfig([kRebootTargetString](const std::string& key, const std::string& value) {
+            if (key == kRebootTargetString) {
+                init_fatal_reboot_target = value;
+            }
+        });
+        // We already default to bootloader if no setting is provided.
+    } else {
+        const std::string kRebootTargetStringPattern = kRebootTargetString + "=";
+        start_pos += sizeof(kRebootTargetStringPattern) - 1;
 
-    auto end_pos = cmdline.find(' ', start_pos);
-    // if end_pos isn't found, then we've run off the end, but this is okay as this is the last
-    // entry, and -1 is a valid size for string::substr();
-    auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
-    init_fatal_reboot_target = cmdline.substr(start_pos, size);
+        auto end_pos = cmdline.find(' ', start_pos);
+        // if end_pos isn't found, then we've run off the end, but this is okay as this is the last
+        // entry, and -1 is a valid size for string::substr();
+        auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
+        init_fatal_reboot_target = cmdline.substr(start_pos, size);
+    }
 }
 
 bool IsRebootCapable() {
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index f9ee9e3..68c6b51 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -115,11 +115,13 @@
   public:
     ColdBoot(UeventListener& uevent_listener,
              std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers,
-             bool enable_parallel_restorecon)
+             bool enable_parallel_restorecon,
+             std::vector<std::string> parallel_restorecon_queue)
         : uevent_listener_(uevent_listener),
           uevent_handlers_(uevent_handlers),
           num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4),
-          enable_parallel_restorecon_(enable_parallel_restorecon) {}
+          enable_parallel_restorecon_(enable_parallel_restorecon),
+          parallel_restorecon_queue_(parallel_restorecon_queue) {}
 
     void Run();
 
@@ -142,6 +144,8 @@
     std::set<pid_t> subprocess_pids_;
 
     std::vector<std::string> restorecon_queue_;
+
+    std::vector<std::string> parallel_restorecon_queue_;
 };
 
 void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
@@ -155,17 +159,34 @@
 }
 
 void ColdBoot::RestoreConHandler(unsigned int process_num, unsigned int total_processes) {
+    android::base::Timer t_process;
+
     for (unsigned int i = process_num; i < restorecon_queue_.size(); i += total_processes) {
+        android::base::Timer t;
         auto& dir = restorecon_queue_[i];
 
         selinux_android_restorecon(dir.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
+
+        //Mark a dir restorecon operation for 50ms,
+        //Maybe you can add this dir to the ueventd.rc script to parallel processing
+        if (t.duration() > 50ms) {
+            LOG(INFO) << "took " << t.duration().count() <<"ms restorecon '"
+                        << dir.c_str() << "' on process '" << process_num  <<"'";
+        }
     }
+
+    //Calculate process restorecon time
+    LOG(VERBOSE) << "took " << t_process.duration().count() << "ms on process '"
+                << process_num  << "'";
 }
 
 void ColdBoot::GenerateRestoreCon(const std::string& directory) {
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(directory.c_str()), &closedir);
 
-    if (!dir) return;
+    if (!dir) {
+        PLOG(WARNING) << "opendir " << directory.c_str();
+        return;
+    }
 
     struct dirent* dent;
     while ((dent = readdir(dir.get())) != NULL) {
@@ -176,7 +197,10 @@
 
         if (S_ISDIR(st.st_mode)) {
             std::string fullpath = directory + "/" + dent->d_name;
-            if (fullpath != "/sys/devices") {
+            auto parallel_restorecon =
+                std::find(parallel_restorecon_queue_.begin(),
+                    parallel_restorecon_queue_.end(), fullpath);
+            if (parallel_restorecon == parallel_restorecon_queue_.end()) {
                 restorecon_queue_.emplace_back(fullpath);
             }
         }
@@ -248,11 +272,16 @@
     RegenerateUevents();
 
     if (enable_parallel_restorecon_) {
-        selinux_android_restorecon("/sys", 0);
-        selinux_android_restorecon("/sys/devices", 0);
-        GenerateRestoreCon("/sys");
-        // takes long time for /sys/devices, parallelize it
-        GenerateRestoreCon("/sys/devices");
+        if (parallel_restorecon_queue_.empty()) {
+            parallel_restorecon_queue_.emplace_back("/sys");
+            // takes long time for /sys/devices, parallelize it
+            parallel_restorecon_queue_.emplace_back("/sys/devices");
+            LOG(INFO) << "Parallel processing directory is not set, set the default";
+        }
+        for (const auto& dir : parallel_restorecon_queue_) {
+            selinux_android_restorecon(dir.c_str(), 0);
+            GenerateRestoreCon(dir);
+        }
     }
 
     ForkSubProcesses();
@@ -326,7 +355,8 @@
 
     if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {
         ColdBoot cold_boot(uevent_listener, uevent_handlers,
-                           ueventd_configuration.enable_parallel_restorecon);
+                           ueventd_configuration.enable_parallel_restorecon,
+                           ueventd_configuration.parallel_restorecon_dirs);
         cold_boot.Run();
     }
 
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 9a14406..d34672e 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -151,6 +151,17 @@
     return {};
 }
 
+Result<void> ParseParallelRestoreconDirsLine(std::vector<std::string>&& args,
+                                          std::vector<std::string>* parallel_restorecon_dirs) {
+    if (args.size() != 2) {
+        return Error() << "parallel_restorecon_dir lines must have exactly 2 parameters";
+    }
+
+    std::move(std::next(args.begin()), args.end(), std::back_inserter(*parallel_restorecon_dirs));
+
+    return {};
+}
+
 Result<void> ParseUeventSocketRcvbufSizeLine(std::vector<std::string>&& args,
                                              size_t* uevent_socket_rcvbuf_size) {
     if (args.size() != 2) {
@@ -268,6 +279,9 @@
     parser.AddSingleLineParser("uevent_socket_rcvbuf_size",
                                std::bind(ParseUeventSocketRcvbufSizeLine, _1,
                                          &ueventd_configuration.uevent_socket_rcvbuf_size));
+    parser.AddSingleLineParser("parallel_restorecon_dir",
+                               std::bind(ParseParallelRestoreconDirsLine, _1,
+                                         &ueventd_configuration.parallel_restorecon_dirs));
     parser.AddSingleLineParser("parallel_restorecon",
                                std::bind(ParseEnabledDisabledLine, _1,
                                          &ueventd_configuration.enable_parallel_restorecon));
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index eaafa5a..81f4e9d 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -31,6 +31,7 @@
     std::vector<Permissions> dev_permissions;
     std::vector<std::string> firmware_directories;
     std::vector<ExternalFirmwareHandler> external_firmware_handlers;
+    std::vector<std::string> parallel_restorecon_dirs;
     bool enable_modalias_handling = false;
     size_t uevent_socket_rcvbuf_size = 0;
     bool enable_parallel_restorecon = false;
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index d77cb03..41924e2 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -77,6 +77,7 @@
     EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
     TestVector(expected.external_firmware_handlers, result.external_firmware_handlers,
                TestExternalFirmwareHandler);
+    EXPECT_EQ(expected.parallel_restorecon_dirs, result.parallel_restorecon_dirs);
 }
 
 TEST(ueventd_parser, EmptyFile) {
@@ -105,7 +106,7 @@
             {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
             {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
 
-    TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}});
+    TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}});
 }
 
 TEST(ueventd_parser, Permissions) {
@@ -131,7 +132,7 @@
             {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true},
     };
 
-    TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}});
+    TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}, {}});
 }
 
 TEST(ueventd_parser, FirmwareDirectories) {
@@ -147,7 +148,7 @@
             "/more",
     };
 
-    TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}});
+    TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}, {}});
 }
 
 TEST(ueventd_parser, ExternalFirmwareHandlers) {
@@ -213,7 +214,7 @@
             },
     };
 
-    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}});
 }
 
 TEST(ueventd_parser, ExternalFirmwareHandlersDuplicate) {
@@ -231,7 +232,21 @@
             },
     };
 
-    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}});
+}
+
+TEST(ueventd_parser, ParallelRestoreconDirs) {
+    auto ueventd_file = R"(
+parallel_restorecon_dir /sys
+parallel_restorecon_dir /sys/devices
+)";
+
+    auto parallel_restorecon_dirs = std::vector<std::string>{
+            "/sys",
+            "/sys/devices",
+    };
+
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, parallel_restorecon_dirs});
 }
 
 TEST(ueventd_parser, UeventSocketRcvbufSize) {
@@ -240,7 +255,7 @@
 uevent_socket_rcvbuf_size 8M
 )";
 
-    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 8 * 1024 * 1024});
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024});
 }
 
 TEST(ueventd_parser, EnabledDisabledLines) {
@@ -250,7 +265,7 @@
 modalias_handling disabled
 )";
 
-    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, false, 0, true});
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 0, true});
 
     auto ueventd_file2 = R"(
 parallel_restorecon enabled
@@ -258,7 +273,7 @@
 parallel_restorecon disabled
 )";
 
-    TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, true, 0, false});
+    TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, true, 0, false});
 }
 
 TEST(ueventd_parser, AllTogether) {
@@ -298,6 +313,9 @@
 modalias_handling enabled
 parallel_restorecon enabled
 
+parallel_restorecon_dir /sys
+parallel_restorecon_dir /sys/devices
+
 #ending comment
 )";
 
@@ -330,11 +348,17 @@
             {"/devices/path/firmware/firmware001.bin", AID_ROOT, AID_ROOT, "/vendor/bin/touch.sh"},
     };
 
+    auto parallel_restorecon_dirs = std::vector<std::string>{
+            "/sys",
+            "/sys/devices",
+    };
+
     size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
 
     TestUeventdFile(ueventd_file,
                     {subsystems, sysfs_permissions, permissions, firmware_directories,
-                     external_firmware_handlers, true, uevent_socket_rcvbuf_size, true});
+                     external_firmware_handlers, parallel_restorecon_dirs, true,
+                     uevent_socket_rcvbuf_size, true});
 }
 
 // All of these lines are ill-formed, so test that there is 0 output.
@@ -366,6 +390,9 @@
 external_firmware_handler blah blah
 external_firmware_handler blah blah blah blah
 
+parallel_restorecon_dir
+parallel_restorecon_dir /sys /sys/devices
+
 )";
 
     TestUeventdFile(ueventd_file, {});
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index b33d46d..c8a183b 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -21,6 +21,7 @@
 cc_library {
     name: "libcrypto_utils",
     vendor_available: true,
+    ramdisk_available: true,
     recovery_available: true,
     vndk: {
         enabled: true,
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 86f68fb..a940b8c 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -15,6 +15,7 @@
     name: "libkeyutils",
     cflags: ["-Werror"],
     defaults: ["linux_bionic_supported"],
+    ramdisk_available: true,
     recovery_available: true,
     export_include_dirs: ["include/"],
     local_include_dirs: ["include/"],
diff --git a/libkeyutils/NOTICE b/libkeyutils/NOTICE
new file mode 100644
index 0000000..5828550
--- /dev/null
+++ b/libkeyutils/NOTICE
@@ -0,0 +1,25 @@
+Copyright (C) 2017 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/libmodprobe/Android.bp b/libmodprobe/Android.bp
index ba11dc9..525a880 100644
--- a/libmodprobe/Android.bp
+++ b/libmodprobe/Android.bp
@@ -8,6 +8,7 @@
         "-Werror",
     ],
     vendor_available: true,
+    ramdisk_available: true,
     recovery_available: true,
     srcs: [
         "libmodprobe.cpp",
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index bd94621..b5fa475 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -476,6 +476,33 @@
     },
 
     {
+      "Name": "SFMainPolicy",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "cpuset",
+            "Path": "system-background"
+          }
+        }
+      ]
+    },
+    {
+      "Name": "SFRenderEnginePolicy",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "cpuset",
+            "Path": "system-background"
+          }
+        }
+      ]
+    },
+
+    {
       "Name": "PerfBoost",
       "Actions": [
         {
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 4b11b1c..8697e9a 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -16,4 +16,4 @@
     capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE SYS_ADMIN
     file /dev/kmsg w
     file /proc/sysrq-trigger w
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
index b1f96a8..5d701fc 100644
--- a/llkd/llkd.rc
+++ b/llkd/llkd.rc
@@ -42,4 +42,4 @@
     capabilities KILL IPC_LOCK
     file /dev/kmsg w
     file /proc/sysrq-trigger w
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index ae21633..e98733a 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -45,4 +45,11 @@
     src: "etc/public.libraries.android.txt",
     filename: "public.libraries.txt",
     installable: false,
-}
\ No newline at end of file
+}
+
+// adb_debug.prop in debug ramdisk
+prebuilt_root {
+    name: "adb_debug.prop",
+    src: "adb_debug.prop",
+    debug_ramdisk: true,
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 99d8f9a..9b80575 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -210,15 +210,4 @@
 	$(hide) $(foreach lib,$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES), \
 		echo $(lib) >> $@;)
 
-#######################################
-# adb_debug.prop in debug ramdisk
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_debug.prop
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
-include $(BUILD_PREBUILT)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index c58f298..d62c41d 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -11,6 +11,9 @@
     "libsigchain.so",
     // TODO(b/122876336): Remove libpac.so once it's migrated to Webview
     "libpac.so",
+    // TODO(b/184872979): Remove libbinder_rpc_unstable.so once stablized and
+    // added to libbinder_ndk.
+    "libbinder_rpc_unstable.so",
     // TODO(b/120786417 or b/134659294): libicuuc.so
     // and libicui18n.so are kept for app compat.
     "libicui18n.so",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c6b74bc..81da0e8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -191,33 +191,6 @@
     chown system system /dev/cpuctl/camera-daemon/tasks
     chmod 0664 /dev/cpuctl/camera-daemon/tasks
 
-    # Android only use global RT throttling and doesn't use CONFIG_RT_GROUP_SCHED
-    # for RT group throttling. These values here are just to make sure RT threads
-    # can be migrated to those groups. These settings can be removed once we migrate
-    # to GKI kernel.
-    write /dev/cpuctl/cpu.rt_period_us 1000000
-    write /dev/cpuctl/cpu.rt_runtime_us 950000
-    # Surfaceflinger is in FG group so giving it a bit more
-    write /dev/cpuctl/foreground/cpu.rt_runtime_us 450000
-    write /dev/cpuctl/foreground/cpu.rt_period_us 1000000
-    write /dev/cpuctl/background/cpu.rt_runtime_us 50000
-    write /dev/cpuctl/background/cpu.rt_period_us 1000000
-    write /dev/cpuctl/top-app/cpu.rt_runtime_us 100000
-    write /dev/cpuctl/top-app/cpu.rt_period_us 1000000
-    write /dev/cpuctl/rt/cpu.rt_runtime_us 100000
-    write /dev/cpuctl/rt/cpu.rt_period_us 1000000
-    write /dev/cpuctl/system/cpu.rt_runtime_us 100000
-    write /dev/cpuctl/system/cpu.rt_period_us 1000000
-    write /dev/cpuctl/system-background/cpu.rt_runtime_us 50000
-    write /dev/cpuctl/system-background/cpu.rt_period_us 1000000
-    write /dev/cpuctl/nnapi-hal/cpu.rt_runtime_us 50000
-    write /dev/cpuctl/nnapi-hal/cpu.rt_period_us 1000000
-    write /dev/cpuctl/camera-daemon/cpu.rt_runtime_us 50000
-    write /dev/cpuctl/camera-daemon/cpu.rt_period_us 1000000
-
-    # Migrate root group to system subgroup
-    copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
-
     # Create an stune group for camera-specific processes
     mkdir /dev/stune/camera-daemon
     chown system system /dev/stune/camera-daemon
@@ -884,6 +857,8 @@
     # Create mirror directory for jit profiles
     mkdir /data_mirror/cur_profiles 0700 root root
     mount none /data/misc/profiles/cur /data_mirror/cur_profiles bind rec
+    mkdir /data_mirror/ref_profiles 0700 root root
+    mount none /data/misc/profiles/ref /data_mirror/ref_profiles bind rec
 
     mkdir /data/cache 0770 system cache encryption=Require
     mkdir /data/cache/recovery 0770 system cache
@@ -1265,6 +1240,7 @@
   umount /data_mirror/data_ce/null
   umount /data_mirror/data_de/null
   umount /data_mirror/cur_profiles
+  umount /data_mirror/ref_profiles
   umount /data_mirror
   remount_userdata
   start bootanim
@@ -1278,7 +1254,3 @@
 
 on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
   setprop sys.init.userspace_reboot.in_progress ""
-
-# Migrate tasks again in case kernel threads are created during boot
-on property:sys.boot_completed=1
-  copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 9469a48..0090841 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -12,5 +12,5 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks
+    task_profiles ProcessCapacityHigh
     critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 98dc088..63772bd 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -12,5 +12,5 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks
+    task_profiles ProcessCapacityHigh
     critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index 0614fad..7085743 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -3,6 +3,6 @@
     capabilities DAC_READ_SEARCH
     priority 10
     file /d/mmc0/mmc0:0001/ext_csd r
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
     user root
     group package_info
diff --git a/trusty/keymaster/3.0/service.cpp b/trusty/keymaster/3.0/service.cpp
index 0d8436e..b916c37 100644
--- a/trusty/keymaster/3.0/service.cpp
+++ b/trusty/keymaster/3.0/service.cpp
@@ -24,7 +24,7 @@
 int main() {
     ::android::hardware::configureRpcThreadpool(1, true);
     auto trustyKeymaster = new keymaster::TrustyKeymaster();
-    int err = trustyKeymaster->Initialize();
+    int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMASTER_3);
     if (err != 0) {
         LOG(FATAL) << "Could not initialize TrustyKeymaster (" << err << ")";
         return -1;
diff --git a/trusty/keymaster/4.0/service.cpp b/trusty/keymaster/4.0/service.cpp
index 96eb584..0e5144d 100644
--- a/trusty/keymaster/4.0/service.cpp
+++ b/trusty/keymaster/4.0/service.cpp
@@ -24,7 +24,7 @@
 int main() {
     ::android::hardware::configureRpcThreadpool(1, true);
     auto trustyKeymaster = new keymaster::TrustyKeymaster();
-    int err = trustyKeymaster->Initialize();
+    int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMASTER_4);
     if (err != 0) {
         LOG(FATAL) << "Could not initialize TrustyKeymaster (" << err << ")";
         return -1;
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6d24e84..58dfa94 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -80,6 +80,49 @@
     vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }
 
+cc_binary {
+    name: "android.hardware.security.keymint-service.trusty",
+    relative_install_path: "hw",
+    init_rc: ["keymint/android.hardware.security.keymint-service.trusty.rc"],
+    vintf_fragments: [
+        "keymint/android.hardware.security.keymint-service.trusty.xml",
+    ],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    local_include_dirs: [
+        "include",
+    ],
+    srcs: [
+        "TrustyKeymaster.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+        "keymint/TrustyKeyMintDevice.cpp",
+        "keymint/TrustyKeyMintOperation.cpp",
+        "keymint/TrustySecureClock.cpp",
+        "keymint/TrustySharedSecret.cpp",
+        "keymint/service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "lib_android_keymaster_keymint_utils",
+        "libbase",
+        "libbinder_ndk",
+        "libhardware",
+        "libkeymaster_messages",
+        "libkeymint",
+        "liblog",
+        "libtrusty",
+    ],
+    required: [
+        "RemoteProvisioner",
+        "android.hardware.hardware_keystore.xml",
+    ],
+}
+
 prebuilt_etc {
     name: "keymaster_soft_attestation_keys.xml",
     vendor: true,
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index 23e0433..ef5fc3f 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-#include <cutils/log.h>
+#define LOG_TAG "trusty_keymaster_hal"
+#include <android-base/logging.h>
+
 #include <keymaster/android_keymaster_messages.h>
 #include <keymaster/keymaster_configuration.h>
 #include <trusty_keymaster/TrustyKeymaster.h>
@@ -22,24 +24,28 @@
 
 namespace keymaster {
 
-int TrustyKeymaster::Initialize() {
+int TrustyKeymaster::Initialize(KmVersion version) {
     int err;
 
+    LOG(INFO) << "Initializing TrustyKeymaster as KmVersion: " << (int)version;
+
     err = trusty_keymaster_connect();
     if (err) {
-        ALOGE("Failed to connect to trusty keymaster %d", err);
+        LOG(ERROR) << "Failed to connect to trusty keymaster (1st try)" << err;
         return err;
     }
 
     // Try GetVersion2 first.
     GetVersion2Request versionReq;
+    versionReq.max_message_version = MessageVersion(version);
     GetVersion2Response versionRsp = GetVersion2(versionReq);
     if (versionRsp.error != KM_ERROR_OK) {
-        ALOGW("TA appears not to support GetVersion2, falling back (err = %d)", versionRsp.error);
+        LOG(WARNING) << "TA appears not to support GetVersion2, falling back (err = "
+                     << versionRsp.error << ")";
 
         err = trusty_keymaster_connect();
         if (err) {
-            ALOGE("Failed to connect to trusty keymaster %d", err);
+            LOG(FATAL) << "Failed to connect to trusty keymaster (2nd try) " << err;
             return err;
         }
 
@@ -47,13 +53,13 @@
         GetVersionResponse versionRsp;
         GetVersion(versionReq, &versionRsp);
         if (versionRsp.error != KM_ERROR_OK) {
-            ALOGE("Failed to get TA version %d", versionRsp.error);
+            LOG(FATAL) << "Failed to get TA version " << 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);
+                LOG(FATAL) << "Failed to negotiate message version " << error;
                 return -1;
             }
         }
@@ -69,7 +75,7 @@
     Configure(req, &rsp);
 
     if (rsp.error != KM_ERROR_OK) {
-        ALOGE("Failed to configure keymaster %d", rsp.error);
+        LOG(FATAL) << "Failed to configure keymaster " << rsp.error;
         return -1;
     }
 
@@ -87,7 +93,7 @@
     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);
+        LOG(ERROR) << "Cmd " << command << " returned error: " << err;
         rsp->error = err;
     }
 }
@@ -137,14 +143,19 @@
 
 void TrustyKeymaster::GenerateKey(const GenerateKeyRequest& request,
                                   GenerateKeyResponse* response) {
-    GenerateKeyRequest datedRequest(request.message_version);
-    datedRequest.key_description = request.key_description;
+    if (message_version_ < 4) {
+        // Pre-KeyMint we need to add TAG_CREATION_DATETIME if not provided by the caller.
+        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)));
+        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);
+    } else {
+        ForwardCommand(KM_GENERATE_KEY, request, response);
     }
-
-    ForwardCommand(KM_GENERATE_KEY, datedRequest, response);
 }
 
 void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
@@ -229,4 +240,16 @@
     return response;
 }
 
+EarlyBootEndedResponse TrustyKeymaster::EarlyBootEnded() {
+    EarlyBootEndedResponse response(message_version());
+    ForwardCommand(KM_EARLY_BOOT_ENDED, EarlyBootEndedRequest(message_version()), &response);
+    return response;
+}
+
+DeviceLockedResponse TrustyKeymaster::DeviceLocked(const DeviceLockedRequest& request) {
+    DeviceLockedResponse response(message_version());
+    ForwardCommand(KM_DEVICE_LOCKED, request, &response);
+    return response;
+}
+
 }  // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
new file mode 100644
index 0000000..5fd628f
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using ::std::optional;
+using ::std::shared_ptr;
+using ::std::vector;
+
+class TrustyKeyMintDevice : public BnKeyMintDevice {
+  public:
+    explicit TrustyKeyMintDevice(shared_ptr<TrustyKeymaster> impl) : impl_(std::move(impl)) {}
+    virtual ~TrustyKeyMintDevice() = default;
+
+    ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+    ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+    ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+                              const optional<AttestationKey>& attestationKey,
+                              KeyCreationResult* creationResult) override;
+
+    ScopedAStatus getKeyCharacteristics(const vector<uint8_t>& keyBlob,
+                                        const vector<uint8_t>& clientId,
+                                        const vector<uint8_t>& appData,
+                                        vector<KeyCharacteristics>* characteristics) override;
+
+    ScopedAStatus importKey(const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+                            const vector<uint8_t>& keyData,
+                            const optional<AttestationKey>& attestationKey,
+                            KeyCreationResult* creationResult) override;
+
+    ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+                                   const vector<uint8_t>& wrappingKeyBlob,
+                                   const vector<uint8_t>& maskingKey,
+                                   const vector<KeyParameter>& unwrappingParams,
+                                   int64_t passwordSid, int64_t biometricSid,
+                                   KeyCreationResult* creationResult) override;
+
+    ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                             const vector<KeyParameter>& upgradeParams,
+                             vector<uint8_t>* keyBlob) override;
+
+    ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+    ScopedAStatus deleteAllKeys() override;
+    ScopedAStatus destroyAttestationIds() override;
+
+    ScopedAStatus begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                        const vector<KeyParameter>& params,
+                        const optional<HardwareAuthToken>& authToken, BeginResult* result) override;
+
+    ScopedAStatus deviceLocked(bool passwordOnly,
+                               const optional<TimeStampToken>& timestampToken) override;
+    ScopedAStatus earlyBootEnded() override;
+
+    ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+                                               std::vector<uint8_t>* ephemeralKeyBlob) override;
+
+  protected:
+    std::shared_ptr<TrustyKeymaster> impl_;
+    SecurityLevel securityLevel_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h
new file mode 100644
index 0000000..65fd2f5
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+class TrustyKeyMintOperation : public BnKeyMintOperation {
+  public:
+    explicit TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,
+                                    keymaster_operation_handle_t opHandle);
+    virtual ~TrustyKeyMintOperation();
+
+    ScopedAStatus updateAad(const vector<uint8_t>& input,
+                            const optional<HardwareAuthToken>& authToken,
+                            const optional<TimeStampToken>& timestampToken) override;
+
+    ScopedAStatus update(const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
+                         const optional<TimeStampToken>& timestampToken,
+                         vector<uint8_t>* output) override;
+
+    ScopedAStatus finish(const optional<vector<uint8_t>>& input,        //
+                         const optional<vector<uint8_t>>& signature,    //
+                         const optional<HardwareAuthToken>& authToken,  //
+                         const optional<TimeStampToken>& timestampToken,
+                         const optional<vector<uint8_t>>& confirmationToken,
+                         vector<uint8_t>* output) override;
+
+    ScopedAStatus abort() override;
+
+  protected:
+    std::shared_ptr<TrustyKeymaster> impl_;
+    keymaster_operation_handle_t opHandle_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index bec2a2a..45ebf7f 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -25,7 +25,7 @@
   public:
     TrustyKeymaster();
     ~TrustyKeymaster();
-    int Initialize();
+    int Initialize(KmVersion version);
     void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
     void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
                              SupportedAlgorithmsResponse* response);
@@ -60,6 +60,8 @@
     ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
     VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
     GetVersion2Response GetVersion2(const GetVersion2Request& request);
+    EarlyBootEndedResponse EarlyBootEnded();
+    DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
 
     uint32_t message_version() const { return message_version_; }
 
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h b/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h
new file mode 100644
index 0000000..f077b27
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/secureclock/Timestamp.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::secureclock::trusty {
+
+class TrustySecureClock : public BnSecureClock {
+  public:
+    explicit TrustySecureClock(std::shared_ptr<::keymaster::TrustyKeymaster> impl)
+        : impl_(std::move(impl)) {}
+    ~TrustySecureClock() = default;
+    ::ndk::ScopedAStatus generateTimeStamp(int64_t challenge, TimeStampToken* token) override;
+
+  private:
+    std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+
+}  // namespace aidl::android::hardware::security::secureclock::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h b/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h
new file mode 100644
index 0000000..946f57e
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::sharedsecret::trusty {
+
+class TrustySharedSecret : public BnSharedSecret {
+  public:
+    explicit TrustySharedSecret(std::shared_ptr<::keymaster::TrustyKeymaster> impl)
+        : impl_(std::move(impl)) {}
+    ~TrustySharedSecret() = default;
+
+    ::ndk::ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override;
+    ::ndk::ScopedAStatus computeSharedSecret(const std::vector<SharedSecretParameters>& params,
+                                             std::vector<uint8_t>* sharingCheck) override;
+
+  private:
+    std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+}  // namespace aidl::android::hardware::security::sharedsecret::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 419c96f..a1229a3 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -54,6 +54,8 @@
     KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
     KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
     KM_GET_VERSION_2                = (28 << KEYMASTER_REQ_SHIFT),
+    KM_EARLY_BOOT_ENDED             = (29 << KEYMASTER_REQ_SHIFT),
+    KM_DEVICE_LOCKED                = (30 << KEYMASTER_REQ_SHIFT),
 
     // Bootloader/provisioning calls.
     KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
new file mode 100644
index 0000000..5f8524b
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
@@ -0,0 +1,324 @@
+/*
+
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <trusty_keymaster/TrustyKeyMintDevice.h>
+
+#define TAG TrustyKeyMintDevice
+#include <android-base/logging.h>
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+
+#include <KeyMintUtils.h>
+
+#include <trusty_keymaster/TrustyKeyMintOperation.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using keymaster::KeymasterBlob;
+using keymaster::KeymasterKeyBlob;
+using keymaster::TAG_APPLICATION_DATA;
+using keymaster::TAG_APPLICATION_ID;
+using keymaster::TAG_AUTH_TOKEN;
+using km_utils::authToken2AidlVec;
+using km_utils::kmBlob2vector;
+using km_utils::kmError2ScopedAStatus;
+using km_utils::kmParam2Aidl;
+using km_utils::KmParamSet;
+using km_utils::kmParamSet2Aidl;
+using km_utils::legacy_enum_conversion;
+
+namespace {
+
+auto kSecurityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
+
+KeyCharacteristics convertAuthSet(SecurityLevel securityLevel,
+                                  const keymaster::AuthorizationSet& authorizations) {
+    KeyCharacteristics retval{securityLevel, {}};
+    std::transform(authorizations.begin(), authorizations.end(),
+                   std::back_inserter(retval.authorizations), kmParam2Aidl);
+    return retval;
+}
+
+vector<KeyCharacteristics> convertKeyCharacteristics(const keymaster::AuthorizationSet& sw_enforced,
+                                                     const keymaster::AuthorizationSet& hw_enforced,
+                                                     bool includeKeystoreEnforced = true) {
+    KeyCharacteristics keyMintEnforced = convertAuthSet(kSecurityLevel, hw_enforced);
+    KeyCharacteristics keystoreEnforced = convertAuthSet(SecurityLevel::KEYSTORE, sw_enforced);
+
+    vector<KeyCharacteristics> retval;
+    retval.reserve(2);
+
+    if (!keyMintEnforced.authorizations.empty()) retval.push_back(std::move(keyMintEnforced));
+    if (includeKeystoreEnforced && !keystoreEnforced.authorizations.empty()) {
+        retval.push_back(std::move(keystoreEnforced));
+    }
+
+    return retval;
+}
+
+Certificate convertCertificate(const keymaster_blob_t& cert) {
+    return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
+}
+
+vector<Certificate> convertCertificateChain(const keymaster::CertificateChain& chain) {
+    vector<Certificate> retval;
+    std::transform(chain.begin(), chain.end(), std::back_inserter(retval), convertCertificate);
+    return retval;
+}
+
+void addClientAndAppData(const vector<uint8_t>& clientId, const vector<uint8_t>& appData,
+                         ::keymaster::AuthorizationSet* params) {
+    params->Clear();
+    if (clientId.size()) params->push_back(TAG_APPLICATION_ID, clientId.data(), clientId.size());
+    if (appData.size()) params->push_back(TAG_APPLICATION_DATA, appData.data(), appData.size());
+}
+
+}  // namespace
+
+ScopedAStatus TrustyKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+    info->versionNumber = 1;
+    info->securityLevel = kSecurityLevel;
+    info->keyMintName = "TrustyKeyMintDevice";
+    info->keyMintAuthorName = "Google";
+    info->timestampTokenRequired = false;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+    if (data.size() == 0) return ScopedAStatus::ok();
+    if (data.size() > 2048) {
+        LOG(DEBUG) << "Too-large entropy update of " << data.size() << " bytes.";
+        return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+    }
+
+    keymaster::AddEntropyRequest request(impl_->message_version());
+    request.random_data.Reinitialize(data.data(), data.size());
+
+    keymaster::AddEntropyResponse response(impl_->message_version());
+    impl_->AddRngEntropy(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
+                                               const optional<AttestationKey>& attestationKey,
+                                               KeyCreationResult* creationResult) {
+    keymaster::GenerateKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+    if (attestationKey) {
+        request.attestation_signing_key_blob =
+                KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+        request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+        request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                                               attestationKey->issuerSubjectName.size());
+    }
+
+    keymaster::GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics =
+            convertKeyCharacteristics(response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::getKeyCharacteristics(
+        const vector<uint8_t>& keyBlob,
+        const vector<uint8_t>& clientId,  //
+        const vector<uint8_t>& appData,   //
+        vector<KeyCharacteristics>* characteristics) {
+    keymaster::GetKeyCharacteristicsRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(clientId, appData, &request.additional_params);
+
+    keymaster::GetKeyCharacteristicsResponse response(impl_->message_version());
+    impl_->GetKeyCharacteristics(request, &response);
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+    *characteristics = convertKeyCharacteristics(response.unenforced, response.enforced,
+                                                 false /* includeKeystoreEnforced */);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
+                                             KeyFormat keyFormat, const vector<uint8_t>& keyData,
+                                             const optional<AttestationKey>& attestationKey,
+                                             KeyCreationResult* creationResult) {
+    keymaster::ImportKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+    request.key_format = legacy_enum_conversion(keyFormat);
+    request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+    if (attestationKey) {
+        request.attestation_signing_key_blob =
+                KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+        request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+        request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                                               attestationKey->issuerSubjectName.size());
+    }
+
+    keymaster::ImportKeyResponse response(impl_->message_version());
+    impl_->ImportKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics =
+            convertKeyCharacteristics(response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+                                                    const vector<uint8_t>& wrappingKeyBlob,  //
+                                                    const vector<uint8_t>& maskingKey,
+                                                    const vector<KeyParameter>& unwrappingParams,
+                                                    int64_t passwordSid,  //
+                                                    int64_t biometricSid,
+                                                    KeyCreationResult* creationResult) {
+    keymaster::ImportWrappedKeyRequest request(impl_->message_version());
+    request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+    request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+    request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+    request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+    request.password_sid = static_cast<uint64_t>(passwordSid);
+    request.biometric_sid = static_cast<uint64_t>(biometricSid);
+
+    keymaster::ImportWrappedKeyResponse response(impl_->message_version());
+    impl_->ImportWrappedKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics =
+            convertKeyCharacteristics(response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                                              const vector<KeyParameter>& upgradeParams,
+                                              vector<uint8_t>* keyBlob) {
+    keymaster::UpgradeKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+    request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+    keymaster::UpgradeKeyResponse response(impl_->message_version());
+    impl_->UpgradeKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    *keyBlob = kmBlob2vector(response.upgraded_key);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+    keymaster::DeleteKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+    keymaster::DeleteKeyResponse response(impl_->message_version());
+    impl_->DeleteKey(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::deleteAllKeys() {
+    // There's nothing to be done to delete software key blobs.
+    keymaster::DeleteAllKeysRequest request(impl_->message_version());
+    keymaster::DeleteAllKeysResponse response(impl_->message_version());
+    impl_->DeleteAllKeys(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::destroyAttestationIds() {
+    return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus TrustyKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                                         const vector<KeyParameter>& params,
+                                         const optional<HardwareAuthToken>& authToken,
+                                         BeginResult* result) {
+    keymaster::BeginOperationRequest request(impl_->message_version());
+    request.purpose = legacy_enum_conversion(purpose);
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    request.additional_params.Reinitialize(KmParamSet(params));
+
+    vector<uint8_t> vector_token = authToken2AidlVec(authToken);
+    request.additional_params.push_back(
+            TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()), vector_token.size());
+
+    keymaster::BeginOperationResponse response(impl_->message_version());
+    impl_->BeginOperation(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    result->params = kmParamSet2Aidl(response.output_params);
+    result->challenge = response.op_handle;
+    result->operation = ndk::SharedRefBase::make<TrustyKeyMintOperation>(impl_, response.op_handle);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::deviceLocked(
+        bool passwordOnly, const std::optional<secureclock::TimeStampToken>& timestampToken) {
+    keymaster::DeviceLockedRequest request(impl_->message_version());
+    request.passwordOnly = passwordOnly;
+    if (timestampToken.has_value()) {
+        request.token.challenge = timestampToken->challenge;
+        request.token.mac = {timestampToken->mac.data(), timestampToken->mac.size()};
+        request.token.timestamp = timestampToken->timestamp.milliSeconds;
+    }
+    keymaster::DeviceLockedResponse response = impl_->DeviceLocked(request);
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::earlyBootEnded() {
+    keymaster::EarlyBootEndedResponse response = impl_->EarlyBootEnded();
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral(
+        const std::vector<uint8_t>& storageKeyBlob, std::vector<uint8_t>* ephemeralKeyBlob) {
+    keymaster::ExportKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(storageKeyBlob.data(), storageKeyBlob.size());
+    request.key_format = KM_KEY_FORMAT_RAW;
+
+    keymaster::ExportKeyResponse response(impl_->message_version());
+    impl_->ExportKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+    if (response.key_data) {
+        *ephemeralKeyBlob = {response.key_data, response.key_data + response.key_data_length};
+    }
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
new file mode 100644
index 0000000..41a21e9
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <trusty_keymaster/TrustyKeyMintOperation.h>
+
+#define TAG TrustyKeyMintOperation
+#include <android-base/logging.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <KeyMintUtils.h>
+#include <keymaster/android_keymaster.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::TAG_ASSOCIATED_DATA;
+using ::keymaster::TAG_AUTH_TOKEN;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using km_utils::authToken2AidlVec;
+using km_utils::kmError2ScopedAStatus;
+using secureclock::TimeStampToken;
+
+TrustyKeyMintOperation::TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,
+                                               keymaster_operation_handle_t opHandle)
+    : impl_(std::move(implementation)), opHandle_(opHandle) {}
+
+TrustyKeyMintOperation::~TrustyKeyMintOperation() {
+    if (opHandle_ != 0) {
+        abort();
+    }
+}
+
+ScopedAStatus TrustyKeyMintOperation::updateAad(
+        const vector<uint8_t>& input, const optional<HardwareAuthToken>& /* authToken */,
+        const optional<TimeStampToken>& /* timestampToken */) {
+    UpdateOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
+
+    UpdateOperationResponse response(impl_->message_version());
+    impl_->UpdateOperation(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintOperation::update(const vector<uint8_t>& input,
+                                             const optional<HardwareAuthToken>& authToken,
+                                             const optional<TimeStampToken>& /* timestampToken */,
+                                             vector<uint8_t>* output) {
+    if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
+
+    UpdateOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    if (authToken) {
+        auto tokenAsVec(authToken2AidlVec(*authToken));
+        request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
+    }
+
+    size_t serialized_size = request.SerializedSize();
+    if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+        return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+    }
+
+    const uint8_t* input_pos = input.data();
+    const uint8_t* input_end = input.data() + input.size();
+    const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
+    output->clear();
+
+    while (input_pos < input_end) {
+        size_t to_send = std::min(max_chunk_size, static_cast<size_t>(input_end - input_pos));
+        LOG(DEBUG) << "update:  Sending " << to_send << " of " << (input_end - input_pos)
+                   << " bytes";
+        request.input.Reinitialize(input_pos, to_send);
+
+        UpdateOperationResponse response(impl_->message_version());
+        impl_->UpdateOperation(request, &response);
+        if (response.error != KM_ERROR_OK) {
+            opHandle_ = 0;  // Operation has ended, the handle is invalid.  This saves an abort().
+            return kmError2ScopedAStatus(response.error);
+        }
+
+        input_pos += response.input_consumed;
+        output->insert(output->end(), response.output.begin(), response.output.end());
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintOperation::finish(
+        const optional<vector<uint8_t>>& input,      //
+        const optional<vector<uint8_t>>& signature,  //
+        const optional<HardwareAuthToken>& authToken,
+        const optional<TimeStampToken>& /* timestampToken */,
+        const optional<vector<uint8_t>>& /* confirmationToken */, vector<uint8_t>* output) {
+    if (!output) {
+        return ScopedAStatus(AStatus_fromServiceSpecificError(
+                static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
+    }
+    output->clear();
+
+    FinishOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    if (signature) request.signature.Reinitialize(signature->data(), signature->size());
+    size_t serialized_size = request.SerializedSize();
+    if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+        return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+    }
+
+    if (input) {
+        const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
+
+        if (input->size() > max_chunk_size) {
+            LOG(DEBUG) << "Sending an update to process finish() data";
+            // Use update to process all but the last max_chunk_size bytes.
+            auto result = update({input->begin(), input->end() - max_chunk_size}, authToken,
+                                 std::nullopt /* timestampToken */, output);
+            if (!result.isOk()) return result;
+
+            // Process the last max_chunk_size with finish.
+            request.input.Reinitialize(input->data() + (input->size() - max_chunk_size),
+                                       max_chunk_size);
+        } else {
+            request.input.Reinitialize(input->data(), input->size());
+        }
+    }
+
+    FinishOperationResponse response(impl_->message_version());
+    impl_->FinishOperation(request, &response);
+    opHandle_ = 0;
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+    *output = {response.output.begin(), response.output.end()};
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintOperation::abort() {
+    AbortOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+
+    AbortOperationResponse response(impl_->message_version());
+    impl_->AbortOperation(request, &response);
+    opHandle_ = 0;
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/trusty/keymaster/keymint/TrustySecureClock.cpp b/trusty/keymaster/keymint/TrustySecureClock.cpp
new file mode 100644
index 0000000..fed5420
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustySecureClock.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <trusty_keymaster/TrustySecureClock.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <KeyMintUtils.h>
+
+namespace aidl::android::hardware::security::secureclock::trusty {
+
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+::ndk::ScopedAStatus TrustySecureClock::generateTimeStamp(int64_t challenge,
+                                                          TimeStampToken* token) {
+    keymaster::VerifyAuthorizationRequest request(impl_->message_version());
+    request.challenge = challenge;
+
+    auto response = impl_->VerifyAuthorization(request);
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+    token->challenge = response.token.challenge;
+    token->timestamp.milliSeconds = static_cast<int64_t>(response.token.timestamp);
+    token->mac = kmBlob2vector(response.token.mac);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::secureclock::trusty
diff --git a/trusty/keymaster/keymint/TrustySharedSecret.cpp b/trusty/keymaster/keymint/TrustySharedSecret.cpp
new file mode 100644
index 0000000..8109168
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustySharedSecret.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.
+ */
+
+#include <trusty_keymaster/TrustySharedSecret.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/android_keymaster.h>
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::sharedsecret::trusty {
+
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+::ndk::ScopedAStatus TrustySharedSecret::getSharedSecretParameters(SharedSecretParameters* params) {
+    auto response = impl_->GetHmacSharingParameters();
+    params->seed = kmBlob2vector(response.params.seed);
+    params->nonce = {std::begin(response.params.nonce), std::end(response.params.nonce)};
+    return kmError2ScopedAStatus(response.error);
+}
+
+::ndk::ScopedAStatus TrustySharedSecret::computeSharedSecret(
+        const std::vector<SharedSecretParameters>& params, std::vector<uint8_t>* sharingCheck) {
+    keymaster::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) {
+        request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()};
+        if (sizeof(request.params_array.params_array[i].nonce) != params[i].nonce.size()) {
+            return kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
+        }
+        memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+               params[i].nonce.size());
+    }
+
+    auto response = impl_->ComputeSharedHmac(request);
+    if (response.error == KM_ERROR_OK) *sharingCheck = kmBlob2vector(response.sharing_check);
+    return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::sharedsecret::trusty
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc
new file mode 100644
index 0000000..389af41
--- /dev/null
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc
@@ -0,0 +1,4 @@
+service vendor.keymint-trusty /vendor/bin/hw/android.hardware.security.keymint-service.trusty
+    class early_hal
+    user nobody
+    group drmrpc
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
new file mode 100644
index 0000000..0ab3d64
--- /dev/null
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -0,0 +1,14 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IKeyMintDevice/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.secureclock</name>
+        <fqname>ISecureClock/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.sharedsecret</name>
+        <fqname>ISharedSecret/default</fqname>
+    </hal>
+</manifest>
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
new file mode 100644
index 0000000..8f5f0f8
--- /dev/null
+++ b/trusty/keymaster/keymint/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021, 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.security.keymint-service.trusty"
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <trusty_keymaster/TrustyKeyMintDevice.h>
+#include <trusty_keymaster/TrustySecureClock.h>
+#include <trusty_keymaster/TrustySharedSecret.h>
+
+using aidl::android::hardware::security::keymint::trusty::TrustyKeyMintDevice;
+using aidl::android::hardware::security::secureclock::trusty::TrustySecureClock;
+using aidl::android::hardware::security::sharedsecret::trusty::TrustySharedSecret;
+
+template <typename T, class... Args>
+std::shared_ptr<T> addService(Args&&... args) {
+    std::shared_ptr<T> service = std::make_shared<T>(std::forward<Args>(args)...);
+    auto instanceName = std::string(T::descriptor) + "/default";
+    LOG(ERROR) << "Adding service instance: " << instanceName;
+    auto status = AServiceManager_addService(service->asBinder().get(), instanceName.c_str());
+    CHECK(status == STATUS_OK) << "Failed to add service " << instanceName;
+    return service;
+}
+
+int main() {
+    auto trustyKeymaster = std::make_shared<keymaster::TrustyKeymaster>();
+    int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMINT_1);
+    if (err != 0) {
+        LOG(FATAL) << "Could not initialize TrustyKeymaster for KeyMint (" << err << ")";
+        return -1;
+    }
+
+    // Zero threads seems like a useless pool but below we'll join this thread to it, increasing
+    // the pool size to 1.
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    auto keyMint = addService<TrustyKeyMintDevice>(trustyKeymaster);
+    auto secureClock = addService<TrustySecureClock>(trustyKeymaster);
+    auto sharedSecret = addService<TrustySharedSecret>(trustyKeymaster);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}