Merge "init.rc: drop spurious trailing ':'."
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 58a88b5..6b842b3 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -17,6 +17,7 @@
 #include "images.h"
 
 #include <limits.h>
+#include <sys/stat.h>
 
 #include <android-base/file.h>
 
@@ -27,12 +28,45 @@
 namespace android {
 namespace fs_mgr {
 
+using android::base::borrowed_fd;
 using android::base::unique_fd;
 
 #if defined(_WIN32)
 static const int O_NOFOLLOW = 0;
 #endif
 
+static bool IsEmptySuperImage(borrowed_fd fd) {
+    struct stat s;
+    if (fstat(fd.get(), &s) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " fstat failed";
+        return false;
+    }
+    if (s.st_size < LP_METADATA_GEOMETRY_SIZE) {
+        return false;
+    }
+
+    // Rewind back to the start, read the geometry struct.
+    LpMetadataGeometry geometry = {};
+    if (SeekFile64(fd.get(), 0, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed";
+        return false;
+    }
+    if (!android::base::ReadFully(fd, &geometry, sizeof(geometry))) {
+        PERROR << __PRETTY_FUNCTION__ << " read failed";
+        return false;
+    }
+    return geometry.magic == LP_METADATA_GEOMETRY_MAGIC;
+}
+
+bool IsEmptySuperImage(const std::string& file) {
+    unique_fd fd = GetControlFileOrOpen(file, O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " open failed";
+        return false;
+    }
+    return IsEmptySuperImage(fd);
+}
+
 std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
     if (SeekFile64(fd, 0, SEEK_SET) < 0) {
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 135a1b3..cd860cd 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -70,8 +70,15 @@
                           uint32_t slot_number);
 std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number);
 
+// Returns whether an image is an "empty" image or not. An empty image contains
+// only metadata. Unlike a flashed block device, there are no reserved bytes or
+// backup sections, and only one slot is stored (even if multiple slots are
+// supported). It is a format specifically for storing only metadata.
+bool IsEmptySuperImage(const std::string& file);
+
 // Read/Write logical partition metadata to an image file, for diagnostics or
-// flashing.
+// flashing. If no partition images are specified, the file will be in the
+// empty format.
 bool WriteToImageFile(const std::string& file, const LpMetadata& metadata, uint32_t block_size,
                       const std::map<std::string, std::string>& images, bool sparsify);
 bool WriteToImageFile(const std::string& file, const LpMetadata& metadata);
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index afcce8f..48c5c83 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -205,9 +205,9 @@
 #endif
 }
 
-base::unique_fd GetControlFileOrOpen(const char* path, int flags) {
+base::unique_fd GetControlFileOrOpen(std::string_view path, int flags) {
 #if defined(__ANDROID__)
-    int fd = android_get_control_file(path);
+    int fd = android_get_control_file(path.data());
     if (fd >= 0) {
         int newfd = TEMP_FAILURE_RETRY(dup(fd));
         if (newfd >= 0) {
@@ -216,7 +216,7 @@
         PERROR << "Cannot dup fd for already controlled file: " << path << ", reopening...";
     }
 #endif
-    return base::unique_fd(open(path, flags));
+    return base::unique_fd(open(path.data(), flags));
 }
 
 bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 25ab66b..0661769 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -21,6 +21,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <string>
+#include <string_view>
+
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
@@ -94,7 +97,7 @@
 // Call BLKROSET ioctl on fd so that fd is readonly / read-writable.
 bool SetBlockReadonly(int fd, bool readonly);
 
-::android::base::unique_fd GetControlFileOrOpen(const char* path, int flags);
+::android::base::unique_fd GetControlFileOrOpen(std::string_view path, int flags);
 
 // For Virtual A/B updates, modify |metadata| so that it can be written to |target_slot_number|.
 bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c744fe4..5813a2d 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -362,12 +362,18 @@
     }
 
     if (linear_sectors) {
+        std::string snap_dev;
+        if (!dm.GetDeviceString(snap_name, &snap_dev)) {
+            LOG(ERROR) << "Cannot determine major/minor for: " << snap_name;
+            return false;
+        }
+
         // Our stacking will looks like this:
         //     [linear, linear] ; to snapshot, and non-snapshot region of base device
         //     [snapshot-inner]
         //     [base device]   [cow]
         DmTable table;
-        table.Emplace<DmTargetLinear>(0, snapshot_sectors, *dev_path, 0);
+        table.Emplace<DmTargetLinear>(0, snapshot_sectors, snap_dev, 0);
         table.Emplace<DmTargetLinear>(snapshot_sectors, linear_sectors, base_device,
                                       snapshot_sectors);
         if (!dm.CreateDevice(name, table, dev_path, timeout_ms)) {
@@ -943,8 +949,8 @@
         return false;
     }
 
-    uint64_t num_sectors = status.snapshot_size / kSectorSize;
-    if (num_sectors * kSectorSize != status.snapshot_size) {
+    uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
+    if (snapshot_sectors * kSectorSize != status.snapshot_size) {
         LOG(ERROR) << "Snapshot " << name
                    << " size is not sector aligned: " << status.snapshot_size;
         return false;
@@ -972,10 +978,16 @@
                 return false;
             }
         }
-        uint64_t sectors = outer_table[0].spec.length + outer_table[1].spec.length;
-        if (sectors != num_sectors) {
-            LOG(ERROR) << "Outer snapshot " << name << " should have " << num_sectors
-                       << ", got: " << sectors;
+        if (outer_table[0].spec.length != snapshot_sectors) {
+            LOG(ERROR) << "dm-snapshot " << name << " should have " << snapshot_sectors
+                       << " sectors, got: " << outer_table[0].spec.length;
+            return false;
+        }
+        uint64_t expected_device_sectors = status.device_size / kSectorSize;
+        uint64_t actual_device_sectors = outer_table[0].spec.length + outer_table[1].spec.length;
+        if (expected_device_sectors != actual_device_sectors) {
+            LOG(ERROR) << "Outer device " << name << " should have " << expected_device_sectors
+                       << " sectors, got: " << actual_device_sectors;
             return false;
         }
     }
diff --git a/init/Android.bp b/init/Android.bp
index 52cd1ca..9c4b5b9 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -129,6 +129,7 @@
         "persistent_properties.cpp",
         "persistent_properties.proto",
         "property_service.cpp",
+        "property_service.proto",
         "property_type.cpp",
         "reboot.cpp",
         "reboot_utils.cpp",
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index c592c37..7e90e0c 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -110,3 +110,9 @@
 
 For boot time purposes, this is done in parallel across a set of child processes. `ueventd.cpp` in
 this directory contains documentation on how the parallelization is done.
+
+There is an option to parallelize the restorecon function during cold boot as well. This should only
+be done for devices that do not use genfscon, which is the recommended method for labeling sysfs
+nodes. To enable this option, use the below line in a ueventd.rc script:
+
+    parallel_restorecon enabled
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d2c73cb..21db8dc 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -80,6 +80,7 @@
 using namespace std::literals::string_literals;
 
 using android::base::Basename;
+using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 using android::fs_mgr::Fstab;
@@ -701,6 +702,15 @@
 }
 
 static Result<void> do_setprop(const BuiltinArguments& args) {
+    if (StartsWith(args[1], "ctl.")) {
+        return Error()
+               << "Cannot set ctl. properties from init; call the Service functions directly";
+    }
+    if (args[1] == kRestoreconProperty) {
+        return Error() << "Cannot set '" << kRestoreconProperty
+                       << "' from init; use the restorecon builtin directly";
+    }
+
     property_set(args[1], args[2]);
     return {};
 }
@@ -1016,7 +1026,20 @@
 }
 
 static Result<void> do_load_persist_props(const BuiltinArguments& args) {
-    load_persist_props();
+    // Devices with FDE have load_persist_props called twice; the first time when the temporary
+    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
+    // read persistent properties from the temporary /data partition or mark persistent properties
+    // as having been loaded during the first call, so we return in that case.
+    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+    if (crypto_state == "encrypted" && crypto_type == "block") {
+        static size_t num_calls = 0;
+        if (++num_calls == 1) return {};
+    }
+
+    SendLoadPersistentPropertiesMessage();
+
+    start_waiting_for_property("ro.persistent_properties.ready", "true");
     return {};
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index 1f74ab6..4e9a14f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -28,6 +28,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 #include <functional>
 #include <map>
 #include <memory>
@@ -60,6 +63,7 @@
 #include "mount_handler.h"
 #include "mount_namespace.h"
 #include "property_service.h"
+#include "proto_utils.h"
 #include "reboot.h"
 #include "reboot_utils.h"
 #include "security.h"
@@ -68,6 +72,7 @@
 #include "service.h"
 #include "service_parser.h"
 #include "sigchld_handler.h"
+#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::chrono_literals;
@@ -89,6 +94,7 @@
 static char qemu[32];
 
 static int signal_fd = -1;
+static int property_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
@@ -614,6 +620,60 @@
                                 selinux_start_time_ns));
 }
 
+void SendLoadPersistentPropertiesMessage() {
+    auto init_message = InitMessage{};
+    init_message.set_load_persistent_properties(true);
+    if (auto result = SendMessage(property_fd, init_message); !result) {
+        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+    }
+}
+
+void SendStopSendingMessagesMessage() {
+    auto init_message = InitMessage{};
+    init_message.set_stop_sending_messages(true);
+    if (auto result = SendMessage(property_fd, init_message); !result) {
+        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+    }
+}
+
+static void HandlePropertyFd() {
+    auto message = ReadMessage(property_fd);
+    if (!message) {
+        LOG(ERROR) << "Could not read message from property service: " << message.error();
+        return;
+    }
+
+    auto property_message = PropertyMessage{};
+    if (!property_message.ParseFromString(*message)) {
+        LOG(ERROR) << "Could not parse message from property service";
+        return;
+    }
+
+    switch (property_message.msg_case()) {
+        case PropertyMessage::kControlMessage: {
+            auto& control_message = property_message.control_message();
+            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
+                                                control_message.pid());
+
+            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+            if (control_message.has_fd()) {
+                int fd = control_message.fd();
+                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
+                close(fd);
+            }
+            break;
+        }
+        case PropertyMessage::kChangedMessage: {
+            auto& changed_message = property_message.changed_message();
+            property_changed(changed_message.name(), changed_message.value());
+            break;
+        }
+        default:
+            LOG(ERROR) << "Unknown message type from property service: "
+                       << property_message.msg_case();
+    }
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -685,7 +745,12 @@
     UmountDebugRamdisk();
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
-    StartPropertyService(&epoll);
+
+    StartPropertyService(&property_fd);
+    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
+        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
+    }
+
     MountHandler mount_handler(&epoll);
     set_usb_controller();
 
diff --git a/init/init.h b/init/init.h
index cfc28f1..8ac52e2 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,16 +31,15 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 Parser CreateServiceOnlyParser(ServiceList& service_list);
 
-bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
-
-void property_changed(const std::string& name, const std::string& value);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
 
 void ResetWaitForProp();
 
+void SendLoadPersistentPropertiesMessage();
+void SendStopSendingMessagesMessage();
+
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 3408ff3..c18decc 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,6 +42,7 @@
 #include <map>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <queue>
 #include <thread>
 #include <vector>
@@ -63,8 +64,10 @@
 #include "init.h"
 #include "persistent_properties.h"
 #include "property_type.h"
+#include "proto_utils.h"
 #include "selinux.h"
 #include "subcontext.h"
+#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::literals;
@@ -76,6 +79,7 @@
 using android::base::StringPrintf;
 using android::base::Timer;
 using android::base::Trim;
+using android::base::unique_fd;
 using android::base::WriteStringToFile;
 using android::properties::BuildTrie;
 using android::properties::ParsePropertyInfoFile;
@@ -85,18 +89,13 @@
 namespace android {
 namespace init {
 
-static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
-
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
+static int init_socket = -1;
 
 static PropertyInfoAreaFile property_info_area;
 
-uint32_t InitPropertySet(const std::string& name, const std::string& value);
-
-uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
-
 void CreateSerializedPropertyInfo();
 
 struct PropertyAuditData {
@@ -164,6 +163,17 @@
     return has_access;
 }
 
+static void SendPropertyChanged(const std::string& name, const std::string& value) {
+    auto property_msg = PropertyMessage{};
+    auto* changed_message = property_msg.mutable_changed_message();
+    changed_message->set_name(name);
+    changed_message->set_value(value);
+
+    if (auto result = SendMessage(init_socket, property_msg); !result) {
+        LOG(ERROR) << "Failed to send property changed message: " << result.error();
+    }
+}
+
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -199,7 +209,11 @@
     if (persistent_properties_loaded && StartsWith(name, "persist.")) {
         WritePersistentProperty(name, value);
     }
-    property_changed(name, value);
+    // If init hasn't started its main loop, then it won't be handling property changed messages
+    // anyway, so there's no need to try to send them.
+    if (init_socket != -1) {
+        SendPropertyChanged(name, value);
+    }
     return PROP_SUCCESS;
 }
 
@@ -239,35 +253,10 @@
     bool thread_started_ = false;
 };
 
-uint32_t InitPropertySet(const std::string& name, const std::string& value) {
-    if (StartsWith(name, "ctl.")) {
-        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
-                      "functions directly";
-        return PROP_ERROR_INVALID_NAME;
-    }
-    if (name == kRestoreconProperty) {
-        LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty
-                   << "' from init; use the restorecon builtin directly";
-        return PROP_ERROR_INVALID_NAME;
-    }
-
-    uint32_t result = 0;
-    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
-    std::string error;
-    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
-    if (result != PROP_SUCCESS) {
-        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
-    }
-
-    return result;
-}
-
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
 
-    ~SocketConnection() { close(socket_); }
-
     bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
         return RecvFully(value, sizeof(*value), timeout_ms);
     }
@@ -304,6 +293,9 @@
     }
 
     bool SendUint32(uint32_t value) {
+        if (!socket_.ok()) {
+            return true;
+        }
         int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
         return result == sizeof(value);
     }
@@ -318,7 +310,7 @@
         return true;
     }
 
-    int socket() { return socket_; }
+    [[nodiscard]] int Release() { return socket_.release(); }
 
     const ucred& cred() { return cred_; }
 
@@ -389,12 +381,46 @@
         return bytes_left == 0;
     }
 
-    int socket_;
+    unique_fd socket_;
     ucred cred_;
 
     DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
 };
 
+static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
+                                   SocketConnection* socket, std::string* error) {
+    if (init_socket == -1) {
+        *error = "Received control message after shutdown, ignoring";
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
+
+    auto property_msg = PropertyMessage{};
+    auto* control_message = property_msg.mutable_control_message();
+    control_message->set_msg(msg);
+    control_message->set_name(name);
+    control_message->set_pid(pid);
+
+    // We must release the fd before sending it to init, otherwise there will be a race with init.
+    // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
+    int fd = -1;
+    if (socket != nullptr) {
+        fd = socket->Release();
+        control_message->set_fd(fd);
+    }
+
+    if (auto result = SendMessage(init_socket, property_msg); !result) {
+        // We've already released the fd above, so if we fail to send the message to init, we need
+        // to manually free it here.
+        if (fd != -1) {
+            close(fd);
+        }
+        *error = "Failed to send control message: " + result.error().message();
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
+
+    return PROP_SUCCESS;
+}
+
 bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                                const std::string& source_context, const ucred& cr) {
     // We check the legacy method first but these properties are dontaudit, so we only log an audit
@@ -462,15 +488,14 @@
 
 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr, std::string* error) {
+                           const std::string& source_context, const ucred& cr,
+                           SocketConnection* socket, std::string* error) {
     if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
         return ret;
     }
 
     if (StartsWith(name, "ctl.")) {
-        return HandleControlMessage(name.c_str() + 4, value, cr.pid)
-                       ? PROP_SUCCESS
-                       : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+        return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
     }
 
     // sys.powerctl is a special property that is used to make the device reboot.  We want to log
@@ -501,6 +526,20 @@
     return PropertySet(name, value, error);
 }
 
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+    uint32_t result = 0;
+    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+    std::string error;
+    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, nullptr, &error);
+    if (result != PROP_SUCCESS) {
+        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
+    }
+
+    return result;
+}
+
+uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
+
 static void handle_property_set_fd() {
     static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
 
@@ -549,7 +588,8 @@
 
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, &error);
+        uint32_t result =
+                HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -577,7 +617,7 @@
 
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result = HandlePropertySet(name, value, source_context, cr, &error);
+        uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -741,33 +781,6 @@
     }
 }
 
-/* When booting an encrypted system, /data is not mounted when the
- * property service is started, so any properties stored there are
- * not loaded.  Vold triggers init to load these properties once it
- * has mounted /data.
- */
-void load_persist_props(void) {
-    // Devices with FDE have load_persist_props called twice; the first time when the temporary
-    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
-    // read persistent properties from the temporary /data partition or mark persistent properties
-    // as having been loaded during the first call, so we return in that case.
-    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
-    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
-    if (crypto_state == "encrypted" && crypto_type == "block") {
-        static size_t num_calls = 0;
-        if (++num_calls == 1) return;
-    }
-
-    load_override_properties();
-    /* Read persistent properties after all default values have been loaded. */
-    auto persistent_properties = LoadPersistentProperties();
-    for (const auto& persistent_property_record : persistent_properties.properties()) {
-        property_set(persistent_property_record.name(), persistent_property_record.value());
-    }
-    persistent_properties_loaded = true;
-    property_set("ro.persistent_properties.ready", "true");
-}
-
 // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
 // set, derive them from ro.product.${partition}.* properties
 static void property_initialize_ro_product_props() {
@@ -985,21 +998,92 @@
     selinux_android_restorecon(kPropertyInfosPath, 0);
 }
 
-void StartPropertyService(Epoll* epoll) {
+static void HandleInitSocket() {
+    auto message = ReadMessage(init_socket);
+    if (!message) {
+        LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
+        return;
+    }
+
+    auto init_message = InitMessage{};
+    if (!init_message.ParseFromString(*message)) {
+        LOG(ERROR) << "Could not parse message from init";
+        return;
+    }
+
+    switch (init_message.msg_case()) {
+        case InitMessage::kLoadPersistentProperties: {
+            load_override_properties();
+            // Read persistent properties after all default values have been loaded.
+            auto persistent_properties = LoadPersistentProperties();
+            for (const auto& persistent_property_record : persistent_properties.properties()) {
+                InitPropertySet(persistent_property_record.name(),
+                                persistent_property_record.value());
+            }
+            InitPropertySet("ro.persistent_properties.ready", "true");
+            persistent_properties_loaded = true;
+            break;
+        }
+        case InitMessage::kStopSendingMessages: {
+            init_socket = -1;
+            break;
+        }
+        default:
+            LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
+    }
+}
+
+static void PropertyServiceThread() {
+    Epoll epoll;
+    if (auto result = epoll.Open(); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    while (true) {
+        auto pending_functions = epoll.Wait(std::nullopt);
+        if (!pending_functions) {
+            LOG(ERROR) << pending_functions.error();
+        } else {
+            for (const auto& function : *pending_functions) {
+                (*function)();
+            }
+        }
+    }
+}
+
+void StartPropertyService(int* epoll_socket) {
     property_set("ro.property_service.version", "2");
 
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
+        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
+    }
+    *epoll_socket = sockets[0];
+    init_socket = sockets[1];
+
     if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    false, 0666, 0, 0, {})) {
         property_set_fd = *result;
     } else {
-        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
+        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
 
-    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
-        PLOG(FATAL) << result.error();
-    }
+    std::thread{PropertyServiceThread}.detach();
+
+    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
+        android::base::SetProperty(key, value);
+        return 0;
+    };
 }
 
 }  // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 7f9f844..8f7d8d9 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,17 +25,15 @@
 namespace android {
 namespace init {
 
+static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
+
 bool CanReadProperty(const std::string& source_context, const std::string& name);
 
 extern uint32_t (*property_set)(const std::string& name, const std::string& value);
 
-uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr, std::string* error);
-
 void property_init();
 void property_load_boot_defaults(bool load_debug_prop);
-void load_persist_props();
-void StartPropertyService(Epoll* epoll);
+void StartPropertyService(int* epoll_socket);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
new file mode 100644
index 0000000..ea454d4
--- /dev/null
+++ b/init/property_service.proto
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+message PropertyMessage {
+    message ControlMessage {
+        optional string msg = 1;
+        optional string name = 2;
+        optional int32 pid = 3;
+        optional int32 fd = 4;
+    }
+
+    message ChangedMessage {
+        optional string name = 1;
+        optional string value = 2;
+    }
+
+    oneof msg {
+        ControlMessage control_message = 1;
+        ChangedMessage changed_message = 2;
+    };
+}
+
+message InitMessage {
+    oneof msg {
+        bool load_persistent_properties = 1;
+        bool stop_sending_messages = 2;
+    };
+}
diff --git a/init/proto_utils.h b/init/proto_utils.h
new file mode 100644
index 0000000..93a7d57
--- /dev/null
+++ b/init/proto_utils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 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 <sys/socket.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "result.h"
+
+namespace android {
+namespace init {
+
+constexpr size_t kBufferSize = 4096;
+
+inline Result<std::string> ReadMessage(int socket) {
+    char buffer[kBufferSize] = {};
+    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
+    if (result == 0) {
+        return Error();
+    } else if (result < 0) {
+        return ErrnoError();
+    }
+    return std::string(buffer, result);
+}
+
+template <typename T>
+Result<void> SendMessage(int socket, const T& message) {
+    std::string message_string;
+    if (!message.SerializeToString(&message_string)) {
+        return Error() << "Unable to serialize message";
+    }
+
+    if (message_string.size() > kBufferSize) {
+        return Error() << "Serialized message too long to send";
+    }
+
+    if (auto result =
+                TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
+        result != static_cast<long>(message_string.size())) {
+        return ErrnoError() << "send() failed to send message contents";
+    }
+    return {};
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b0b5b54..786a084 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -730,6 +730,12 @@
         s->UnSetExec();
     }
 
+    // We no longer process messages about properties changing coming from property service, so we
+    // need to tell property service to stop sending us these messages, otherwise it'll fill the
+    // buffers and block indefinitely, causing future property sets, including those that init makes
+    // during shutdown in Service::NotifyStateChange() to also block indefinitely.
+    SendStopSendingMessagesMessage();
+
     return true;
 }
 
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 00f91d8..ec93b58 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -18,16 +18,17 @@
 
 #include <fcntl.h>
 #include <poll.h>
-#include <sys/socket.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <selinux/android.h>
 
 #include "action.h"
 #include "builtins.h"
+#include "proto_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -59,45 +60,6 @@
 
 namespace {
 
-constexpr size_t kBufferSize = 4096;
-
-Result<std::string> ReadMessage(int socket) {
-    char buffer[kBufferSize] = {};
-    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
-    if (result == 0) {
-        return Error();
-    } else if (result < 0) {
-        return ErrnoError();
-    }
-    return std::string(buffer, result);
-}
-
-template <typename T>
-Result<void> SendMessage(int socket, const T& message) {
-    std::string message_string;
-    if (!message.SerializeToString(&message_string)) {
-        return Error() << "Unable to serialize message";
-    }
-
-    if (message_string.size() > kBufferSize) {
-        return Error() << "Serialized message too long to send";
-    }
-
-    if (auto result =
-            TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
-        result != static_cast<long>(message_string.size())) {
-        return ErrnoError() << "send() failed to send message contents";
-    }
-    return {};
-}
-
-std::vector<std::pair<std::string, std::string>> properties_to_set;
-
-uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
-    properties_to_set.emplace_back(name, value);
-    return 0;
-}
-
 class SubcontextProcess {
   public:
     SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
@@ -131,14 +93,6 @@
         result = RunBuiltinFunction(map_result->function, args, context_);
     }
 
-    for (const auto& [name, value] : properties_to_set) {
-        auto property = reply->add_properties_to_set();
-        property->set_name(name);
-        property->set_value(value);
-    }
-
-    properties_to_set.clear();
-
     if (result) {
         reply->set_success(true);
     } else {
@@ -224,7 +178,10 @@
 
     SelabelInitialize();
 
-    property_set = SubcontextPropertySet;
+    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
+        android::base::SetProperty(key, value);
+        return 0;
+    };
 
     auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
     subcontext_process.MainLoop();
@@ -311,15 +268,6 @@
         return subcontext_reply.error();
     }
 
-    for (const auto& property : subcontext_reply->properties_to_set()) {
-        ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
-        std::string error;
-        if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
-            LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
-                       << property.value() << "': " << error;
-        }
-    }
-
     if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
         auto& failure = subcontext_reply->failure();
         return ResultError(failure.error_string(), failure.error_errno());
diff --git a/init/subcontext.proto b/init/subcontext.proto
index c31f4fb..e68115e 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,10 +38,4 @@
         Failure failure = 2;
         ExpandArgsReply expand_args_reply = 3;
     }
-
-    message PropertyToSet {
-        optional string name = 1;
-        optional string value = 2;
-    }
-    repeated PropertyToSet properties_to_set = 4;
 }
\ No newline at end of file
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index cffc1b9..6741e2a 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -113,10 +113,12 @@
 class ColdBoot {
   public:
     ColdBoot(UeventListener& uevent_listener,
-             std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers)
+             std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers,
+             bool enable_parallel_restorecon)
         : uevent_listener_(uevent_listener),
           uevent_handlers_(uevent_handlers),
-          num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
+          num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4),
+          enable_parallel_restorecon_(enable_parallel_restorecon) {}
 
     void Run();
 
@@ -132,6 +134,8 @@
     std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers_;
 
     unsigned int num_handler_subprocesses_;
+    bool enable_parallel_restorecon_;
+
     std::vector<Uevent> uevent_queue_;
 
     std::set<pid_t> subprocess_pids_;
@@ -155,7 +159,6 @@
 
         selinux_android_restorecon(dir.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
     }
-    _exit(EXIT_SUCCESS);
 }
 
 void ColdBoot::GenerateRestoreCon(const std::string& directory) {
@@ -195,7 +198,10 @@
 
         if (pid == 0) {
             UeventHandlerMain(i, num_handler_subprocesses_);
-            RestoreConHandler(i, num_handler_subprocesses_);
+            if (enable_parallel_restorecon_) {
+                RestoreConHandler(i, num_handler_subprocesses_);
+            }
+            _exit(EXIT_SUCCESS);
         }
 
         subprocess_pids_.emplace(pid);
@@ -240,14 +246,20 @@
 
     RegenerateUevents();
 
-    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 (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");
+    }
 
     ForkSubProcesses();
 
+    if (!enable_parallel_restorecon_) {
+        selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    }
+
     WaitForSubProcesses();
 
     android::base::SetProperty(kColdBootDoneProp, "true");
@@ -293,7 +305,8 @@
     UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size);
 
     if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {
-        ColdBoot cold_boot(uevent_listener, uevent_handlers);
+        ColdBoot cold_boot(uevent_listener, uevent_handlers,
+                           ueventd_configuration.enable_parallel_restorecon);
         cold_boot.Run();
     }
 
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 8ee0cce..1ca1715 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -88,18 +88,17 @@
     return {};
 }
 
-Result<void> ParseModaliasHandlingLine(std::vector<std::string>&& args,
-                                       bool* enable_modalias_handling) {
+Result<void> ParseEnabledDisabledLine(std::vector<std::string>&& args, bool* feature) {
     if (args.size() != 2) {
-        return Error() << "modalias_handling lines take exactly one parameter";
+        return Error() << args[0] << " lines take exactly one parameter";
     }
 
     if (args[1] == "enabled") {
-        *enable_modalias_handling = true;
+        *feature = true;
     } else if (args[1] == "disabled") {
-        *enable_modalias_handling = false;
+        *feature = false;
     } else {
-        return Error() << "modalias_handling takes either 'enabled' or 'disabled' as a parameter";
+        return Error() << args[0] << " takes either 'enabled' or 'disabled' as a parameter";
     }
 
     return {};
@@ -213,11 +212,14 @@
                                std::bind(ParseFirmwareDirectoriesLine, _1,
                                          &ueventd_configuration.firmware_directories));
     parser.AddSingleLineParser("modalias_handling",
-                               std::bind(ParseModaliasHandlingLine, _1,
+                               std::bind(ParseEnabledDisabledLine, _1,
                                          &ueventd_configuration.enable_modalias_handling));
     parser.AddSingleLineParser("uevent_socket_rcvbuf_size",
                                std::bind(ParseUeventSocketRcvbufSizeLine, _1,
                                          &ueventd_configuration.uevent_socket_rcvbuf_size));
+    parser.AddSingleLineParser("parallel_restorecon",
+                               std::bind(ParseEnabledDisabledLine, _1,
+                                         &ueventd_configuration.enable_parallel_restorecon));
 
     for (const auto& config : configs) {
         parser.ParseConfig(config);
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index d476dec..b54dba8 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_UEVENTD_PARSER_H
-#define _INIT_UEVENTD_PARSER_H
+#pragma once
 
 #include <string>
 #include <vector>
@@ -32,11 +31,10 @@
     std::vector<std::string> firmware_directories;
     bool enable_modalias_handling = false;
     size_t uevent_socket_rcvbuf_size = 0;
+    bool enable_parallel_restorecon = false;
 };
 
 UeventdConfiguration ParseConfig(const std::vector<std::string>& configs);
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index 9c1cedf..885e79d 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -147,6 +147,24 @@
     TestUeventdFile(ueventd_file, {{}, {}, {}, {}, false, 8 * 1024 * 1024});
 }
 
+TEST(ueventd_parser, EnabledDisabledLines) {
+    auto ueventd_file = R"(
+modalias_handling enabled
+parallel_restorecon enabled
+modalias_handling disabled
+)";
+
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, false, 0, true});
+
+    auto ueventd_file2 = R"(
+parallel_restorecon enabled
+modalias_handling enabled
+parallel_restorecon disabled
+)";
+
+    TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, true, 0, false});
+}
+
 TEST(ueventd_parser, AllTogether) {
     auto ueventd_file = R"(
 
@@ -179,6 +197,8 @@
 firmware_directories /more
 
 uevent_socket_rcvbuf_size 6M
+modalias_handling enabled
+parallel_restorecon enabled
 
 #ending comment
 )";
@@ -211,7 +231,7 @@
     size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
 
     TestUeventdFile(ueventd_file, {subsystems, sysfs_permissions, permissions, firmware_directories,
-                                   false, uevent_socket_rcvbuf_size});
+                                   true, uevent_socket_rcvbuf_size, true});
 }
 
 // All of these lines are ill-formed, so test that there is 0 output.
@@ -230,6 +250,13 @@
 
 subsystem #no name
 
+modalias_handling
+modalias_handling enabled enabled
+modalias_handling blah
+
+parallel_restorecon
+parallel_restorecon enabled enabled
+parallel_restorecon blah
 )";
 
     TestUeventdFile(ueventd_file, {});
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index f8d5058..e000a00 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -79,7 +79,7 @@
       index_++;
       return *this;
     }
-    iterator& operator++(int increment) {
+    const iterator operator++(int increment) {
       index_ += increment;
       return *this;
     }
@@ -87,7 +87,7 @@
       index_--;
       return *this;
     }
-    iterator& operator--(int decrement) {
+    const iterator operator--(int decrement) {
       index_ -= decrement;
       return *this;
     }
diff --git a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
index b5fc6bf..ec2ba12 100644
--- a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
+++ b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "android.hardware.keymaster@4.0-impl.trusty"
 
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 #include <authorization_set.h>
 #include <cutils/log.h>
 #include <keymaster/android_keymaster_messages.h>
@@ -46,6 +47,9 @@
 using ::keymaster::UpdateOperationResponse;
 using ::keymaster::ng::Tag;
 
+typedef ::android::hardware::keymaster::V3_0::Tag Tag3;
+using ::android::hardware::keymaster::V4_0::Constants;
+
 namespace keymaster {
 namespace V4_0 {
 namespace {
@@ -79,6 +83,45 @@
     return keymaster_tag_get_type(tag);
 }
 
+/*
+ * injectAuthToken translates a KM4 authToken into a legacy AUTH_TOKEN tag
+ *
+ * Currently, system/keymaster's reference implementation only accepts this
+ * method for passing an auth token, so until that changes we need to
+ * translate to the old format.
+ */
+inline hidl_vec<KeyParameter> injectAuthToken(const hidl_vec<KeyParameter>& keyParamsBase,
+                                              const HardwareAuthToken& authToken) {
+    std::vector<KeyParameter> keyParams(keyParamsBase);
+    const size_t mac_len = static_cast<size_t>(Constants::AUTH_TOKEN_MAC_LENGTH);
+    /*
+     * mac.size() == 0 indicates no token provided, so we should not copy.
+     * mac.size() != mac_len means it is incompatible with the old
+     *   hw_auth_token_t structure. This is forbidden by spec, but to be safe
+     *   we only copy if mac.size() == mac_len, e.g. there is an authToken
+     *   with a hw_auth_token_t compatible MAC.
+     */
+    if (authToken.mac.size() == mac_len) {
+        KeyParameter p;
+        p.tag = static_cast<Tag>(Tag3::AUTH_TOKEN);
+        p.blob.resize(sizeof(hw_auth_token_t));
+
+        hw_auth_token_t* auth_token = reinterpret_cast<hw_auth_token_t*>(p.blob.data());
+        auth_token->version = 0;
+        auth_token->challenge = authToken.challenge;
+        auth_token->user_id = authToken.userId;
+        auth_token->authenticator_id = authToken.authenticatorId;
+        auth_token->authenticator_type =
+                htobe32(static_cast<uint32_t>(authToken.authenticatorType));
+        auth_token->timestamp = htobe64(authToken.timestamp);
+        static_assert(mac_len == sizeof(auth_token->hmac));
+        memcpy(auth_token->hmac, authToken.mac.data(), mac_len);
+        keyParams.push_back(p);
+    }
+
+    return hidl_vec<KeyParameter>(std::move(keyParams));
+}
+
 class KmParamSet : public keymaster_key_param_set_t {
   public:
     KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
@@ -472,11 +515,11 @@
 Return<void> TrustyKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
                                            const hidl_vec<KeyParameter>& inParams,
                                            const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
-    (void)authToken;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     BeginOperationRequest request;
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     BeginOperationResponse response;
     impl_->BeginOperation(request, &response);
@@ -496,16 +539,16 @@
                                             const HardwareAuthToken& authToken,
                                             const VerificationToken& verificationToken,
                                             update_cb _hidl_cb) {
-    (void)authToken;
     (void)verificationToken;
     UpdateOperationRequest request;
     UpdateOperationResponse response;
     hidl_vec<KeyParameter> resultParams;
     hidl_vec<uint8_t> resultBlob;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     uint32_t resultConsumed = 0;
 
     request.op_handle = operationHandle;
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     size_t inp_size = input.size();
     size_t ser_size = request.SerializedSize();
@@ -537,13 +580,13 @@
                                             const HardwareAuthToken& authToken,
                                             const VerificationToken& verificationToken,
                                             finish_cb _hidl_cb) {
-    (void)authToken;
     (void)verificationToken;
     FinishOperationRequest request;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.signature.Reinitialize(signature.data(), signature.size());
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     FinishOperationResponse response;
     impl_->FinishOperation(request, &response);
diff --git a/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml b/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml
new file mode 100644
index 0000000..aa30707
--- /dev/null
+++ b/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.keymaster</name>
+        <transport>hwbinder</transport>
+        <version>4.0</version>
+        <interface>
+        <name>IKeymasterDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 3a9beaf..f32a69e 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -136,4 +136,6 @@
         "libkeymaster4",
         "android.hardware.keymaster@4.0"
     ],
+
+    vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }