Merge "Allow loading zip at an offset in fd" into rvc-dev
diff --git a/adb/Android.bp b/adb/Android.bp
index a26017f..2f71945 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -298,6 +298,7 @@
         "client/fastdeploycallbacks.cpp",
         "client/incremental.cpp",
         "client/incremental_server.cpp",
+        "client/incremental_utils.cpp",
         "shell_service_protocol.cpp",
     ],
 
@@ -429,7 +430,7 @@
     },
 }
 
-cc_library_static {
+cc_library {
     name: "libadbd_services",
     defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
@@ -464,6 +465,7 @@
         "libbase",
         "libcrypto",
         "libcrypto_utils",
+        "libcutils_sockets",
         "liblog",
     ],
 
@@ -515,6 +517,7 @@
         "libadb_tls_connection",
         "libadbd_auth",
         "libadbd_fs",
+        "libadbd_services",
         "libasyncio",
         "libbase",
         "libcrypto",
@@ -533,7 +536,6 @@
     },
 
     static_libs: [
-        "libadbd_services",
         "libcutils_sockets",
         "libdiagnose_usb",
         "libmdnssd",
@@ -575,10 +577,8 @@
         "libcrypto_utils",
         "libcutils_sockets",
         "libdiagnose_usb",
-        "liblog",
         "libmdnssd",
         "libminijail",
-        "libselinux",
         "libssl",
     ],
 
@@ -588,6 +588,8 @@
         "libadbd_auth",
         "libadbd_fs",
         "libcrypto",
+        "liblog",
+        "libselinux",
     ],
 
     target: {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 081bac4..2199fd3 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1423,6 +1423,26 @@
 #endif
 }
 
+static bool _is_valid_os_fd(int fd) {
+    // Disallow invalid FDs and stdin/out/err as well.
+    if (fd < 3) {
+        return false;
+    }
+#ifdef _WIN32
+    auto handle = (HANDLE)fd;
+    DWORD info = 0;
+    if (GetHandleInformation(handle, &info) == 0) {
+        return false;
+    }
+#else
+    int flags = fcntl(fd, F_GETFD);
+    if (flags == -1) {
+        return false;
+    }
+#endif
+    return true;
+}
+
 int adb_commandline(int argc, const char** argv) {
     bool no_daemon = false;
     bool is_daemon = false;
@@ -1977,17 +1997,28 @@
             }
         }
     } else if (!strcmp(argv[0], "inc-server")) {
-        if (argc < 3) {
-            error_exit("usage: adb inc-server FD FILE1 FILE2 ...");
+        if (argc < 4) {
+#ifdef _WIN32
+            error_exit("usage: adb inc-server CONNECTION_HANDLE OUTPUT_HANDLE FILE1 FILE2 ...");
+#else
+            error_exit("usage: adb inc-server CONNECTION_FD OUTPUT_FD FILE1 FILE2 ...");
+#endif
         }
-        int fd = atoi(argv[1]);
-        if (fd < 3) {
-            // Disallow invalid FDs and stdin/out/err as well.
-            error_exit("Invalid fd number given: %d", fd);
+        int connection_fd = atoi(argv[1]);
+        if (!_is_valid_os_fd(connection_fd)) {
+            error_exit("Invalid connection_fd number given: %d", connection_fd);
         }
-        fd = adb_register_socket(fd);
-        close_on_exec(fd);
-        return incremental::serve(fd, argc - 2, argv + 2);
+
+        connection_fd = adb_register_socket(connection_fd);
+        close_on_exec(connection_fd);
+
+        int output_fd = atoi(argv[2]);
+        if (!_is_valid_os_fd(output_fd)) {
+            error_exit("Invalid output_fd number given: %d", output_fd);
+        }
+        output_fd = adb_register_socket(output_fd);
+        close_on_exec(output_fd);
+        return incremental::serve(connection_fd, output_fd, argc - 3, argv + 3);
     }
 
     error_exit("unknown command %s", argv[0]);
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index cc38926..94bd8f5 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -112,6 +112,7 @@
     uint64_t bytes_transferred;
     uint64_t bytes_expected;
     bool expect_multiple_files;
+    std::string last_progress_str;
 
     TransferLedger() {
         Reset();
@@ -127,6 +128,7 @@
     }
 
     void Reset() {
+        last_progress_str.clear();
         start_time = std::chrono::steady_clock::now();
         files_transferred = 0;
         files_skipped = 0;
@@ -181,7 +183,10 @@
                     android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
             }
         }
-        lp.Print(output, LinePrinter::LineType::INFO);
+        if (output != last_progress_str) {
+            lp.Print(output, LinePrinter::LineType::INFO);
+            last_progress_str = std::move(output);
+        }
     }
 
     void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index 6499d46..a9e65dc 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -41,37 +41,35 @@
 
 static inline int32_t read_int32(borrowed_fd fd) {
     int32_t result;
-    ReadFully(fd, &result, sizeof(result));
-    return result;
-}
-
-static inline int32_t read_be_int32(borrowed_fd fd) {
-    return int32_t(be32toh(read_int32(fd)));
+    return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1;
 }
 
 static inline void append_int(borrowed_fd fd, std::vector<char>* bytes) {
-    int32_t be_val = read_int32(fd);
+    int32_t le_val = read_int32(fd);
     auto old_size = bytes->size();
-    bytes->resize(old_size + sizeof(be_val));
-    memcpy(bytes->data() + old_size, &be_val, sizeof(be_val));
+    bytes->resize(old_size + sizeof(le_val));
+    memcpy(bytes->data() + old_size, &le_val, sizeof(le_val));
 }
 
 static inline void append_bytes_with_size(borrowed_fd fd, std::vector<char>* bytes) {
-    int32_t be_size = read_int32(fd);
-    int32_t size = int32_t(be32toh(be_size));
+    int32_t le_size = read_int32(fd);
+    if (le_size < 0) {
+        return;
+    }
+    int32_t size = int32_t(le32toh(le_size));
     auto old_size = bytes->size();
-    bytes->resize(old_size + sizeof(be_size) + size);
-    memcpy(bytes->data() + old_size, &be_size, sizeof(be_size));
-    ReadFully(fd, bytes->data() + old_size + sizeof(be_size), size);
+    bytes->resize(old_size + sizeof(le_size) + size);
+    memcpy(bytes->data() + old_size, &le_size, sizeof(le_size));
+    ReadFdExactly(fd, bytes->data() + old_size + sizeof(le_size), size);
 }
 
 static inline std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
     std::vector<char> result;
     append_int(fd, &result);              // version
-    append_bytes_with_size(fd, &result);  // verityRootHash
-    append_bytes_with_size(fd, &result);  // v3Digest
-    append_bytes_with_size(fd, &result);  // pkcs7SignatureBlock
-    auto tree_size = read_be_int32(fd);   // size of the verity tree
+    append_bytes_with_size(fd, &result);  // hashingInfo
+    append_bytes_with_size(fd, &result);  // signingInfo
+    auto le_tree_size = read_int32(fd);
+    auto tree_size = int32_t(le32toh(le_tree_size));  // size of the verity tree
     return {std::move(result), tree_size};
 }
 
@@ -197,20 +195,72 @@
     auto fd_param = std::to_string(osh);
 #endif
 
+    // pipe for child process to write output
+    int print_fds[2];
+    if (adb_socketpair(print_fds) != 0) {
+        fprintf(stderr, "Failed to create socket pair for child to print to parent\n");
+        return {};
+    }
+    auto [pipe_read_fd, pipe_write_fd] = print_fds;
+    auto pipe_write_fd_param = std::to_string(intptr_t(adb_get_os_handle(pipe_write_fd)));
+    close_on_exec(pipe_read_fd);
+
     std::vector<std::string> args(std::move(files));
-    args.insert(args.begin(), {"inc-server", fd_param});
-    auto child = adb_launch_process(adb_path, std::move(args), {connection_fd.get()});
+    args.insert(args.begin(), {"inc-server", fd_param, pipe_write_fd_param});
+    auto child =
+            adb_launch_process(adb_path, std::move(args), {connection_fd.get(), pipe_write_fd});
     if (!child) {
         fprintf(stderr, "adb: failed to fork: %s\n", strerror(errno));
         return {};
     }
 
+    adb_close(pipe_write_fd);
+
     auto killOnExit = [](Process* p) { p->kill(); };
     std::unique_ptr<Process, decltype(killOnExit)> serverKiller(&child, killOnExit);
-    // TODO: Terminate server process if installation fails.
-    serverKiller.release();
 
+    Result result = wait_for_installation(pipe_read_fd);
+    adb_close(pipe_read_fd);
+
+    if (result == Result::Success) {
+        // adb client exits now but inc-server can continue
+        serverKiller.release();
+    }
     return child;
 }
 
+Result wait_for_installation(int read_fd) {
+    static constexpr int maxMessageSize = 256;
+    std::vector<char> child_stdout(CHUNK_SIZE);
+    int bytes_read;
+    int buf_size = 0;
+    // TODO(b/150865433): optimize child's output parsing
+    while ((bytes_read = adb_read(read_fd, child_stdout.data() + buf_size,
+                                  child_stdout.size() - buf_size)) > 0) {
+        // print to parent's stdout
+        fprintf(stdout, "%.*s", bytes_read, child_stdout.data() + buf_size);
+
+        buf_size += bytes_read;
+        const std::string_view stdout_str(child_stdout.data(), buf_size);
+        // wait till installation either succeeds or fails
+        if (stdout_str.find("Success") != std::string::npos) {
+            return Result::Success;
+        }
+        // on failure, wait for full message
+        static constexpr auto failure_msg_head = "Failure ["sv;
+        if (const auto begin_itr = stdout_str.find(failure_msg_head);
+            begin_itr != std::string::npos) {
+            if (buf_size >= maxMessageSize) {
+                return Result::Failure;
+            }
+            const auto end_itr = stdout_str.rfind("]");
+            if (end_itr != std::string::npos && end_itr >= begin_itr + failure_msg_head.size()) {
+                return Result::Failure;
+            }
+        }
+        child_stdout.resize(buf_size + CHUNK_SIZE);
+    }
+    return Result::None;
+}
+
 }  // namespace incremental
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 4b9f6bd..731e6fb 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -27,4 +27,7 @@
 
 std::optional<Process> install(std::vector<std::string> files);
 
+enum class Result { Success, Failure, None };
+Result wait_for_installation(int read_fd);
+
 }  // namespace incremental
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
index 2512d05..737563c 100644
--- a/adb/client/incremental_server.cpp
+++ b/adb/client/incremental_server.cpp
@@ -18,13 +18,6 @@
 
 #include "incremental_server.h"
 
-#include "adb.h"
-#include "adb_io.h"
-#include "adb_trace.h"
-#include "adb_unique_fd.h"
-#include "adb_utils.h"
-#include "sysdeps.h"
-
 #include <android-base/endian.h>
 #include <android-base/strings.h>
 #include <inttypes.h>
@@ -41,6 +34,14 @@
 #include <type_traits>
 #include <unordered_set>
 
+#include "adb.h"
+#include "adb_io.h"
+#include "adb_trace.h"
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "incremental_utils.h"
+#include "sysdeps.h"
+
 namespace incremental {
 
 static constexpr int kBlockSize = 4096;
@@ -49,6 +50,7 @@
 static constexpr short kCompressionLZ4 = 1;
 static constexpr int kCompressBound = std::max(kBlockSize, LZ4_COMPRESSBOUND(kBlockSize));
 static constexpr auto kReadBufferSize = 128 * 1024;
+static constexpr int kPollTimeoutMillis = 300000;  // 5 minutes
 
 using BlockSize = int16_t;
 using FileId = int16_t;
@@ -61,9 +63,10 @@
 
 static constexpr MagicType INCR = 0x494e4352;  // LE INCR
 
-static constexpr RequestType EXIT = 0;
+static constexpr RequestType SERVING_COMPLETE = 0;
 static constexpr RequestType BLOCK_MISSING = 1;
 static constexpr RequestType PREFETCH = 2;
+static constexpr RequestType DESTROY = 3;
 
 static constexpr inline int64_t roundDownToBlockOffset(int64_t val) {
     return val & ~(kBlockSize - 1);
@@ -134,6 +137,7 @@
     // Plain file
     File(const char* filepath, FileId id, int64_t size, unique_fd fd) : File(filepath, id, size) {
         this->fd_ = std::move(fd);
+        priority_blocks_ = PriorityBlocksForFile(filepath, fd_.get(), size);
     }
     int64_t ReadBlock(BlockIdx block_idx, void* buf, bool* is_zip_compressed,
                       std::string* error) const {
@@ -145,6 +149,7 @@
     }
 
     const unique_fd& RawFd() const { return fd_; }
+    const std::vector<BlockIdx>& PriorityBlocks() const { return priority_blocks_; }
 
     std::vector<bool> sentBlocks;
     NumBlocks sentBlocksCount = 0;
@@ -158,12 +163,13 @@
         sentBlocks.resize(numBytesToNumBlocks(size));
     }
     unique_fd fd_;
+    std::vector<BlockIdx> priority_blocks_;
 };
 
 class IncrementalServer {
   public:
-    IncrementalServer(unique_fd fd, std::vector<File> files)
-        : adb_fd_(std::move(fd)), files_(std::move(files)) {
+    IncrementalServer(unique_fd adb_fd, unique_fd output_fd, std::vector<File> files)
+        : adb_fd_(std::move(adb_fd)), output_fd_(std::move(output_fd)), files_(std::move(files)) {
         buffer_.reserve(kReadBufferSize);
     }
 
@@ -174,14 +180,23 @@
         const File* file;
         BlockIdx overallIndex = 0;
         BlockIdx overallEnd = 0;
+        BlockIdx priorityIndex = 0;
 
-        PrefetchState(const File& f) : file(&f), overallEnd((BlockIdx)f.sentBlocks.size()) {}
-        PrefetchState(const File& f, BlockIdx start, int count)
+        explicit PrefetchState(const File& f, BlockIdx start, int count)
             : file(&f),
               overallIndex(start),
               overallEnd(std::min<BlockIdx>(start + count, f.sentBlocks.size())) {}
 
-        bool done() const { return overallIndex >= overallEnd; }
+        explicit PrefetchState(const File& f)
+            : PrefetchState(f, 0, (BlockIdx)f.sentBlocks.size()) {}
+
+        bool done() const {
+            const bool overallSent = (overallIndex >= overallEnd);
+            if (file->PriorityBlocks().empty()) {
+                return overallSent;
+            }
+            return overallSent && (priorityIndex >= (BlockIdx)file->PriorityBlocks().size());
+        }
     };
 
     bool SkipToRequest(void* buffer, size_t* size, bool blocking);
@@ -197,9 +212,10 @@
     void Send(const void* data, size_t size, bool flush);
     void Flush();
     using TimePoint = decltype(std::chrono::high_resolution_clock::now());
-    bool Exit(std::optional<TimePoint> startTime, int missesCount, int missesSent);
+    bool ServingComplete(std::optional<TimePoint> startTime, int missesCount, int missesSent);
 
     unique_fd const adb_fd_;
+    unique_fd const output_fd_;
     std::vector<File> files_;
 
     // Incoming data buffer.
@@ -210,6 +226,9 @@
     long long sentSize_ = 0;
 
     std::vector<char> pendingBlocks_;
+
+    // True when client notifies that all the data has been received
+    bool servingComplete_ = false;
 };
 
 bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) {
@@ -217,7 +236,8 @@
         // Looking for INCR magic.
         bool magic_found = false;
         int bcur = 0;
-        for (int bsize = buffer_.size(); bcur + 4 < bsize; ++bcur) {
+        int bsize = buffer_.size();
+        for (bcur = 0; bcur + 4 < bsize; ++bcur) {
             uint32_t magic = be32toh(*(uint32_t*)(buffer_.data() + bcur));
             if (magic == INCR) {
                 magic_found = true;
@@ -226,8 +246,8 @@
         }
 
         if (bcur > 0) {
-            // Stream the rest to stderr.
-            fprintf(stderr, "%.*s", bcur, buffer_.data());
+            // output the rest.
+            WriteFdExactly(output_fd_, buffer_.data(), bcur);
             erase_buffer_head(bcur);
         }
 
@@ -239,17 +259,26 @@
         }
 
         adb_pollfd pfd = {adb_fd_.get(), POLLIN, 0};
-        auto res = adb_poll(&pfd, 1, blocking ? -1 : 0);
+        auto res = adb_poll(&pfd, 1, blocking ? kPollTimeoutMillis : 0);
+
         if (res != 1) {
+            WriteFdExactly(output_fd_, buffer_.data(), buffer_.size());
             if (res < 0) {
-                fprintf(stderr, "Failed to poll: %s\n", strerror(errno));
+                D("Failed to poll: %s\n", strerror(errno));
+                return false;
+            }
+            if (blocking) {
+                fprintf(stderr, "Timed out waiting for data from device.\n");
+            }
+            if (blocking && servingComplete_) {
+                // timeout waiting from client. Serving is complete, so quit.
                 return false;
             }
             *size = 0;
             return true;
         }
 
-        auto bsize = buffer_.size();
+        bsize = buffer_.size();
         buffer_.resize(kReadBufferSize);
         int r = adb_read(adb_fd_, buffer_.data() + bsize, kReadBufferSize - bsize);
         if (r > 0) {
@@ -257,21 +286,19 @@
             continue;
         }
 
-        if (r == -1) {
-            fprintf(stderr, "Failed to read from fd %d: %d. Exit\n", adb_fd_.get(), errno);
-            return false;
-        }
-
-        // socket is closed
-        return false;
+        D("Failed to read from fd %d: %d. Exit\n", adb_fd_.get(), errno);
+        break;
     }
+    // socket is closed. print remaining messages
+    WriteFdExactly(output_fd_, buffer_.data(), buffer_.size());
+    return false;
 }
 
 std::optional<RequestCommand> IncrementalServer::ReadRequest(bool blocking) {
     uint8_t commandBuf[sizeof(RequestCommand)];
     auto size = sizeof(commandBuf);
     if (!SkipToRequest(&commandBuf, &size, blocking)) {
-        return {{EXIT}};
+        return {{DESTROY}};
     }
     if (size < sizeof(RequestCommand)) {
         return {};
@@ -351,6 +378,17 @@
     while (!prefetches_.empty() && blocksToSend > 0) {
         auto& prefetch = prefetches_.front();
         const auto& file = *prefetch.file;
+        const auto& priority_blocks = file.PriorityBlocks();
+        if (!priority_blocks.empty()) {
+            for (auto& i = prefetch.priorityIndex;
+                 blocksToSend > 0 && i < (BlockIdx)priority_blocks.size(); ++i) {
+                if (auto res = SendBlock(file.id, priority_blocks[i]); res == SendResult::Sent) {
+                    --blocksToSend;
+                } else if (res == SendResult::Error) {
+                    fprintf(stderr, "Failed to send priority block %" PRId32 "\n", i);
+                }
+            }
+        }
         for (auto& i = prefetch.overallIndex; blocksToSend > 0 && i < prefetch.overallEnd; ++i) {
             if (auto res = SendBlock(file.id, i); res == SendResult::Sent) {
                 --blocksToSend;
@@ -391,17 +429,17 @@
     pendingBlocks_.clear();
 }
 
-bool IncrementalServer::Exit(std::optional<TimePoint> startTime, int missesCount, int missesSent) {
+bool IncrementalServer::ServingComplete(std::optional<TimePoint> startTime, int missesCount,
+                                        int missesSent) {
+    servingComplete_ = true;
     using namespace std::chrono;
     auto endTime = high_resolution_clock::now();
-    fprintf(stderr,
-            "Connection failed or received exit command. Exit.\n"
-            "Misses: %d, of those unique: %d; sent compressed: %d, uncompressed: "
-            "%d, mb: %.3f\n"
-            "Total time taken: %.3fms\n",
-            missesCount, missesSent, compressed_, uncompressed_, sentSize_ / 1024.0 / 1024.0,
-            duration_cast<microseconds>(endTime - (startTime ? *startTime : endTime)).count() /
-                    1000.0);
+    D("Streaming completed.\n"
+      "Misses: %d, of those unique: %d; sent compressed: %d, uncompressed: "
+      "%d, mb: %.3f\n"
+      "Total time taken: %.3fms\n",
+      missesCount, missesSent, compressed_, uncompressed_, sentSize_ / 1024.0 / 1024.0,
+      duration_cast<microseconds>(endTime - (startTime ? *startTime : endTime)).count() / 1000.0);
     return true;
 }
 
@@ -425,7 +463,7 @@
             std::all_of(files_.begin(), files_.end(), [](const File& f) {
                 return f.sentBlocksCount == NumBlocks(f.sentBlocks.size());
             })) {
-            fprintf(stdout, "All files should be loaded. Notifying the device.\n");
+            fprintf(stderr, "All files should be loaded. Notifying the device.\n");
             SendDone();
             doneSent = true;
         }
@@ -446,9 +484,14 @@
             BlockIdx blockIdx = request->block_idx;
 
             switch (request->request_type) {
-                case EXIT: {
+                case DESTROY: {
                     // Stop everything.
-                    return Exit(startTime, missesCount, missesSent);
+                    return true;
+                }
+                case SERVING_COMPLETE: {
+                    // Not stopping the server here.
+                    ServingComplete(startTime, missesCount, missesSent);
+                    break;
                 }
                 case BLOCK_MISSING: {
                     ++missesCount;
@@ -502,8 +545,9 @@
     }
 }
 
-bool serve(int adb_fd, int argc, const char** argv) {
-    auto connection_fd = unique_fd(adb_fd);
+bool serve(int connection_fd, int output_fd, int argc, const char** argv) {
+    auto connection_ufd = unique_fd(connection_fd);
+    auto output_ufd = unique_fd(output_fd);
     if (argc <= 0) {
         error_exit("inc-server: must specify at least one file.");
     }
@@ -526,7 +570,7 @@
         files.emplace_back(filepath, i, st.st_size, std::move(fd));
     }
 
-    IncrementalServer server(std::move(connection_fd), std::move(files));
+    IncrementalServer server(std::move(connection_ufd), std::move(output_ufd), std::move(files));
     printf("Serving...\n");
     fclose(stdin);
     fclose(stdout);
diff --git a/adb/client/incremental_server.h b/adb/client/incremental_server.h
index 53f011e..55b8215 100644
--- a/adb/client/incremental_server.h
+++ b/adb/client/incremental_server.h
@@ -21,6 +21,6 @@
 // Expecting arguments like:
 // {FILE1 FILE2 ...}
 // Where FILE* are files to serve.
-bool serve(int adbFd, int argc, const char** argv);
+bool serve(int connection_fd, int output_fd, int argc, const char** argv);
 
 }  // namespace incremental
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
new file mode 100644
index 0000000..caadb26
--- /dev/null
+++ b/adb/client/incremental_utils.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG INCREMENTAL
+
+#include "incremental_utils.h"
+
+#include <android-base/mapped_file.h>
+#include <android-base/strings.h>
+#include <ziparchive/zip_archive.h>
+#include <ziparchive/zip_writer.h>
+
+#include <cinttypes>
+#include <numeric>
+#include <unordered_set>
+
+#include "adb_trace.h"
+#include "sysdeps.h"
+
+static constexpr int kBlockSize = 4096;
+
+static constexpr inline int32_t offsetToBlockIndex(int64_t offset) {
+    return (offset & ~(kBlockSize - 1)) >> 12;
+}
+
+template <class T>
+T valueAt(int fd, off64_t offset) {
+    T t;
+    memset(&t, 0, sizeof(T));
+    if (adb_pread(fd, &t, sizeof(T), offset) != sizeof(T)) {
+        memset(&t, -1, sizeof(T));
+    }
+
+    return t;
+}
+
+static void appendBlocks(int32_t start, int count, std::vector<int32_t>* blocks) {
+    if (count == 1) {
+        blocks->push_back(start);
+    } else {
+        auto oldSize = blocks->size();
+        blocks->resize(oldSize + count);
+        std::iota(blocks->begin() + oldSize, blocks->end(), start);
+    }
+}
+
+template <class T>
+static void unduplicate(std::vector<T>& v) {
+    std::unordered_set<T> uniques(v.size());
+    v.erase(std::remove_if(v.begin(), v.end(),
+                           [&uniques](T t) { return !uniques.insert(t).second; }),
+            v.end());
+}
+
+static off64_t CentralDirOffset(int fd, int64_t fileSize) {
+    static constexpr int kZipEocdRecMinSize = 22;
+    static constexpr int32_t kZipEocdRecSig = 0x06054b50;
+    static constexpr int kZipEocdCentralDirSizeFieldOffset = 12;
+    static constexpr int kZipEocdCommentLengthFieldOffset = 20;
+
+    int32_t sigBuf = 0;
+    off64_t eocdOffset = -1;
+    off64_t maxEocdOffset = fileSize - kZipEocdRecMinSize;
+    int16_t commentLenBuf = 0;
+
+    // Search from the end of zip, backward to find beginning of EOCD
+    for (int16_t commentLen = 0; commentLen < fileSize; ++commentLen) {
+        sigBuf = valueAt<int32_t>(fd, maxEocdOffset - commentLen);
+        if (sigBuf == kZipEocdRecSig) {
+            commentLenBuf = valueAt<int16_t>(
+                    fd, maxEocdOffset - commentLen + kZipEocdCommentLengthFieldOffset);
+            if (commentLenBuf == commentLen) {
+                eocdOffset = maxEocdOffset - commentLen;
+                break;
+            }
+        }
+    }
+
+    if (eocdOffset < 0) {
+        return -1;
+    }
+
+    off64_t cdLen = static_cast<int64_t>(
+            valueAt<int32_t>(fd, eocdOffset + kZipEocdCentralDirSizeFieldOffset));
+
+    return eocdOffset - cdLen;
+}
+
+// Does not support APKs larger than 4GB
+static off64_t SignerBlockOffset(int fd, int64_t fileSize) {
+    static constexpr int kApkSigBlockMinSize = 32;
+    static constexpr int kApkSigBlockFooterSize = 24;
+    static constexpr int64_t APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42l;
+    static constexpr int64_t APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041l;
+
+    off64_t cdOffset = CentralDirOffset(fd, fileSize);
+    if (cdOffset < 0) {
+        return -1;
+    }
+    // CD offset is where original signer block ends. Search backwards for magic and footer.
+    if (cdOffset < kApkSigBlockMinSize ||
+        valueAt<int64_t>(fd, cdOffset - 2 * sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_LO ||
+        valueAt<int64_t>(fd, cdOffset - sizeof(int64_t)) != APK_SIG_BLOCK_MAGIC_HI) {
+        return -1;
+    }
+    int32_t signerSizeInFooter = valueAt<int32_t>(fd, cdOffset - kApkSigBlockFooterSize);
+    off64_t signerBlockOffset = cdOffset - signerSizeInFooter - sizeof(int64_t);
+    if (signerBlockOffset < 0) {
+        return -1;
+    }
+    int32_t signerSizeInHeader = valueAt<int32_t>(fd, signerBlockOffset);
+    if (signerSizeInFooter != signerSizeInHeader) {
+        return -1;
+    }
+
+    return signerBlockOffset;
+}
+
+static std::vector<int32_t> ZipPriorityBlocks(off64_t signerBlockOffset, int64_t fileSize) {
+    int32_t signerBlockIndex = offsetToBlockIndex(signerBlockOffset);
+    int32_t lastBlockIndex = offsetToBlockIndex(fileSize);
+    const auto numPriorityBlocks = lastBlockIndex - signerBlockIndex + 1;
+
+    std::vector<int32_t> zipPriorityBlocks;
+
+    // Some magic here: most of zip libraries perform a scan for EOCD record starting at the offset
+    // of a maximum comment size from the end of the file. This means the last 65-ish KBs will be
+    // accessed first, followed by the rest of the central directory blocks. Make sure we
+    // send the data in the proper order, as central directory can be quite big by itself.
+    static constexpr auto kMaxZipCommentSize = 64 * 1024;
+    static constexpr auto kNumBlocksInEocdSearch = kMaxZipCommentSize / kBlockSize + 1;
+    if (numPriorityBlocks > kNumBlocksInEocdSearch) {
+        appendBlocks(lastBlockIndex - kNumBlocksInEocdSearch + 1, kNumBlocksInEocdSearch,
+                     &zipPriorityBlocks);
+        appendBlocks(signerBlockIndex, numPriorityBlocks - kNumBlocksInEocdSearch,
+                     &zipPriorityBlocks);
+    } else {
+        appendBlocks(signerBlockIndex, numPriorityBlocks, &zipPriorityBlocks);
+    }
+
+    // Somehow someone keeps accessing the start of the archive, even if there's nothing really
+    // interesting there...
+    appendBlocks(0, 1, &zipPriorityBlocks);
+    return zipPriorityBlocks;
+}
+
+[[maybe_unused]] static ZipArchiveHandle openZipArchiveFd(int fd) {
+    bool transferFdOwnership = false;
+#ifdef _WIN32
+    //
+    // Need to create a special CRT FD here as the current one is not compatible with
+    // normal read()/write() calls that libziparchive uses.
+    // To make this work we have to create a copy of the file handle, as CRT doesn't care
+    // and closes it together with the new descriptor.
+    //
+    // Note: don't move this into a helper function, it's better to be hard to reuse because
+    //       the code is ugly and won't work unless it's a last resort.
+    //
+    auto handle = adb_get_os_handle(fd);
+    HANDLE dupedHandle;
+    if (!::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(), &dupedHandle, 0,
+                           false, DUPLICATE_SAME_ACCESS)) {
+        D("%s failed at DuplicateHandle: %d", __func__, (int)::GetLastError());
+        return {};
+    }
+    fd = _open_osfhandle((intptr_t)dupedHandle, _O_RDONLY | _O_BINARY);
+    if (fd < 0) {
+        D("%s failed at _open_osfhandle: %d", __func__, errno);
+        ::CloseHandle(handle);
+        return {};
+    }
+    transferFdOwnership = true;
+#endif
+    ZipArchiveHandle zip;
+    if (OpenArchiveFd(fd, "apk_fd", &zip, transferFdOwnership) != 0) {
+        D("%s failed at OpenArchiveFd: %d", __func__, errno);
+#ifdef _WIN32
+        // "_close()" is a secret WinCRT name for the regular close() function.
+        _close(fd);
+#endif
+        return {};
+    }
+    return zip;
+}
+
+static std::pair<ZipArchiveHandle, std::unique_ptr<android::base::MappedFile>> openZipArchive(
+        int fd, int64_t fileSize) {
+#ifndef __LP64__
+    if (fileSize >= INT_MAX) {
+        return {openZipArchiveFd(fd), nullptr};
+    }
+#endif
+    auto mapping =
+            android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), 0, fileSize, PROT_READ);
+    if (!mapping) {
+        D("%s failed at FromOsHandle: %d", __func__, errno);
+        return {};
+    }
+    ZipArchiveHandle zip;
+    if (OpenArchiveFromMemory(mapping->data(), mapping->size(), "apk_mapping", &zip) != 0) {
+        D("%s failed at OpenArchiveFromMemory: %d", __func__, errno);
+        return {};
+    }
+    return {zip, std::move(mapping)};
+}
+
+// TODO(b/151676293): avoid using libziparchive as it reads local file headers
+// which causes additional performance cost. Instead, only read from central directory.
+static std::vector<int32_t> InstallationPriorityBlocks(int fd, int64_t fileSize) {
+    auto [zip, _] = openZipArchive(fd, fileSize);
+    if (!zip) {
+        return {};
+    }
+
+    void* cookie = nullptr;
+    if (StartIteration(zip, &cookie) != 0) {
+        D("%s failed at StartIteration: %d", __func__, errno);
+        return {};
+    }
+
+    std::vector<int32_t> installationPriorityBlocks;
+    ZipEntry entry;
+    std::string_view entryName;
+    while (Next(cookie, &entry, &entryName) == 0) {
+        if (entryName == "resources.arsc" || entryName == "AndroidManifest.xml" ||
+            entryName.starts_with("lib/")) {
+            // Full entries are needed for installation
+            off64_t entryStartOffset = entry.offset;
+            off64_t entryEndOffset =
+                    entryStartOffset +
+                    (entry.method == kCompressStored ? entry.uncompressed_length
+                                                     : entry.compressed_length) +
+                    (entry.has_data_descriptor ? 16 /* sizeof(DataDescriptor) */ : 0);
+            int32_t startBlockIndex = offsetToBlockIndex(entryStartOffset);
+            int32_t endBlockIndex = offsetToBlockIndex(entryEndOffset);
+            int32_t numNewBlocks = endBlockIndex - startBlockIndex + 1;
+            appendBlocks(startBlockIndex, numNewBlocks, &installationPriorityBlocks);
+            D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
+        } else if (entryName == "classes.dex") {
+            // Only the head is needed for installation
+            int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
+            appendBlocks(startBlockIndex, 1, &installationPriorityBlocks);
+        }
+    }
+
+    EndIteration(cookie);
+    CloseArchive(zip);
+    return installationPriorityBlocks;
+}
+
+namespace incremental {
+std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, int fd, int64_t fileSize) {
+    if (!android::base::EndsWithIgnoreCase(filepath, ".apk")) {
+        return {};
+    }
+    off64_t signerOffset = SignerBlockOffset(fd, fileSize);
+    if (signerOffset < 0) {
+        // No signer block? not a valid APK
+        return {};
+    }
+    std::vector<int32_t> priorityBlocks = ZipPriorityBlocks(signerOffset, fileSize);
+    std::vector<int32_t> installationPriorityBlocks = InstallationPriorityBlocks(fd, fileSize);
+
+    priorityBlocks.insert(priorityBlocks.end(), installationPriorityBlocks.begin(),
+                          installationPriorityBlocks.end());
+    unduplicate(priorityBlocks);
+    return priorityBlocks;
+}
+}  // namespace incremental
diff --git a/init/service_lock.cpp b/adb/client/incremental_utils.h
similarity index 73%
rename from init/service_lock.cpp
rename to adb/client/incremental_utils.h
index 404d439..8bcf6c0 100644
--- a/init/service_lock.cpp
+++ b/adb/client/incremental_utils.h
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-#include "service_lock.h"
+#pragma once
 
-namespace android {
-namespace init {
+#include <stdint.h>
 
-RecursiveMutex service_lock;
+#include <string>
+#include <vector>
 
-}  // namespace init
-}  // namespace android
+namespace incremental {
+std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, int fd, int64_t fileSize);
+}  // namespace incremental
\ No newline at end of file
diff --git a/adb/fdevent/fdevent.cpp b/adb/fdevent/fdevent.cpp
index 562f587..fd55020 100644
--- a/adb/fdevent/fdevent.cpp
+++ b/adb/fdevent/fdevent.cpp
@@ -63,7 +63,10 @@
 
     int fd_num = fd.get();
 
-    fdevent* fde = new fdevent();
+    auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
+    CHECK(inserted);
+
+    fdevent* fde = &it->second;
     fde->id = fdevent_id_++;
     fde->state = 0;
     fde->fd = std::move(fd);
@@ -76,10 +79,6 @@
         LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
     }
 
-    auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fde);
-    CHECK(inserted);
-    UNUSED(it);
-
     this->Register(fde);
     return fde;
 }
@@ -92,12 +91,12 @@
 
     this->Unregister(fde);
 
-    auto erased = this->installed_fdevents_.erase(fde->fd.get());
+    unique_fd fd = std::move(fde->fd);
+
+    auto erased = this->installed_fdevents_.erase(fd.get());
     CHECK_EQ(1UL, erased);
 
-    unique_fd result = std::move(fde->fd);
-    delete fde;
-    return result;
+    return fd;
 }
 
 void fdevent_context::Add(fdevent* fde, unsigned events) {
@@ -123,9 +122,9 @@
 
     for (const auto& [fd, fde] : this->installed_fdevents_) {
         UNUSED(fd);
-        auto timeout_opt = fde->timeout;
+        auto timeout_opt = fde.timeout;
         if (timeout_opt) {
-            auto deadline = fde->last_active + *timeout_opt;
+            auto deadline = fde.last_active + *timeout_opt;
             auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
             if (time_left < 0ms) {
                 time_left = 0ms;
@@ -194,11 +193,13 @@
 #endif
 }
 
-static auto& g_ambient_fdevent_context =
-        *new std::unique_ptr<fdevent_context>(fdevent_create_context());
+static auto& g_ambient_fdevent_context() {
+    static auto context = fdevent_create_context().release();
+    return context;
+}
 
 static fdevent_context* fdevent_get_ambient() {
-    return g_ambient_fdevent_context.get();
+    return g_ambient_fdevent_context();
 }
 
 fdevent* fdevent_create(int fd, fd_func func, void* arg) {
@@ -256,5 +257,6 @@
 }
 
 void fdevent_reset() {
-    g_ambient_fdevent_context = fdevent_create_context();
+    auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
+    delete old;
 }
diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h
index 86814d7..9fc3b2c 100644
--- a/adb/fdevent/fdevent.h
+++ b/adb/fdevent/fdevent.h
@@ -52,6 +52,20 @@
     unsigned events;
 };
 
+struct fdevent final {
+    uint64_t id;
+
+    unique_fd fd;
+    int force_eof = 0;
+
+    uint16_t state = 0;
+    std::optional<std::chrono::milliseconds> timeout;
+    std::chrono::steady_clock::time_point last_active;
+
+    std::variant<fd_func, fd_func2> func;
+    void* arg = nullptr;
+};
+
 struct fdevent_context {
   public:
     virtual ~fdevent_context() = default;
@@ -113,7 +127,7 @@
     std::atomic<bool> terminate_loop_ = false;
 
   protected:
-    std::unordered_map<int, fdevent*> installed_fdevents_;
+    std::unordered_map<int, fdevent> installed_fdevents_;
 
   private:
     uint64_t fdevent_id_ = 0;
@@ -121,20 +135,6 @@
     std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
 };
 
-struct fdevent {
-    uint64_t id;
-
-    unique_fd fd;
-    int force_eof = 0;
-
-    uint16_t state = 0;
-    std::optional<std::chrono::milliseconds> timeout;
-    std::chrono::steady_clock::time_point last_active;
-
-    std::variant<fd_func, fd_func2> func;
-    void* arg = nullptr;
-};
-
 // Backwards compatibility shims that forward to the global fdevent_context.
 fdevent* fdevent_create(int fd, fd_func func, void* arg);
 fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
diff --git a/adb/fdevent/fdevent_epoll.cpp b/adb/fdevent/fdevent_epoll.cpp
index e3d1674..4ef41d1 100644
--- a/adb/fdevent/fdevent_epoll.cpp
+++ b/adb/fdevent/fdevent_epoll.cpp
@@ -155,15 +155,15 @@
             event_map[fde] = events;
         }
 
-        for (const auto& [fd, fde] : installed_fdevents_) {
+        for (auto& [fd, fde] : installed_fdevents_) {
             unsigned events = 0;
-            if (auto it = event_map.find(fde); it != event_map.end()) {
+            if (auto it = event_map.find(&fde); it != event_map.end()) {
                 events = it->second;
             }
 
             if (events == 0) {
-                if (fde->timeout) {
-                    auto deadline = fde->last_active + *fde->timeout;
+                if (fde.timeout) {
+                    auto deadline = fde.last_active + *fde.timeout;
                     if (deadline < post_poll) {
                         events |= FDE_TIMEOUT;
                     }
@@ -171,13 +171,13 @@
             }
 
             if (events != 0) {
-                LOG(DEBUG) << dump_fde(fde) << " got events " << std::hex << std::showbase
+                LOG(DEBUG) << dump_fde(&fde) << " got events " << std::hex << std::showbase
                            << events;
-                fde_events.push_back({fde, events});
-                fde->last_active = post_poll;
+                fde_events.push_back({&fde, events});
+                fde.last_active = post_poll;
             }
         }
-        this->HandleEvents(std::move(fde_events));
+        this->HandleEvents(fde_events);
         fde_events.clear();
     }
 
diff --git a/adb/fdevent/fdevent_epoll.h b/adb/fdevent/fdevent_epoll.h
index 684fa32..6214d2e 100644
--- a/adb/fdevent/fdevent_epoll.h
+++ b/adb/fdevent/fdevent_epoll.h
@@ -47,12 +47,7 @@
   protected:
     virtual void Interrupt() final;
 
-  public:
-    // All operations to fdevent should happen only in the main thread.
-    // That's why we don't need a lock for fdevent.
-    std::unordered_map<int, fdevent*> epoll_node_map_;
-    std::list<fdevent*> pending_list_;
-
+  private:
     unique_fd epoll_fd_;
     unique_fd interrupt_fd_;
     fdevent* interrupt_fde_ = nullptr;
diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp
index cc4a7a1..ac86c08 100644
--- a/adb/fdevent/fdevent_poll.cpp
+++ b/adb/fdevent/fdevent_poll.cpp
@@ -103,24 +103,27 @@
 void fdevent_context_poll::Loop() {
     main_thread_id_ = android::base::GetThreadId();
 
+    std::vector<adb_pollfd> pollfds;
+    std::vector<fdevent_event> poll_events;
+
     while (true) {
         if (terminate_loop_) {
             break;
         }
 
         D("--- --- waiting for events");
-        std::vector<adb_pollfd> pollfds;
+        pollfds.clear();
         for (const auto& [fd, fde] : this->installed_fdevents_) {
             adb_pollfd pfd;
             pfd.fd = fd;
             pfd.events = 0;
-            if (fde->state & FDE_READ) {
+            if (fde.state & FDE_READ) {
                 pfd.events |= POLLIN;
             }
-            if (fde->state & FDE_WRITE) {
+            if (fde.state & FDE_WRITE) {
                 pfd.events |= POLLOUT;
             }
-            if (fde->state & FDE_ERROR) {
+            if (fde.state & FDE_ERROR) {
                 pfd.events |= POLLERR;
             }
 #if defined(__linux__)
@@ -147,7 +150,6 @@
         }
 
         auto post_poll = std::chrono::steady_clock::now();
-        std::vector<fdevent_event> poll_events;
 
         for (const auto& pollfd : pollfds) {
             unsigned events = 0;
@@ -170,7 +172,7 @@
 
             auto it = this->installed_fdevents_.find(pollfd.fd);
             CHECK(it != this->installed_fdevents_.end());
-            fdevent* fde = it->second;
+            fdevent* fde = &it->second;
 
             if (events == 0) {
                 if (fde->timeout) {
@@ -187,7 +189,8 @@
                 fde->last_active = post_poll;
             }
         }
-        this->HandleEvents(std::move(poll_events));
+        this->HandleEvents(poll_events);
+        poll_events.clear();
     }
 
     main_thread_id_.reset();
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 4efbc02..3e781b8 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -276,6 +276,7 @@
 class Process {
   public:
     constexpr explicit Process(HANDLE h = nullptr) : h_(h) {}
+    constexpr Process(Process&& other) : h_(std::exchange(other.h_, nullptr)) {}
     ~Process() { close(); }
     constexpr explicit operator bool() const { return h_ != nullptr; }
 
@@ -292,6 +293,8 @@
     }
 
   private:
+    DISALLOW_COPY_AND_ASSIGN(Process);
+
     void close() {
         if (*this) {
             ::CloseHandle(h_);
@@ -666,6 +669,8 @@
 class Process {
   public:
     constexpr explicit Process(pid_t pid) : pid_(pid) {}
+    constexpr Process(Process&& other) : pid_(std::exchange(other.pid_, -1)) {}
+
     constexpr explicit operator bool() const { return pid_ >= 0; }
 
     void wait() {
@@ -682,6 +687,8 @@
     }
 
   private:
+    DISALLOW_COPY_AND_ASSIGN(Process);
+
     pid_t pid_;
 };
 
diff --git a/base/Android.bp b/base/Android.bp
index 25c74f2..3702b43 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -70,10 +70,6 @@
         "test_utils.cpp",
     ],
 
-    static: {
-        cflags: ["-DNO_LIBLOG_DLSYM"],
-    },
-
     cppflags: ["-Wexit-time-destructors"],
     shared_libs: ["liblog"],
     target: {
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
index 8d59179..1f4b69b 100644
--- a/base/liblog_symbols.cpp
+++ b/base/liblog_symbols.cpp
@@ -16,11 +16,9 @@
 
 #include "liblog_symbols.h"
 
-#if defined(__ANDROID__)
-#if !defined(NO_LIBLOG_DLSYM) || defined(__ANDROID_APEX__)
+#if defined(__ANDROID_SDK_VERSION__) && (__ANDROID_SDK_VERSION__ <= 29)
 #define USE_DLSYM
 #endif
-#endif
 
 #ifdef USE_DLSYM
 #include <dlfcn.h>
@@ -48,7 +46,7 @@
   }
 
     DLSYM(__android_log_set_logger)
-    DLSYM(__android_log_write_logger_data)
+    DLSYM(__android_log_write_log_message)
     DLSYM(__android_log_logd_logger)
     DLSYM(__android_log_stderr_logger)
     DLSYM(__android_log_set_aborter)
@@ -71,7 +69,7 @@
   static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
     return LibLogFunctions{
         .__android_log_set_logger = __android_log_set_logger,
-        .__android_log_write_logger_data = __android_log_write_logger_data,
+        .__android_log_write_log_message = __android_log_write_log_message,
         .__android_log_logd_logger = __android_log_logd_logger,
         .__android_log_stderr_logger = __android_log_stderr_logger,
         .__android_log_set_aborter = __android_log_set_aborter,
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
index d3134e9..2e6b47f 100644
--- a/base/liblog_symbols.h
+++ b/base/liblog_symbols.h
@@ -25,19 +25,16 @@
 
 struct LibLogFunctions {
   void (*__android_log_set_logger)(__android_logger_function logger);
-  void (*__android_log_write_logger_data)(struct __android_logger_data* logger_data,
-                                          const char* msg);
+  void (*__android_log_write_log_message)(struct __android_log_message* log_message);
 
-  void (*__android_log_logd_logger)(const struct __android_logger_data* logger_data,
-                                    const char* msg);
-  void (*__android_log_stderr_logger)(const struct __android_logger_data* logger_data,
-                                      const char* message);
+  void (*__android_log_logd_logger)(const struct __android_log_message* log_message);
+  void (*__android_log_stderr_logger)(const struct __android_log_message* log_message);
 
   void (*__android_log_set_aborter)(__android_aborter_function aborter);
   void (*__android_log_call_aborter)(const char* abort_message);
   void (*__android_log_default_aborter)(const char* abort_message);
-  int (*__android_log_set_minimum_priority)(int priority);
-  int (*__android_log_get_minimum_priority)();
+  int32_t (*__android_log_set_minimum_priority)(int32_t priority);
+  int32_t (*__android_log_get_minimum_priority)();
   void (*__android_log_set_default_tag)(const char* tag);
 };
 
diff --git a/base/logging.cpp b/base/logging.cpp
index 9360a56..cd460eb 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -118,7 +118,7 @@
 }
 #endif
 
-static LogId log_id_tToLogId(int buffer_id) {
+static LogId log_id_tToLogId(int32_t buffer_id) {
   switch (buffer_id) {
     case LOG_ID_MAIN:
       return MAIN;
@@ -134,7 +134,7 @@
   }
 }
 
-static int LogIdTolog_id_t(LogId log_id) {
+static int32_t LogIdTolog_id_t(LogId log_id) {
   switch (log_id) {
     case MAIN:
       return LOG_ID_MAIN;
@@ -171,7 +171,7 @@
   }
 }
 
-static android_LogPriority LogSeverityToPriority(LogSeverity severity) {
+static int32_t LogSeverityToPriority(LogSeverity severity) {
   switch (severity) {
     case VERBOSE:
       return ANDROID_LOG_VERBOSE;
@@ -333,12 +333,12 @@
 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
                             const char* file, unsigned int line,
                             const char* message) {
-  android_LogPriority priority = LogSeverityToPriority(severity);
+  int32_t priority = LogSeverityToPriority(severity);
   if (id == DEFAULT) {
     id = default_log_id_;
   }
 
-  int lg_id = LogIdTolog_id_t(id);
+  int32_t lg_id = LogIdTolog_id_t(id);
 
   char log_message_with_file[4068];  // LOGGER_ENTRY_MAX_PAYLOAD, not available in the NDK.
   if (priority == ANDROID_LOG_FATAL && file != nullptr) {
@@ -349,9 +349,9 @@
 
   static auto& liblog_functions = GetLibLogFunctions();
   if (liblog_functions) {
-    __android_logger_data logger_data = {sizeof(__android_logger_data),     lg_id, priority, tag,
-                                         static_cast<const char*>(nullptr), 0};
-    liblog_functions->__android_log_logd_logger(&logger_data, message);
+    __android_log_message log_message = {sizeof(__android_log_message),     lg_id, priority, tag,
+                                         static_cast<const char*>(nullptr), 0,     message};
+    liblog_functions->__android_log_logd_logger(&log_message);
   } else {
     __android_log_buf_print(lg_id, priority, tag, "%s", message);
   }
@@ -426,13 +426,13 @@
     // std::function<>, which is the not-thread-safe alternative.
     static std::atomic<LogFunction*> logger_function(nullptr);
     auto* old_logger_function = logger_function.exchange(new LogFunction(logger));
-    liblog_functions->__android_log_set_logger([](const struct __android_logger_data* logger_data,
-                                                  const char* message) {
-      auto log_id = log_id_tToLogId(logger_data->buffer_id);
-      auto severity = PriorityToLogSeverity(logger_data->priority);
+    liblog_functions->__android_log_set_logger([](const struct __android_log_message* log_message) {
+      auto log_id = log_id_tToLogId(log_message->buffer_id);
+      auto severity = PriorityToLogSeverity(log_message->priority);
 
       auto& function = *logger_function.load(std::memory_order_acquire);
-      function(log_id, severity, logger_data->tag, logger_data->file, logger_data->line, message);
+      function(log_id, severity, log_message->tag, log_message->file, log_message->line,
+               log_message->message);
     });
     delete old_logger_function;
   } else {
@@ -574,11 +574,11 @@
 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
                          const char* message) {
   static auto& liblog_functions = GetLibLogFunctions();
-  auto priority = LogSeverityToPriority(severity);
+  int32_t priority = LogSeverityToPriority(severity);
   if (liblog_functions) {
-    __android_logger_data logger_data = {
-        sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
-    liblog_functions->__android_log_write_logger_data(&logger_data, message);
+    __android_log_message log_message = {
+        sizeof(__android_log_message), LOG_ID_DEFAULT, priority, tag, file, line, message};
+    liblog_functions->__android_log_write_log_message(&log_message);
   } else {
     if (tag == nullptr) {
       std::lock_guard<std::recursive_mutex> lock(TagLock());
@@ -608,7 +608,7 @@
   // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
   // take into consideration the value from SetMinimumLogSeverity().
   if (liblog_functions) {
-    int priority = LogSeverityToPriority(severity);
+    int32_t priority = LogSeverityToPriority(severity);
     return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
   } else {
     return severity >= gMinimumLogSeverity;
@@ -618,7 +618,7 @@
 LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
   static auto& liblog_functions = GetLibLogFunctions();
   if (liblog_functions) {
-    auto priority = LogSeverityToPriority(new_severity);
+    int32_t priority = LogSeverityToPriority(new_severity);
     return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
   } else {
     LogSeverity old_severity = gMinimumLogSeverity;
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 46d4bd3..2c0989e 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,14 +34,54 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+static void bootimg_set_cmdline_v3(boot_img_hdr_v3* h, const std::string& cmdline) {
     if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
     strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+    if (h->header_version == 3) {
+        return bootimg_set_cmdline_v3(reinterpret_cast<boot_img_hdr_v3*>(h), cmdline);
+    }
+    if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
+}
+
+static boot_img_hdr_v3* mkbootimg_v3(const std::vector<char>& kernel,
+                                     const std::vector<char>& ramdisk, const boot_img_hdr_v2& src,
+                                     std::vector<char>* out) {
+#define V3_PAGE_SIZE 4096
+    const size_t page_mask = V3_PAGE_SIZE - 1;
+    int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
+    int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
+
+    int64_t bootimg_size = V3_PAGE_SIZE + kernel_actual + ramdisk_actual;
+    out->resize(bootimg_size);
+
+    boot_img_hdr_v3* hdr = reinterpret_cast<boot_img_hdr_v3*>(out->data());
+
+    memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
+    hdr->kernel_size = kernel.size();
+    hdr->ramdisk_size = ramdisk.size();
+    hdr->os_version = src.os_version;
+    hdr->header_size = sizeof(boot_img_hdr_v3);
+    hdr->header_version = 3;
+
+    memcpy(hdr->magic + V3_PAGE_SIZE, kernel.data(), kernel.size());
+    memcpy(hdr->magic + V3_PAGE_SIZE + kernel_actual, ramdisk.data(), ramdisk.size());
+
+    return hdr;
+}
+
 boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
                            const std::vector<char>& second, const std::vector<char>& dtb,
                            size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
+    if (src.header_version == 3) {
+        if (!second.empty() || !dtb.empty()) {
+            die("Second stage bootloader and dtb not supported in v3 boot image\n");
+        }
+        return reinterpret_cast<boot_img_hdr_v2*>(mkbootimg_v3(kernel, ramdisk, src, out));
+    }
     const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7fdc28b..7f6e723 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -464,7 +464,7 @@
     }
 
     // Is this actually a boot image?
-    if (kernel_data.size() < sizeof(boot_img_hdr_v2)) {
+    if (kernel_data.size() < sizeof(boot_img_hdr_v3)) {
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
@@ -493,7 +493,7 @@
 
     std::vector<char> dtb_data;
     if (!g_dtb_path.empty()) {
-        if (g_boot_img_hdr.header_version < 2) {
+        if (g_boot_img_hdr.header_version != 2) {
                     die("Argument dtb not supported for boot image header version %d\n",
                         g_boot_img_hdr.header_version);
         }
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 2e46b4f..46018b9 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -737,15 +737,33 @@
     unsigned long mountflags = entry.flags;
     int ret = 0;
     int save_errno = 0;
+    int gc_allowance = 0;
+    std::string opts;
+    bool try_f2fs_gc_allowance = is_f2fs(entry.fs_type) && entry.fs_checkpoint_opts.length() > 0;
+    Timer t;
+
     do {
+        if (save_errno == EINVAL && try_f2fs_gc_allowance) {
+            PINFO << "Kernel does not support checkpoint=disable:[n]%, trying without.";
+            try_f2fs_gc_allowance = false;
+        }
+        if (try_f2fs_gc_allowance) {
+            opts = entry.fs_options + entry.fs_checkpoint_opts + ":" +
+                   std::to_string(gc_allowance) + "%";
+        } else {
+            opts = entry.fs_options;
+        }
         if (save_errno == EAGAIN) {
             PINFO << "Retrying mount (source=" << source << ",target=" << target
-                  << ",type=" << entry.fs_type << ")=" << ret << "(" << save_errno << ")";
+                  << ",type=" << entry.fs_type << ", gc_allowance=" << gc_allowance << "%)=" << ret
+                  << "(" << save_errno << ")";
         }
         ret = mount(source.c_str(), target.c_str(), entry.fs_type.c_str(), mountflags,
-                    entry.fs_options.c_str());
+                    opts.c_str());
         save_errno = errno;
-    } while (ret && save_errno == EAGAIN);
+        if (try_f2fs_gc_allowance) gc_allowance += 10;
+    } while ((ret && save_errno == EAGAIN && gc_allowance <= 100) ||
+             (ret && save_errno == EINVAL && try_f2fs_gc_allowance));
     const char* target_missing = "";
     const char* source_missing = "";
     if (save_errno == ENOENT) {
@@ -761,6 +779,8 @@
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_mgr_set_blk_ro(source);
     }
+    android::base::SetProperty("ro.boottime.init.mount." + Basename(target),
+                               std::to_string(t.duration().count()));
     errno = save_errno;
     return ret;
 }
@@ -1075,7 +1095,7 @@
     bool UpdateCheckpointPartition(FstabEntry* entry, const std::string& block_device) {
         if (entry->fs_mgr_flags.checkpoint_fs) {
             if (is_f2fs(entry->fs_type)) {
-                entry->fs_options += ",checkpoint=disable";
+                entry->fs_checkpoint_opts = ",checkpoint=disable";
             } else {
                 LERROR << entry->fs_type << " does not implement checkpoints.";
             }
@@ -1589,76 +1609,58 @@
     }
 }
 
-static std::string ResolveBlockDevice(const std::string& block_device) {
+static bool UnwindDmDeviceStack(const std::string& block_device,
+                                std::vector<std::string>* dm_stack) {
     if (!StartsWith(block_device, "/dev/block/")) {
         LWARNING << block_device << " is not a block device";
-        return block_device;
+        return false;
     }
-    std::string name = block_device.substr(5);
-    if (!StartsWith(name, "block/dm-")) {
-        // Not a dm-device, but might be a symlink. Optimistically try to readlink.
-        std::string result;
-        if (Readlink(block_device, &result)) {
-            return result;
-        } else if (errno == EINVAL) {
-            // After all, it wasn't a symlink.
-            return block_device;
-        } else {
-            LERROR << "Failed to readlink " << block_device;
-            return "";
-        }
-    }
-    // It's a dm-device, let's find what's inside!
-    std::string sys_dir = "/sys/" + name;
+    std::string current = block_device;
+    DeviceMapper& dm = DeviceMapper::Instance();
     while (true) {
-        std::string slaves_dir = sys_dir + "/slaves";
-        std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
-        if (!dir) {
-            LERROR << "Failed to open " << slaves_dir;
-            return "";
+        dm_stack->push_back(current);
+        if (!dm.IsDmBlockDevice(current)) {
+            break;
         }
-        std::string sub_device_name = "";
-        for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
-            if (entry->d_type != DT_LNK) continue;
-            if (!sub_device_name.empty()) {
-                LERROR << "Too many slaves in " << slaves_dir;
-                return "";
-            }
-            sub_device_name = entry->d_name;
+        auto parent = dm.GetParentBlockDeviceByPath(current);
+        if (!parent) {
+            return false;
         }
-        if (sub_device_name.empty()) {
-            LERROR << "No slaves in " << slaves_dir;
-            return "";
-        }
-        if (!StartsWith(sub_device_name, "dm-")) {
-            // Not a dm-device! We can stop now.
-            return "/dev/block/" + sub_device_name;
-        }
-        // Still a dm-device, keep digging.
-        sys_dir = "/sys/block/" + sub_device_name;
+        current = *parent;
     }
+    return true;
 }
 
 FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab, const FstabEntry& mounted_entry) {
-    std::string resolved_block_device = ResolveBlockDevice(mounted_entry.blk_device);
-    if (resolved_block_device.empty()) {
+    if (mounted_entry.mount_point != "/data") {
+        LERROR << mounted_entry.mount_point << " is not /data";
         return nullptr;
     }
-    LINFO << "/data is mounted on " << resolved_block_device;
+    std::vector<std::string> dm_stack;
+    if (!UnwindDmDeviceStack(mounted_entry.blk_device, &dm_stack)) {
+        LERROR << "Failed to unwind dm-device stack for " << mounted_entry.blk_device;
+        return nullptr;
+    }
     for (auto& entry : *fstab) {
         if (entry.mount_point != "/data") {
             continue;
         }
         std::string block_device;
-        if (!Readlink(entry.blk_device, &block_device)) {
-            LWARNING << "Failed to readlink " << entry.blk_device;
+        if (entry.fs_mgr_flags.logical) {
+            if (!fs_mgr_update_logical_partition(&entry)) {
+                LERROR << "Failed to update logic partition " << entry.blk_device;
+                continue;
+            }
+            block_device = entry.blk_device;
+        } else if (!Readlink(entry.blk_device, &block_device)) {
+            PWARNING << "Failed to read link " << entry.blk_device;
             block_device = entry.blk_device;
         }
-        if (block_device == resolved_block_device) {
+        if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
             return &entry;
         }
     }
-    LERROR << "Didn't find entry that was used to mount /data";
+    LERROR << "Didn't find entry that was used to mount /data onto " << mounted_entry.blk_device;
     return nullptr;
 }
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 009c04c..7cf4f89 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -36,6 +36,7 @@
     std::string fs_type;
     unsigned long flags = 0;
     std::string fs_options;
+    std::string fs_checkpoint_opts;
     std::string key_loc;
     std::string metadata_key_dir;
     std::string metadata_encryption;
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 96c36ed..5e29d4e 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -19,7 +19,6 @@
 #include <android-base/properties.h>
 #include <android/gsi/BnProgressCallback.h>
 #include <android/gsi/IGsiService.h>
-#include <android/gsi/IGsid.h>
 #include <binder/IServiceManager.h>
 #include <libfiemap/image_manager.h>
 #include <libgsi/libgsi.h>
@@ -225,54 +224,22 @@
     return false;
 }
 
-static android::sp<IGsid> AcquireIGsid(const std::chrono::milliseconds& timeout_ms) {
-    if (android::base::GetProperty("init.svc.gsid", "") != "running") {
-        if (!android::base::SetProperty("ctl.start", "gsid") ||
-            !android::base::WaitForProperty("init.svc.gsid", "running", timeout_ms)) {
-            LOG(ERROR) << "Could not start the gsid service";
-            return nullptr;
-        }
-        // Sleep for 250ms to give the service time to register.
-        usleep(250 * 1000);
-    }
+static sp<IGsiService> GetGsiService() {
     auto sm = android::defaultServiceManager();
     auto name = android::String16(kGsiServiceName);
-    auto service = sm->checkService(name);
-    return android::interface_cast<IGsid>(service);
-}
-
-static android::sp<IGsid> GetGsiService(const std::chrono::milliseconds& timeout_ms) {
-    auto start_time = std::chrono::steady_clock::now();
-
-    std::chrono::milliseconds elapsed = std::chrono::milliseconds::zero();
-    do {
-        if (auto gsid = AcquireIGsid(timeout_ms - elapsed); gsid != nullptr) {
-            return gsid;
-        }
-        auto now = std::chrono::steady_clock::now();
-        elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
-    } while (elapsed <= timeout_ms);
-
-    LOG(ERROR) << "Timed out trying to acquire IGsid interface";
+    android::sp<android::IBinder> res = sm->waitForService(name);
+    if (res) {
+        return android::interface_cast<IGsiService>(res);
+    }
     return nullptr;
 }
 
-std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir,
-                                                   const std::chrono::milliseconds& timeout_ms) {
-    auto gsid = GetGsiService(timeout_ms);
-    if (!gsid) {
-        return nullptr;
-    }
-
-    android::sp<IGsiService> service;
-    auto status = gsid->getClient(&service);
-    if (!status.isOk() || !service) {
-        LOG(ERROR) << "Could not acquire IGsiService";
-        return nullptr;
-    }
-
+std::unique_ptr<IImageManager> IImageManager::Open(
+        const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
+    android::sp<IGsiService> service = GetGsiService();
     android::sp<IImageService> manager;
-    status = service->openImageService(dir, &manager);
+
+    auto status = service->openImageService(dir, &manager);
     if (!status.isOk() || !manager) {
         LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().string();
         return nullptr;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 68a81ed..957c26c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -74,7 +74,8 @@
 
 static constexpr const std::string_view kCowGroupName = "cow";
 
-bool SourceCopyOperationIsClone(const chromeos_update_engine::InstallOperation& operation);
+bool OptimizeSourceCopyOperation(const chromeos_update_engine::InstallOperation& operation,
+                                 chromeos_update_engine::InstallOperation* optimized);
 
 enum class CreateResult : unsigned int {
     ERROR,
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 61f5c0c..efdb59f 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -62,17 +62,68 @@
     return false;
 }
 
-bool SourceCopyOperationIsClone(const InstallOperation& operation) {
-    using ChromeOSExtent = chromeos_update_engine::Extent;
-    if (operation.src_extents().size() != operation.dst_extents().size()) {
+bool OptimizeSourceCopyOperation(const InstallOperation& operation, InstallOperation* optimized) {
+    if (operation.type() != InstallOperation::SOURCE_COPY) {
         return false;
     }
-    return std::equal(operation.src_extents().begin(), operation.src_extents().end(),
-                      operation.dst_extents().begin(),
-                      [](const ChromeOSExtent& src, const ChromeOSExtent& dst) {
-                          return src.start_block() == dst.start_block() &&
-                                 src.num_blocks() == dst.num_blocks();
-                      });
+
+    optimized->Clear();
+    optimized->set_type(InstallOperation::SOURCE_COPY);
+
+    const auto& src_extents = operation.src_extents();
+    const auto& dst_extents = operation.dst_extents();
+
+    // If input is empty, skip by returning an empty result.
+    if (src_extents.empty() && dst_extents.empty()) {
+        return true;
+    }
+
+    auto s_it = src_extents.begin();
+    auto d_it = dst_extents.begin();
+    uint64_t s_offset = 0;  // offset within *s_it
+    uint64_t d_offset = 0;  // offset within *d_it
+    bool is_optimized = false;
+
+    while (s_it != src_extents.end() || d_it != dst_extents.end()) {
+        if (s_it == src_extents.end() || d_it == dst_extents.end()) {
+            LOG(ERROR) << "number of blocks do not equal in src_extents and dst_extents";
+            return false;
+        }
+        if (s_it->num_blocks() <= s_offset || d_it->num_blocks() <= d_offset) {
+            LOG(ERROR) << "Offset goes out of bounds.";
+            return false;
+        }
+
+        // Check the next |step| blocks, where |step| is the min of remaining blocks in the current
+        // source extent and current destination extent.
+        auto s_step = s_it->num_blocks() - s_offset;
+        auto d_step = d_it->num_blocks() - d_offset;
+        auto step = std::min(s_step, d_step);
+
+        bool moved = s_it->start_block() + s_offset != d_it->start_block() + d_offset;
+        if (moved) {
+            // If the next |step| blocks are not copied to the same location, add them to result.
+            AppendExtent(optimized->mutable_src_extents(), s_it->start_block() + s_offset, step);
+            AppendExtent(optimized->mutable_dst_extents(), d_it->start_block() + d_offset, step);
+        } else {
+            // The next |step| blocks are optimized out.
+            is_optimized = true;
+        }
+
+        // Advance offsets by |step|, and go to the next non-empty extent if the current extent is
+        // depleted.
+        s_offset += step;
+        d_offset += step;
+        while (s_it != src_extents.end() && s_offset >= s_it->num_blocks()) {
+            ++s_it;
+            s_offset = 0;
+        }
+        while (d_it != dst_extents.end() && d_offset >= d_it->num_blocks()) {
+            ++d_it;
+            d_offset = 0;
+        }
+    }
+    return is_optimized;
 }
 
 void WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Extent& de,
@@ -101,12 +152,15 @@
     if (operations == nullptr) return sc.cow_size_bytes();
 
     for (const auto& iop : *operations) {
-        // Do not allocate space for operations that are going to be skipped
+        const InstallOperation* written_op = &iop;
+        InstallOperation buf;
+        // Do not allocate space for extents that are going to be skipped
         // during OTA application.
-        if (iop.type() == InstallOperation::SOURCE_COPY && SourceCopyOperationIsClone(iop))
-            continue;
+        if (iop.type() == InstallOperation::SOURCE_COPY && OptimizeSourceCopyOperation(iop, &buf)) {
+            written_op = &buf;
+        }
 
-        for (const auto& de : iop.dst_extents()) {
+        for (const auto& de : written_op->dst_extents()) {
             WriteExtent(&sc, de, sectors_per_block);
         }
     }
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index 9da3f05..526f874 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <optional>
+#include <tuple>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <libdm/dm.h>
@@ -26,6 +29,13 @@
 
 using namespace android::fs_mgr;
 
+using chromeos_update_engine::InstallOperation;
+using UeExtent = chromeos_update_engine::Extent;
+using google::protobuf::RepeatedPtrField;
+using ::testing::Matches;
+using ::testing::Pointwise;
+using ::testing::Truly;
+
 namespace android {
 namespace snapshot {
 
@@ -213,5 +223,76 @@
     }
 }
 
+void BlocksToExtents(const std::vector<uint64_t>& blocks,
+                     google::protobuf::RepeatedPtrField<UeExtent>* extents) {
+    for (uint64_t block : blocks) {
+        AppendExtent(extents, block, 1);
+    }
+}
+
+template <typename T>
+std::vector<uint64_t> ExtentsToBlocks(const T& extents) {
+    std::vector<uint64_t> blocks;
+    for (const auto& extent : extents) {
+        for (uint64_t offset = 0; offset < extent.num_blocks(); ++offset) {
+            blocks.push_back(extent.start_block() + offset);
+        }
+    }
+    return blocks;
+}
+
+InstallOperation CreateCopyOp(const std::vector<uint64_t>& src_blocks,
+                              const std::vector<uint64_t>& dst_blocks) {
+    InstallOperation op;
+    op.set_type(InstallOperation::SOURCE_COPY);
+    BlocksToExtents(src_blocks, op.mutable_src_extents());
+    BlocksToExtents(dst_blocks, op.mutable_dst_extents());
+    return op;
+}
+
+// ExtentEqual(tuple<UeExtent, UeExtent>)
+MATCHER(ExtentEqual, "") {
+    auto&& [a, b] = arg;
+    return a.start_block() == b.start_block() && a.num_blocks() == b.num_blocks();
+}
+
+struct OptimizeOperationTestParam {
+    InstallOperation input;
+    std::optional<InstallOperation> expected_output;
+};
+
+class OptimizeOperationTest : public ::testing::TestWithParam<OptimizeOperationTestParam> {};
+TEST_P(OptimizeOperationTest, Test) {
+    InstallOperation actual_output;
+    EXPECT_EQ(GetParam().expected_output.has_value(),
+              OptimizeSourceCopyOperation(GetParam().input, &actual_output))
+            << "OptimizeSourceCopyOperation should "
+            << (GetParam().expected_output.has_value() ? "succeed" : "fail");
+    if (!GetParam().expected_output.has_value()) return;
+    EXPECT_THAT(actual_output.src_extents(),
+                Pointwise(ExtentEqual(), GetParam().expected_output->src_extents()));
+    EXPECT_THAT(actual_output.dst_extents(),
+                Pointwise(ExtentEqual(), GetParam().expected_output->dst_extents()));
+}
+
+std::vector<OptimizeOperationTestParam> GetOptimizeOperationTestParams() {
+    return {
+            {CreateCopyOp({}, {}), CreateCopyOp({}, {})},
+            {CreateCopyOp({1, 2, 4}, {1, 2, 4}), CreateCopyOp({}, {})},
+            {CreateCopyOp({1, 2, 3}, {4, 5, 6}), std::nullopt},
+            {CreateCopyOp({3, 2}, {1, 2}), CreateCopyOp({3}, {1})},
+            {CreateCopyOp({5, 6, 3, 4, 1, 2}, {1, 2, 3, 4, 5, 6}),
+             CreateCopyOp({5, 6, 1, 2}, {1, 2, 5, 6})},
+            {CreateCopyOp({1, 2, 3, 5, 5, 6}, {5, 6, 3, 4, 1, 2}),
+             CreateCopyOp({1, 2, 5, 5, 6}, {5, 6, 4, 1, 2})},
+            {CreateCopyOp({1, 2, 5, 6, 9, 10}, {1, 4, 5, 6, 7, 8}),
+             CreateCopyOp({2, 9, 10}, {4, 7, 8})},
+            {CreateCopyOp({2, 3, 3, 4, 4}, {1, 2, 3, 4, 5}), CreateCopyOp({2, 3, 4}, {1, 2, 5})},
+    };
+}
+
+INSTANTIATE_TEST_CASE_P(Snapshot, OptimizeOperationTest,
+                        ::testing::ValuesIn(GetOptimizeOperationTestParams()));
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 3318b33..d32b61e 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -34,6 +34,7 @@
 using android::fs_mgr::MetadataBuilder;
 using android::fs_mgr::Partition;
 using android::fs_mgr::ReadDefaultFstab;
+using google::protobuf::RepeatedPtrField;
 
 namespace android {
 namespace snapshot {
@@ -166,5 +167,20 @@
     return os << std::put_time(&now, "%Y%m%d-%H%M%S");
 }
 
+void AppendExtent(RepeatedPtrField<chromeos_update_engine::Extent>* extents, uint64_t start_block,
+                  uint64_t num_blocks) {
+    if (extents->size() > 0) {
+        auto last_extent = extents->rbegin();
+        auto next_block = last_extent->start_block() + last_extent->num_blocks();
+        if (start_block == next_block) {
+            last_extent->set_num_blocks(last_extent->num_blocks() + num_blocks);
+            return;
+        }
+    }
+    auto* new_extent = extents->Add();
+    new_extent->set_start_block(start_block);
+    new_extent->set_num_blocks(num_blocks);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 90ad0fe..e69bdad 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -125,5 +125,9 @@
 struct Now {};
 std::ostream& operator<<(std::ostream& os, const Now&);
 
+// Append to |extents|. Merged into the last element if possible.
+void AppendExtent(google::protobuf::RepeatedPtrField<chromeos_update_engine::Extent>* extents,
+                  uint64_t start_block, uint64_t num_blocks);
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 52628f3..72a7bfe 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -28,7 +28,6 @@
     "rlimit_parser.cpp",
     "service.cpp",
     "service_list.cpp",
-    "service_lock.cpp",
     "service_parser.cpp",
     "service_utils.cpp",
     "subcontext.cpp",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index dd5af72..200bfff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -151,7 +151,6 @@
 
 template <typename F>
 static void ForEachServiceInClass(const std::string& classname, F function) {
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(classname)) std::invoke(function, service);
     }
@@ -163,7 +162,6 @@
         return {};
     // Starting a class does not start services which are explicitly disabled.
     // They must  be started individually.
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfNotDisabled(); !result.ok()) {
@@ -186,7 +184,6 @@
         // stopped either.
         return {};
     }
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfPostData(); !result.ok()) {
@@ -237,7 +234,6 @@
 }
 
 static Result<void> do_enable(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "Could not find service";
 
@@ -249,7 +245,6 @@
 }
 
 static Result<void> do_exec(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec service: " << service.error();
@@ -263,7 +258,6 @@
 }
 
 static Result<void> do_exec_background(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec background service: " << service.error();
@@ -277,7 +271,6 @@
 }
 
 static Result<void> do_exec_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* service = ServiceList::GetInstance().FindService(args[1]);
     if (!service) {
         return Error() << "Service not found";
@@ -347,7 +340,6 @@
 }
 
 static Result<void> do_interface_restart(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Restart();
@@ -355,7 +347,6 @@
 }
 
 static Result<void> do_interface_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -365,7 +356,6 @@
 }
 
 static Result<void> do_interface_stop(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Stop();
@@ -750,7 +740,6 @@
 }
 
 static Result<void> do_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -760,7 +749,6 @@
 }
 
 static Result<void> do_stop(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Stop();
@@ -768,7 +756,6 @@
 }
 
 static Result<void> do_restart(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Restart();
@@ -1124,7 +1111,6 @@
             function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
         }
     });
-    auto lock = std::lock_guard{service_lock};
     if (auto result = (*service)->ExecStart(); !result.ok()) {
         function("ExecStart failed: " + result.error().message());
     }
@@ -1264,7 +1250,6 @@
         }
         success &= parser.ParseConfigFile(c);
     }
-    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().MarkServicesUpdate();
     if (success) {
         return {};
diff --git a/init/init.cpp b/init/init.cpp
index b0f929c..4289dcf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -99,6 +99,15 @@
 
 static std::unique_ptr<Subcontext> subcontext;
 
+struct PendingControlMessage {
+    std::string message;
+    std::string name;
+    pid_t pid;
+    int fd;
+};
+static std::mutex pending_control_messages_lock;
+static std::queue<PendingControlMessage> pending_control_messages;
+
 // Init epolls various FDs to wait for various inputs.  It previously waited on property changes
 // with a blocking socket that contained the information related to the change, however, it was easy
 // to fill that socket and deadlock the system.  Now we use locks to handle the property changes
@@ -120,7 +129,7 @@
         }
     };
 
-    if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
+    if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 }
@@ -238,7 +247,6 @@
 } shutdown_state;
 
 void DumpState() {
-    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().DumpState();
     ActionManager::GetInstance().DumpState();
 }
@@ -312,7 +320,6 @@
 
 static std::optional<boot_clock::time_point> HandleProcessActions() {
     std::optional<boot_clock::time_point> next_process_action_time;
-    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
             auto timeout_time = s->time_started() + *s->timeout_period();
@@ -341,7 +348,7 @@
     return next_process_action_time;
 }
 
-static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlStart(Service* service) {
     return service->Start();
 }
 
@@ -350,7 +357,7 @@
     return {};
 }
 
-static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlRestart(Service* service) {
     service->Restart();
     return {};
 }
@@ -384,7 +391,7 @@
     return control_message_functions;
 }
 
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
     const auto& map = get_control_message_map();
     const auto it = map.find(msg);
 
@@ -393,7 +400,7 @@
         return false;
     }
 
-    std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
+    std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
     std::string process_cmdline;
     if (ReadFileToString(cmdline_path, &process_cmdline)) {
         std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -404,8 +411,6 @@
 
     const ControlMessageFunction& function = it->second;
 
-    auto lock = std::lock_guard{service_lock};
-
     Service* svc = nullptr;
 
     switch (function.target) {
@@ -423,22 +428,59 @@
 
     if (svc == nullptr) {
         LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
-                   << " from pid: " << from_pid << " (" << process_cmdline << ")";
+                   << " from pid: " << pid << " (" << process_cmdline << ")";
         return false;
     }
 
     if (auto result = function.action(svc); !result.ok()) {
         LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
-                   << "' from pid: " << from_pid << " (" << process_cmdline
-                   << "): " << result.error();
+                   << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
         return false;
     }
 
     LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
-              << "' from pid: " << from_pid << " (" << process_cmdline << ")";
+              << "' from pid: " << pid << " (" << process_cmdline << ")";
     return true;
 }
 
+bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd) {
+    auto lock = std::lock_guard{pending_control_messages_lock};
+    if (pending_control_messages.size() > 100) {
+        LOG(ERROR) << "Too many pending control messages, dropped '" << message << "' for '" << name
+                   << "' from pid: " << pid;
+        return false;
+    }
+    pending_control_messages.push({message, name, pid, fd});
+    WakeEpoll();
+    return true;
+}
+
+static void HandleControlMessages() {
+    auto lock = std::unique_lock{pending_control_messages_lock};
+    // Init historically would only execute handle one property message, including control messages
+    // in each iteration of its main loop.  We retain this behavior here to prevent starvation of
+    // other actions in the main loop.
+    if (!pending_control_messages.empty()) {
+        auto control_message = pending_control_messages.front();
+        pending_control_messages.pop();
+        lock.unlock();
+
+        bool success = HandleControlMessage(control_message.message, control_message.name,
+                                            control_message.pid);
+
+        uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+        if (control_message.fd != -1) {
+            TEMP_FAILURE_RETRY(send(control_message.fd, &response, sizeof(response), 0));
+            close(control_message.fd);
+        }
+        lock.lock();
+    }
+    // If we still have items to process, make sure we wake back up to do so.
+    if (!pending_control_messages.empty()) {
+        WakeEpoll();
+    }
+}
+
 static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
     if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
         LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
@@ -588,7 +630,6 @@
     }
 
     auto found = false;
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         auto svc = service.get();
         if (svc->keycodes() == keycodes) {
@@ -659,22 +700,6 @@
     }
 }
 
-void SendStopSendingMessagesMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_stop_sending_messages(true);
-    if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
-        LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error();
-    }
-}
-
-void SendStartSendingMessagesMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_start_sending_messages(true);
-    if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
-        LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error();
-    }
-}
-
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -688,8 +713,15 @@
     InitKernelLogging(argv);
     LOG(INFO) << "init second stage started!";
 
-    // Will handle EPIPE at the time of write by checking the errno
-    signal(SIGPIPE, SIG_IGN);
+    // Init should not crash because of a dependence on any other process, therefore we ignore
+    // SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN
+    // is inherited across exec, but custom signal handlers are not.  Since we do not want to
+    // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
+    {
+        struct sigaction action = {.sa_flags = SA_RESTART};
+        action.sa_handler = [](int) {};
+        sigaction(SIGPIPE, &action, nullptr);
+    }
 
     // Set init and its forked children's oom_adj.
     if (auto result =
@@ -796,7 +828,6 @@
     Keychords keychords;
     am.QueueBuiltinAction(
             [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
-                auto lock = std::lock_guard{service_lock};
                 for (const auto& svc : ServiceList::GetInstance()) {
                     keychords.Register(svc->keycodes());
                 }
@@ -863,6 +894,7 @@
                 (*function)();
             }
         }
+        HandleControlMessages();
     }
 
     return 0;
diff --git a/init/init.h b/init/init.h
index bcf24e7..27f64e2 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,11 +38,9 @@
 void ResetWaitForProp();
 
 void SendLoadPersistentPropertiesMessage();
-void SendStopSendingMessagesMessage();
-void SendStartSendingMessagesMessage();
 
 void PropertyChanged(const std::string& name, const std::string& value);
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
+bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd);
 
 int SecondStageMain(int argc, char** argv);
 
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3053bd8..caf3e03 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -167,7 +167,6 @@
 
     ServiceList service_list;
     TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
-    auto lock = std::lock_guard{service_lock};
     ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
 
     auto service = service_list.begin()->get();
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index a531d0a..dd1ab4d 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,8 +79,7 @@
 }
 
 static void RegisterServices(pid_t exclude_pid) {
-    auto lock = std::lock_guard{service_lock};
-    for (const auto& service : ServiceList::GetInstance()) {
+    for (const auto& service : ServiceList::GetInstance().services()) {
         auto svc = service.get();
         if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
             // skip if process is excluded or not yet forked (pid==0)
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 2175075..0749fe3 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -29,7 +29,6 @@
 #include <android-base/unique_fd.h>
 #include <apex_manifest.pb.h>
 
-#include "property_service.h"
 #include "util.h"
 
 namespace android {
@@ -291,14 +290,6 @@
         return true;
     }
     if (default_ns_id != GetMountNamespaceId()) {
-        // The property service thread and its descendent threads must be in the correct mount
-        // namespace to call Service::Start(), however setns() only operates on a single thread and
-        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
-        // must join the property service thread and its descendents before the setns() call.  Those
-        // threads are then started again after the setns() call, and they'll be in the proper
-        // namespace.
-        PausePropertyService();
-
         if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
             return false;
@@ -308,8 +299,6 @@
             LOG(ERROR) << result.error();
             return false;
         }
-
-        ResumePropertyService();
     }
 
     LOG(INFO) << "Switched to default mount namespace";
@@ -323,20 +312,10 @@
     }
     if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
         IsApexUpdatable()) {
-        // The property service thread and its descendent threads must be in the correct mount
-        // namespace to call Service::Start(), however setns() only operates on a single thread and
-        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
-        // must join the property service thread and its descendents before the setns() call.  Those
-        // threads are then started again after the setns() call, and they'll be in the proper
-        // namespace.
-        PausePropertyService();
-
         if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
             return false;
         }
-
-        ResumePropertyService();
     }
     return true;
 }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 319a241..8206522 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -95,6 +95,7 @@
 static int from_init_socket = -1;
 static int init_socket = -1;
 static bool accept_messages = false;
+static std::mutex accept_messages_lock;
 static std::thread property_service_thread;
 
 static PropertyInfoAreaFile property_info_area;
@@ -117,6 +118,16 @@
     return 0;
 }
 
+void StartSendingMessages() {
+    auto lock = std::lock_guard{accept_messages_lock};
+    accept_messages = true;
+}
+
+void StopSendingMessages() {
+    auto lock = std::lock_guard{accept_messages_lock};
+    accept_messages = true;
+}
+
 bool CanReadProperty(const std::string& source_context, const std::string& name) {
     const char* target_context = nullptr;
     property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
@@ -186,138 +197,49 @@
     }
     // 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.
+    auto lock = std::lock_guard{accept_messages_lock};
     if (accept_messages) {
         PropertyChanged(name, value);
     }
     return PROP_SUCCESS;
 }
 
-template <typename T>
-class SingleThreadExecutor {
+class AsyncRestorecon {
   public:
-    virtual ~SingleThreadExecutor() {}
-
-    template <typename F = T>
-    void Run(F&& item) {
+    void TriggerRestorecon(const std::string& path) {
         auto guard = std::lock_guard{mutex_};
-        items_.emplace(std::forward<F>(item));
+        paths_.emplace(path);
 
-        if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
-            return;
-        }
-
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        }
-
-        StartThread();
-    }
-
-    void StopAndJoin() {
-        auto lock = std::unique_lock{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        } else if (thread_state_ == ThreadState::kRunning) {
-            thread_state_ = ThreadState::kStopped;
-            lock.unlock();
-            thread_.join();
-            lock.lock();
-        }
-
-        thread_state_ = ThreadState::kStopped;
-    }
-
-    void Restart() {
-        auto guard = std::lock_guard{mutex_};
-        if (items_.empty()) {
-            thread_state_ = ThreadState::kNotStarted;
-        } else {
-            StartThread();
-        }
-    }
-
-    void MaybeJoin() {
-        auto guard = std::lock_guard{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-            thread_state_ = ThreadState::kNotStarted;
+        if (!thread_started_) {
+            thread_started_ = true;
+            std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
         }
     }
 
   private:
-    virtual void Execute(T&& item) = 0;
-
-    void StartThread() {
-        thread_state_ = ThreadState::kRunning;
-        auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
-        std::swap(thread_, thread);
-    }
-
     void ThreadFunction() {
         auto lock = std::unique_lock{mutex_};
 
-        while (!items_.empty()) {
-            auto item = items_.front();
-            items_.pop();
+        while (!paths_.empty()) {
+            auto path = paths_.front();
+            paths_.pop();
 
             lock.unlock();
-            Execute(std::move(item));
+            if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+                LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+            }
+            android::base::SetProperty(kRestoreconProperty, path);
             lock.lock();
         }
 
-        if (thread_state_ != ThreadState::kStopped) {
-            thread_state_ = ThreadState::kPendingJoin;
-        }
+        thread_started_ = false;
     }
 
     std::mutex mutex_;
-    std::queue<T> items_;
-    enum class ThreadState {
-        kNotStarted,  // Initial state when starting the program or when restarting with no items to
-                      // process.
-        kRunning,     // The thread is running and is in a state that it will process new items if
-                      // are run.
-        kPendingJoin,  // The thread has run to completion and is pending join().  A new thread must
-                       // be launched for new items to be processed.
-        kStopped,  // This executor has stopped and will not process more items until Restart() is
-                   // called.  Currently pending items will be processed and the thread will be
-                   // joined.
-    };
-    ThreadState thread_state_ = ThreadState::kNotStarted;
-    std::thread thread_;
+    std::queue<std::string> paths_;
+    bool thread_started_ = false;
 };
 
-class RestoreconThread : public SingleThreadExecutor<std::string> {
-    virtual void Execute(std::string&& path) override {
-        if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
-            LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
-        }
-        android::base::SetProperty(kRestoreconProperty, path);
-    }
-};
-
-struct ControlMessageInfo {
-    std::string message;
-    std::string name;
-    pid_t pid;
-    int fd;
-};
-
-class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
-    virtual void Execute(ControlMessageInfo&& info) override {
-        bool success = HandleControlMessage(info.message, info.name, info.pid);
-
-        uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-        if (info.fd != -1) {
-            TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
-            close(info.fd);
-        }
-    }
-};
-
-static RestoreconThread restorecon_thread;
-static ControlMessageThread control_message_thread;
-
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -454,22 +376,25 @@
 
 static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
                                    SocketConnection* socket, std::string* error) {
+    auto lock = std::lock_guard{accept_messages_lock};
     if (!accept_messages) {
         *error = "Received control message after shutdown, ignoring";
         return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
     }
 
-    // We must release the fd before spawning the thread, otherwise there will be a race with the
-    // thread. If the thread calls close() before this function calls Release(), then fdsan will see
-    // the wrong tag and abort().
+    // 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 && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
         fd = socket->Release();
     }
 
-    // Handling a control message likely calls SetProperty, which we must synchronously handle,
-    // therefore we must fork a thread to handle it.
-    control_message_thread.Run({msg, name, pid, fd});
+    bool queue_success = QueueControlMessage(msg, name, pid, fd);
+    if (!queue_success && fd != -1) {
+        uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+        TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
+        close(fd);
+    }
 
     return PROP_SUCCESS;
 }
@@ -571,7 +496,8 @@
     // We use a thread to do this restorecon operation to prevent holding up init, as it may take
     // a long time to complete.
     if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
-        restorecon_thread.Run(value);
+        static AsyncRestorecon async_restorecon;
+        async_restorecon.TriggerRestorecon(value);
         return PROP_SUCCESS;
     }
 
@@ -1152,8 +1078,6 @@
     PropertyLoadBootDefaults();
 }
 
-static bool pause_property_service = false;
-
 static void HandleInitSocket() {
     auto message = ReadMessage(init_socket);
     if (!message.ok()) {
@@ -1180,18 +1104,6 @@
             persistent_properties_loaded = true;
             break;
         }
-        case InitMessage::kStopSendingMessages: {
-            accept_messages = false;
-            break;
-        }
-        case InitMessage::kStartSendingMessages: {
-            accept_messages = true;
-            break;
-        }
-        case InitMessage::kPausePropertyService: {
-            pause_property_service = true;
-            break;
-        }
         default:
             LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
     }
@@ -1212,7 +1124,7 @@
         LOG(FATAL) << result.error();
     }
 
-    while (!pause_property_service) {
+    while (true) {
         auto pending_functions = epoll.Wait(std::nullopt);
         if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
@@ -1221,34 +1133,9 @@
                 (*function)();
             }
         }
-        control_message_thread.MaybeJoin();
-        restorecon_thread.MaybeJoin();
     }
 }
 
-void SendStopPropertyServiceMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_pause_property_service(true);
-    if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
-        LOG(ERROR) << "Failed to send stop property service message: " << result.error();
-    }
-}
-
-void PausePropertyService() {
-    control_message_thread.StopAndJoin();
-    restorecon_thread.StopAndJoin();
-    SendStopPropertyServiceMessage();
-    property_service_thread.join();
-}
-
-void ResumePropertyService() {
-    pause_property_service = false;
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
-    restorecon_thread.Restart();
-    control_message_thread.Restart();
-}
-
 void StartPropertyService(int* epoll_socket) {
     InitPropertySet("ro.property_service.version", "2");
 
@@ -1258,7 +1145,7 @@
     }
     *epoll_socket = from_init_socket = sockets[0];
     init_socket = sockets[1];
-    accept_messages = true;
+    StartSendingMessages();
 
     if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    false, 0666, 0, 0, {});
diff --git a/init/property_service.h b/init/property_service.h
index e921326..2d49a36 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -31,8 +31,9 @@
 
 void PropertyInit();
 void StartPropertyService(int* epoll_socket);
-void ResumePropertyService();
-void PausePropertyService();
+
+void StartSendingMessages();
+void StopSendingMessages();
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
index 36245b2..08268d9 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -41,6 +41,5 @@
         bool load_persistent_properties = 1;
         bool stop_sending_messages = 2;
         bool start_sending_messages = 3;
-        bool pause_property_service = 4;
     };
 }
diff --git a/init/reboot.cpp b/init/reboot.cpp
index cad192d..f006df3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -59,6 +59,7 @@
 #include "builtin_arguments.h"
 #include "init.h"
 #include "mount_namespace.h"
+#include "property_service.h"
 #include "reboot_utils.h"
 #include "service.h"
 #include "service_list.h"
@@ -85,7 +86,7 @@
 
 static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
 
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
+static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
     std::vector<Service*> ret;
     ret.reserve(kDebuggingServices.size());
     for (const auto& s : ServiceList::GetInstance()) {
@@ -181,7 +182,7 @@
 };
 
 // Turn off backlight while we are performing power down cleanup activities.
-static void TurnOffBacklight() REQUIRES(service_lock) {
+static void TurnOffBacklight() {
     Service* service = ServiceList::GetInstance().FindService("blank_screen");
     if (service == nullptr) {
         LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
@@ -589,7 +590,6 @@
     // Start reboot monitor thread
     sem_post(&reboot_semaphore);
 
-    auto lock = std::lock_guard{service_lock};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
     const std::set<std::string> to_starts{"watchdogd"};
     std::vector<Service*> stop_first;
@@ -709,21 +709,15 @@
     // Skip wait for prop if it is in progress
     ResetWaitForProp();
     // Clear EXEC flag if there is one pending
-    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         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();
 }
 
 static void LeaveShutdown() {
     LOG(INFO) << "Leaving shutdown mode";
     shutting_down = false;
-    SendStartSendingMessagesMessage();
+    StartSendingMessages();
 }
 
 static Result<void> UnmountAllApexes() {
@@ -753,7 +747,6 @@
         return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
     }
     EnterShutdown();
-    auto lock = std::lock_guard{service_lock};
     if (!SetProperty("sys.powerctl", "")) {
         return Error() << "Failed to reset sys.powerctl property";
     }
@@ -914,7 +907,6 @@
                 run_fsck = true;
             } else if (cmd_params[1] == "thermal") {
                 // Turn off sources of heat immediately.
-                auto lock = std::lock_guard{service_lock};
                 TurnOffBacklight();
                 // run_fsck is false to avoid delay
                 cmd = ANDROID_RB_THERMOFF;
@@ -985,6 +977,10 @@
         return;
     }
 
+    // We do not want to process any messages (queue'ing triggers, shutdown messages, control
+    // messages, etc) from properties during reboot.
+    StopSendingMessages();
+
     if (userspace_reboot) {
         HandleUserspaceReboot();
         return;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index acbcbd6..808cb7f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -539,9 +539,9 @@
 
     // adb remount, snapshot-based updates, and DSUs all create files during
     // first-stage init.
-    selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
-
     selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
+    selinux_android_restorecon("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE |
+                                                        SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.h b/init/service.h
index d2a4462..cf3f0c2 100644
--- a/init/service.h
+++ b/init/service.h
@@ -27,14 +27,12 @@
 #include <vector>
 
 #include <android-base/chrono_utils.h>
-#include <android-base/thread_annotations.h>
 #include <cutils/iosched_policy.h>
 
 #include "action.h"
 #include "capabilities.h"
 #include "keyword_map.h"
 #include "parser.h"
-#include "service_lock.h"
 #include "service_utils.h"
 #include "subcontext.h"
 
@@ -79,17 +77,17 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
-    Result<void> ExecStart() REQUIRES(service_lock);
-    Result<void> Start() REQUIRES(service_lock);
-    Result<void> StartIfNotDisabled() REQUIRES(service_lock);
-    Result<void> StartIfPostData() REQUIRES(service_lock);
-    Result<void> Enable() REQUIRES(service_lock);
+    Result<void> ExecStart();
+    Result<void> Start();
+    Result<void> StartIfNotDisabled();
+    Result<void> StartIfPostData();
+    Result<void> Enable();
     void Reset();
     void ResetIfPostData();
     void Stop();
     void Terminate();
     void Timeout();
-    void Restart() REQUIRES(service_lock);
+    void Restart();
     void Reap(const siginfo_t& siginfo);
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
diff --git a/init/service_list.h b/init/service_list.h
index 280a228..3b9018b 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -17,13 +17,9 @@
 #pragma once
 
 #include <memory>
-#include <mutex>
 #include <vector>
 
-#include <android-base/thread_annotations.h>
-
 #include "service.h"
-#include "service_lock.h"
 
 namespace android {
 namespace init {
@@ -36,16 +32,16 @@
     ServiceList();
     size_t CheckAllCommands();
 
-    void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
-    void RemoveService(const Service& svc) REQUIRES(service_lock);
+    void AddService(std::unique_ptr<Service> service);
+    void RemoveService(const Service& svc);
     template <class UnaryPredicate>
-    void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
+    void RemoveServiceIf(UnaryPredicate predicate) {
         services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
                         services_.end());
     }
 
     template <typename T, typename F = decltype(&Service::name)>
-    Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
+    Service* FindService(T value, F function = &Service::name) const {
         auto svc = std::find_if(services_.begin(), services_.end(),
                                 [&function, &value](const std::unique_ptr<Service>& s) {
                                     return std::invoke(function, s) == value;
@@ -56,7 +52,7 @@
         return nullptr;
     }
 
-    Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
+    Service* FindInterface(const std::string& interface_name) {
         for (const auto& svc : services_) {
             if (svc->interfaces().count(interface_name) > 0) {
                 return svc.get();
@@ -66,20 +62,18 @@
         return nullptr;
     }
 
-    void DumpState() const REQUIRES(service_lock);
+    void DumpState() const;
 
-    auto begin() const REQUIRES(service_lock) { return services_.begin(); }
-    auto end() const REQUIRES(service_lock) { return services_.end(); }
-    const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
-        return services_;
-    }
-    const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
+    auto begin() const { return services_.begin(); }
+    auto end() const { return services_.end(); }
+    const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
+    const std::vector<Service*> services_in_shutdown_order() const;
 
     void MarkPostData();
     bool IsPostData();
-    void MarkServicesUpdate() REQUIRES(service_lock);
+    void MarkServicesUpdate();
     bool IsServicesUpdated() const { return services_update_finished_; }
-    void DelayService(const Service& service) REQUIRES(service_lock);
+    void DelayService(const Service& service);
 
     void ResetState() {
         post_data_ = false;
diff --git a/init/service_lock.h b/init/service_lock.h
deleted file mode 100644
index 6b94271..0000000
--- a/init/service_lock.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <mutex>
-
-#include <android-base/thread_annotations.h>
-
-namespace android {
-namespace init {
-
-// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
-
-class CAPABILITY("mutex") RecursiveMutex {
-  public:
-    void lock() ACQUIRE() { mutex_.lock(); }
-    void unlock() RELEASE() { mutex_.unlock(); }
-
-  private:
-    std::recursive_mutex mutex_;
-};
-
-extern RecursiveMutex service_lock;
-
-}  // namespace init
-}  // namespace android
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 51f4c97..560f693 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -168,7 +168,6 @@
 
     const std::string fullname = interface_name + "/" + instance_name;
 
-    auto lock = std::lock_guard{service_lock};
     for (const auto& svc : *service_list_) {
         if (svc->interfaces().count(fullname) > 0) {
             return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
@@ -599,7 +598,6 @@
         }
     }
 
-    auto lock = std::lock_guard{service_lock};
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 064d64d..9b2c7d9 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -64,8 +64,6 @@
     std::string wait_string;
     Service* service = nullptr;
 
-    auto lock = std::lock_guard{service_lock};
-
     if (SubcontextChildReap(pid)) {
         name = "Subcontext";
     } else {
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 4e93df3..fc06c1d 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -45,13 +45,9 @@
 }
 
 // Socket specific parts of libcutils that are safe to statically link into an APEX.
-cc_library_static {
+cc_library {
     name: "libcutils_sockets",
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
@@ -62,6 +58,7 @@
 
     export_include_dirs: ["include"],
 
+    shared_libs: ["liblog"],
     srcs: ["sockets.cpp"],
     target: {
         linux_bionic: {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index c4e4f85..5805a4d 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -201,6 +201,8 @@
                                            CAP_MASK_LONG(CAP_SETGID),
                                               "system/bin/simpleperf_app_runner" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/e2fsck" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/tune2fs" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/resize2fs" },
     // generic defaults
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
diff --git a/liblog/Android.bp b/liblog/Android.bp
index f1e5118..8410370 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -117,8 +117,12 @@
     logtags: ["event.logtags"],
     compile_multilib: "both",
     apex_available: [
-        "//apex_available:anyapex",
         "//apex_available:platform",
+        // liblog is exceptionally available to the runtime APEX
+        // because the dynamic linker has to use it statically.
+        // See b/151051671
+        "com.android.runtime",
+        // DO NOT add more apex names here
     ],
 }
 
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 1c4ec64..512c7cd 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -56,6 +56,7 @@
 
 #include <stdarg.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 #if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
@@ -154,14 +155,11 @@
   /** The kernel log buffer. */
   LOG_ID_KERNEL = 7,
 
-  LOG_ID_MAX
-} log_id_t;
+  LOG_ID_MAX,
 
-/**
- * Let the logging function choose the best log target.
- * This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
- * unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
-#define LOG_ID_DEFAULT -1
+  /** Let the logging function choose the best log target. */
+  LOG_ID_DEFAULT = 0x7FFFFFFF
+} log_id_t;
 
 /**
  * Writes the constant string `text` to the log buffer `id`,
@@ -186,74 +184,108 @@
  * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
  * and sending log messages to user defined loggers specified in __android_log_set_logger().
  */
-struct __android_logger_data {
-  size_t struct_size; /* Must be set to sizeof(__android_logger_data) and is used for versioning. */
-  int buffer_id;      /* log_id_t or -1 to represent 'default'. */
-  int priority;       /* android_LogPriority values. */
-  const char* tag;
-  const char* file;  /* Optional file name, may be set to nullptr. */
-  unsigned int line; /* Optional line number, ignore if file is nullptr. */
+struct __android_log_message {
+  size_t
+      struct_size;   /** Must be set to sizeof(__android_log_message) and is used for versioning. */
+  int32_t buffer_id; /** {@link log_id_t} values. */
+  int32_t priority;  /** {@link android_LogPriority} values. */
+  const char* tag;   /** The tag for the log message. */
+  const char* file;  /** Optional file name, may be set to nullptr. */
+  uint32_t line;     /** Optional line number, ignore if file is nullptr. */
+  const char* message; /** The log message itself. */
 };
 
 /**
  * Prototype for the 'logger' function that is called for every log message.
  */
-typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
-                                          const char* message);
+typedef void (*__android_logger_function)(const struct __android_log_message* log_message);
 /**
  * Prototype for the 'abort' function that is called when liblog will abort due to
  * __android_log_assert() failures.
  */
 typedef void (*__android_aborter_function)(const char* abort_message);
 
-#if __ANDROID_API__ >= 30 || !defined(__ANDROID__)
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
 /**
- * Writes the log message specified with logger_data and msg to the log.  logger_data includes
- * additional file name and line number information that a logger may use.  logger_data is versioned
- * for backwards compatibility.
+ * Writes the log message specified by log_message.  log_message includes additional file name and
+ * line number information that a logger may use.  log_message is versioned for backwards
+ * compatibility.
  * This assumes that loggability has already been checked through __android_log_is_loggable().
  * Higher level logging libraries, such as libbase, first check loggability, then format their
  * buffers, then pass the message to liblog via this function, and therefore we do not want to
  * duplicate the loggability check here.
+ *
+ * @param log_message the log message itself, see {@link __android_log_message}.
+ *
+ * Available since API level 30.
  */
-void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg)
-    __INTRODUCED_IN(30);
+void __android_log_write_log_message(struct __android_log_message* log_message) __INTRODUCED_IN(30);
 
 /**
  * Sets a user defined logger function.  All log messages sent to liblog will be set to the
- * function pointer specified by logger for processing.
+ * function pointer specified by logger for processing.  It is not expected that log messages are
+ * already terminated with a new line.  This function should add new lines if required for line
+ * separation.
+ *
+ * @param logger the new function that will handle log messages.
+ *
+ * Available since API level 30.
  */
 void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to logd.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on a device.
+ *
+ * @param log_message the log message to write, see {@link __android_log_message}.
+ *
+ * Available since API level 30.
  */
-void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg)
-    __INTRODUCED_IN(30);
+void __android_log_logd_logger(const struct __android_log_message* log_message) __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to stderr.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on host.
+ *
+ * @param log_message the log message to write, see {@link __android_log_message}.
+ *
+ * Available since API level 30.
  */
-void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
-                                 const char* message) __INTRODUCED_IN(30);
+void __android_log_stderr_logger(const struct __android_log_message* log_message)
+    __INTRODUCED_IN(30);
 
 /**
- * Sets a user defined aborter function that is called for __android_log_assert() failures.
+ * Sets a user defined aborter function that is called for __android_log_assert() failures.  This
+ * user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
+ * required to.
+ *
+ * @param aborter the new aborter function, see {@link __android_aborter_function}.
+ *
+ * Available since API level 30.
  */
 void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
 
 /**
  * Calls the stored aborter function.  This allows for other logging libraries to use the same
  * aborter function by calling this function in liblog.
+ *
+ * @param abort_message an additional message supplied when aborting, for example this is used to
+ *                      call android_set_abort_message() in __android_log_default_aborter().
+ *
+ * Available since API level 30.
  */
 void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
 
 /**
  * Sets android_set_abort_message() on device then aborts().  This is the default aborter.
+ *
+ * @param abort_message an additional message supplied when aborting.  This functions calls
+ *                      android_set_abort_message() with its contents.
+ *
+ * Available since API level 30.
  */
-void __android_log_default_aborter(const char* abort_message) __INTRODUCED_IN(30);
+void __android_log_default_aborter(const char* abort_message) __attribute__((noreturn))
+__INTRODUCED_IN(30);
 
 /**
  * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
@@ -265,7 +297,13 @@
  * minimum priority needed to log.  If only one is set, then that value is used to determine the
  * minimum priority needed.  If none are set, then default_priority is used.
  *
- * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
+ * @param prio         the priority to test, takes {@link android_LogPriority} values.
+ * @param tag          the tag to test.
+ * @param len          the length of the tag.
+ * @param default_prio the default priority to use if no properties or minimum priority are set.
+ * @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
+ *
+ * Available since API level 30.
  */
 int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
@@ -274,20 +312,33 @@
 /**
  * Sets the minimum priority that will be logged for this process.
  *
- * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
+ * @param priority the new minimum priority to set, takes @{link android_LogPriority} values.
+ * @return the previous set minimum priority as @{link android_LogPriority} values, or
+ *         ANDROID_LOG_DEFAULT if none was set.
+ *
+ * Available since API level 30.
  */
-int __android_log_set_minimum_priority(int priority) __INTRODUCED_IN(30);
+int32_t __android_log_set_minimum_priority(int32_t priority) __INTRODUCED_IN(30);
 
 /**
  * Gets the minimum priority that will be logged for this process.  If none has been set by a
  * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
+ *
+ * @return the current minimum priority as @{link android_LogPriority} values, or
+ *         ANDROID_LOG_DEFAULT if none is set.
+ *
+ * Available since API level 30.
  */
-int __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
+int32_t __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
 
 /**
  * Sets the default tag if no tag is provided when writing a log message.  Defaults to
  * getprogname().  This truncates tag to the maximum log message size, though appropriate tags
  * should be much smaller.
+ *
+ * @param tag the new log tag.
+ *
+ * Available since API level 30.
  */
 void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
 #endif
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 9dcbbc9..6ca1a16 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -77,7 +77,7 @@
     __android_log_set_logger;
     __android_log_set_minimum_priority;
     __android_log_stderr_logger;
-    __android_log_write_logger_data;
+    __android_log_write_log_message;
 };
 
 LIBLOG_PRIVATE {
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index 7d676f4..e72290e 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -41,7 +41,10 @@
 }
 
 static_assert(std::is_same<std::underlying_type<log_id_t>::type, uint32_t>::value,
-              "log_id_t must be an unsigned int");
+              "log_id_t must be an uint32_t");
+
+static_assert(std::is_same<std::underlying_type<android_LogPriority>::type, uint32_t>::value,
+              "log_id_t must be an uint32_t");
 
 log_id_t android_name_to_log_id(const char* logName) {
   const char* b;
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 454a13b..7c78ea1 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -149,12 +149,12 @@
   GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
 }
 
-static std::atomic_int minimum_log_priority = ANDROID_LOG_DEFAULT;
-int __android_log_set_minimum_priority(int priority) {
+static std::atomic_int32_t minimum_log_priority = ANDROID_LOG_DEFAULT;
+int32_t __android_log_set_minimum_priority(int32_t priority) {
   return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
 }
 
-int __android_log_get_minimum_priority() {
+int32_t __android_log_get_minimum_priority() {
   return minimum_log_priority;
 }
 
@@ -250,8 +250,7 @@
 #endif
 }
 
-void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
-                                 const char* message) {
+void __android_log_stderr_logger(const struct __android_log_message* log_message) {
   struct tm now;
   time_t t = time(nullptr);
 
@@ -267,34 +266,33 @@
   static const char log_characters[] = "XXVDIWEF";
   static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
                 "Mismatch in size of log_characters and values in android_LogPriority");
-  int priority =
-      logger_data->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : logger_data->priority;
+  int32_t priority =
+      log_message->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : log_message->priority;
   char priority_char = log_characters[priority];
   uint64_t tid = GetThreadId();
 
-  if (logger_data->file != nullptr) {
+  if (log_message->file != nullptr) {
     fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
-            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
-            tid, logger_data->file, logger_data->line, message);
+            log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, log_message->file, log_message->line, log_message->message);
   } else {
     fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
-            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
-            tid, message);
+            log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, log_message->message);
   }
 }
 
-void __android_log_logd_logger(const struct __android_logger_data* logger_data,
-                               const char* message) {
-  int buffer_id = logger_data->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : logger_data->buffer_id;
+void __android_log_logd_logger(const struct __android_log_message* log_message) {
+  int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
 
   struct iovec vec[3];
   vec[0].iov_base =
-      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&logger_data->priority));
+      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
   vec[0].iov_len = 1;
-  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(logger_data->tag));
-  vec[1].iov_len = strlen(logger_data->tag) + 1;
-  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(message));
-  vec[2].iov_len = strlen(message) + 1;
+  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
+  vec[1].iov_len = strlen(log_message->tag) + 1;
+  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
+  vec[2].iov_len = strlen(log_message->message) + 1;
 
   write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
 }
@@ -303,29 +301,29 @@
   return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
-void __android_log_write_logger_data(__android_logger_data* logger_data, const char* msg) {
+void __android_log_write_log_message(__android_log_message* log_message) {
   ErrnoRestorer errno_restorer;
 
-  if (logger_data->buffer_id != LOG_ID_DEFAULT && logger_data->buffer_id != LOG_ID_MAIN &&
-      logger_data->buffer_id != LOG_ID_SYSTEM && logger_data->buffer_id != LOG_ID_RADIO &&
-      logger_data->buffer_id != LOG_ID_CRASH) {
+  if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
+      log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
+      log_message->buffer_id != LOG_ID_CRASH) {
     return;
   }
 
   auto tag_lock = std::shared_lock{default_tag_lock, std::defer_lock};
-  if (logger_data->tag == nullptr) {
+  if (log_message->tag == nullptr) {
     tag_lock.lock();
-    logger_data->tag = GetDefaultTag().c_str();
+    log_message->tag = GetDefaultTag().c_str();
   }
 
 #if __BIONIC__
-  if (logger_data->priority == ANDROID_LOG_FATAL) {
-    android_set_abort_message(msg);
+  if (log_message->priority == ANDROID_LOG_FATAL) {
+    android_set_abort_message(log_message->message);
   }
 #endif
 
   auto lock = std::shared_lock{logger_function_lock};
-  logger_function(logger_data, msg);
+  logger_function(log_message);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
@@ -335,8 +333,9 @@
     return 0;
   }
 
-  __android_logger_data logger_data = {sizeof(__android_logger_data), bufID, prio, tag, nullptr, 0};
-  __android_log_write_logger_data(&logger_data, msg);
+  __android_log_message log_message = {
+      sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, msg};
+  __android_log_write_log_message(&log_message);
   return 1;
 }
 
@@ -351,9 +350,9 @@
 
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
 
-  __android_logger_data logger_data = {
-      sizeof(__android_logger_data), LOG_ID_MAIN, prio, tag, nullptr, 0};
-  __android_log_write_logger_data(&logger_data, buf);
+  __android_log_message log_message = {
+      sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
+  __android_log_write_log_message(&log_message);
   return 1;
 }
 
@@ -371,9 +370,9 @@
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
   va_end(ap);
 
-  __android_logger_data logger_data = {
-      sizeof(__android_logger_data), LOG_ID_MAIN, prio, tag, nullptr, 0};
-  __android_log_write_logger_data(&logger_data, buf);
+  __android_log_message log_message = {
+      sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
+  __android_log_write_log_message(&log_message);
   return 1;
 }
 
@@ -391,8 +390,9 @@
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
   va_end(ap);
 
-  __android_logger_data logger_data = {sizeof(__android_logger_data), bufID, prio, tag, nullptr, 0};
-  __android_log_write_logger_data(&logger_data, buf);
+  __android_log_message log_message = {
+      sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, buf};
+  __android_log_write_log_message(&log_message);
   return 1;
 }
 
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
index 9a181ef..3508818 100644
--- a/liblog/tests/liblog_global_state.cpp
+++ b/liblog/tests/liblog_global_state.cpp
@@ -59,16 +59,15 @@
   static unsigned int expected_line;
   static std::string expected_message = "libbase test message";
 
-  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
-                                   const char* message) {
+  auto liblog_logger_function = [](const struct __android_log_message* log_message) {
     message_seen = true;
-    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
-    EXPECT_EQ(LOG_ID_DEFAULT, logger_data->buffer_id);
-    EXPECT_EQ(ANDROID_LOG_WARN, logger_data->priority);
-    EXPECT_STREQ(LOG_TAG, logger_data->tag);
-    EXPECT_EQ(expected_file, logger_data->file);
-    EXPECT_EQ(expected_line, logger_data->line);
-    EXPECT_EQ(expected_message, message);
+    EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
+    EXPECT_EQ(LOG_ID_DEFAULT, log_message->buffer_id);
+    EXPECT_EQ(ANDROID_LOG_WARN, log_message->priority);
+    EXPECT_STREQ(LOG_TAG, log_message->tag);
+    EXPECT_EQ(expected_file, log_message->file);
+    EXPECT_EQ(expected_line, log_message->line);
+    EXPECT_EQ(expected_message, log_message->message);
   };
 
   __android_log_set_logger(liblog_logger_function);
@@ -111,16 +110,15 @@
   static int expected_priority = ANDROID_LOG_WARN;
   static std::string expected_message = "libbase test message";
 
-  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
-                                   const char* message) {
+  auto liblog_logger_function = [](const struct __android_log_message* log_message) {
     message_seen = true;
-    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
-    EXPECT_EQ(expected_buffer_id, logger_data->buffer_id);
-    EXPECT_EQ(expected_priority, logger_data->priority);
-    EXPECT_STREQ(LOG_TAG, logger_data->tag);
-    EXPECT_STREQ(nullptr, logger_data->file);
-    EXPECT_EQ(0U, logger_data->line);
-    EXPECT_EQ(expected_message, message);
+    EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
+    EXPECT_EQ(expected_buffer_id, log_message->buffer_id);
+    EXPECT_EQ(expected_priority, log_message->priority);
+    EXPECT_STREQ(LOG_TAG, log_message->tag);
+    EXPECT_STREQ(nullptr, log_message->file);
+    EXPECT_EQ(0U, log_message->line);
+    EXPECT_EQ(expected_message, log_message->message);
   };
 
   __android_log_set_logger(liblog_logger_function);
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 3f08535..0cee6bb 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -49,6 +49,11 @@
       "Name": "UClampMax",
       "Controller": "cpu",
       "File": "cpu.uclamp.max"
+    },
+    {
+      "Name": "FreezerState",
+      "Controller": "freezer",
+      "File": "frozen/freezer.state"
     }
   ],
 
@@ -518,6 +523,32 @@
           }
         }
       ]
+    },
+    {
+      "Name": "FreezerThawed",
+      "Actions": [
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "FreezerState",
+            "Value": "THAWED"
+          }
+        }
+      ]
+    },
+    {
+      "Name": "FreezerFrozen",
+      "Actions": [
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "FreezerState",
+            "Value": "FROZEN"
+          }
+        }
+      ]
     }
   ],
 
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
index ad9b04e..0b0df2b 100644
--- a/libstats/pull/include/stats_pull_atom_callback.h
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -112,6 +112,8 @@
  * invoke the callback when the stats service determines that this atom needs to be
  * pulled.
  *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
  * \param atom_tag          The tag of the atom for this pull atom callback.
  * \param metadata          Optional metadata specifying the timeout, cool down time, and
  *                          additive fields for mapping isolated to host uids.
@@ -128,6 +130,8 @@
  * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
  * pulls will still occur.
  *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
  * \param atomTag           The tag of the atom of which to unregister
  */
 void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag);
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index 4de95dc..f0fcff6 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -35,6 +35,8 @@
     header_libs: ["libstatssocket_headers"],
     static_libs: [
         "libbase",
+    ],
+    shared_libs: [
         "liblog",
     ],
 }
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index ff84283..3576298 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -29,8 +29,9 @@
  *      AStatsEvent* event = AStatsEvent_obtain();
  *
  *      AStatsEvent_setAtomId(event, atomId);
+ *      AStatsEvent_addBoolAnnotation(event, 5, false); // atom-level annotation
  *      AStatsEvent_writeInt32(event, 24);
- *      AStatsEvent_addBoolAnnotation(event, 1, true); // annotations apply to the previous field
+ *      AStatsEvent_addBoolAnnotation(event, 1, true); // annotation for preceding atom field
  *      AStatsEvent_addInt32Annotation(event, 2, 128);
  *      AStatsEvent_writeFloat(event, 2.0);
  *
@@ -38,13 +39,8 @@
  *      AStatsEvent_write(event);
  *      AStatsEvent_release(event);
  *
- * Notes:
- *    (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
- *        and annotations are defined in the atom.
- *    (b) set_atom_id() can be called anytime before stats_event_write().
- *    (c) add_<type>_annotation() calls apply to the previous field.
- *    (d) If errors occur, stats_event_write() will write a bitmask of the errors to the socket.
- *    (e) All strings should be encoded using UTF8.
+ * Note that calls to add atom fields and annotations should be made in the
+ * order that they are defined in the atom.
  */
 
 #ifdef __cplusplus
@@ -84,7 +80,7 @@
 int AStatsEvent_write(AStatsEvent* event);
 
 /**
- * Frees the memory held by this StatsEvent
+ * Frees the memory held by this StatsEvent.
  *
  * After calling this, the StatsEvent must not be used or modified in any way.
  */
@@ -92,6 +88,8 @@
 
 /**
  * Sets the atom id for this StatsEvent.
+ *
+ * This function should be called immediately after AStatsEvent_obtain.
  **/
 void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
 
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index b045d93..24d2ea8 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -29,7 +29,6 @@
 #define POS_NUM_ELEMENTS 1
 #define POS_TIMESTAMP (POS_NUM_ELEMENTS + sizeof(uint8_t))
 #define POS_ATOM_ID (POS_TIMESTAMP + sizeof(uint8_t) + sizeof(uint64_t))
-#define POS_FIRST_FIELD (POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t))
 
 /* LIMITS */
 #define MAX_ANNOTATION_COUNT 15
@@ -66,8 +65,11 @@
 // within a buf. Also includes other required fields.
 struct AStatsEvent {
     uint8_t* buf;
-    size_t lastFieldPos;  // location of last field within the buf
-    size_t size;          // number of valid bytes within buffer
+    // Location of last field within the buf. Here, field denotes either a
+    // metadata field (e.g. timestamp) or an atom field.
+    size_t lastFieldPos;
+    // Number of valid bytes within the buffer.
+    size_t size;
     uint32_t numElements;
     uint32_t atomId;
     uint32_t errors;
@@ -85,20 +87,21 @@
 AStatsEvent* AStatsEvent_obtain() {
     AStatsEvent* event = malloc(sizeof(AStatsEvent));
     event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
-    event->buf[0] = OBJECT_TYPE;
+    event->lastFieldPos = 0;
+    event->size = 2;  // reserve first two bytes for outer event type and number of elements
+    event->numElements = 0;
     event->atomId = 0;
     event->errors = 0;
     event->truncate = true;  // truncate for both pulled and pushed atoms
     event->built = false;
 
-    // place the timestamp
-    uint64_t timestampNs = get_elapsed_realtime_ns();
-    event->buf[POS_TIMESTAMP] = INT64_TYPE;
-    memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], &timestampNs, sizeof(timestampNs));
+    event->buf[0] = OBJECT_TYPE;
+    AStatsEvent_writeInt64(event, get_elapsed_realtime_ns());  // write the timestamp
 
-    event->numElements = 1;
-    event->lastFieldPos = 0;  // 0 since we haven't written a field yet
-    event->size = POS_FIRST_FIELD;
+    // Force client to set atom id immediately (this is required for atom-level
+    // annotations to be written correctly). All atom field and annotation
+    // writes will fail until the atom id is set because event->errors != 0.
+    event->errors |= ERROR_NO_ATOM_ID;
 
     return event;
 }
@@ -109,10 +112,12 @@
 }
 
 void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
+    if ((event->errors & ERROR_NO_ATOM_ID) == 0) return;
+
+    // Clear the ERROR_NO_ATOM_ID bit.
+    event->errors &= ~ERROR_NO_ATOM_ID;
     event->atomId = atomId;
-    event->buf[POS_ATOM_ID] = INT32_TYPE;
-    memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
-    event->numElements++;
+    AStatsEvent_writeInt32(event, atomId);
 }
 
 // Overwrites the timestamp populated in AStatsEvent_obtain with a custom
@@ -306,23 +311,23 @@
 void AStatsEvent_build(AStatsEvent* event) {
     if (event->built) return;
 
-    if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
-
-    if (event->numElements > MAX_BYTE_VALUE) {
-        event->errors |= ERROR_TOO_MANY_FIELDS;
-    } else {
-        event->buf[POS_NUM_ELEMENTS] = event->numElements;
-    }
+    if (event->numElements > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_FIELDS;
 
     // If there are errors, rewrite buffer.
     if (event->errors) {
-        event->buf[POS_NUM_ELEMENTS] = 3;
-        event->buf[POS_FIRST_FIELD] = ERROR_TYPE;
-        memcpy(&event->buf[POS_FIRST_FIELD + sizeof(uint8_t)], &event->errors,
-               sizeof(event->errors));
-        event->size = POS_FIRST_FIELD + sizeof(uint8_t) + sizeof(uint32_t);
+        // Discard everything after the atom id (including atom-level
+        // annotations). This leaves only two elements (timestamp and atom id).
+        event->numElements = 2;
+        // Reset number of atom-level annotations to 0.
+        event->buf[POS_ATOM_ID] = INT32_TYPE;
+        // Now, write errors to the buffer immediately after the atom id.
+        event->size = POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t);
+        start_field(event, ERROR_TYPE);
+        append_int32(event, event->errors);
     }
 
+    event->buf[POS_NUM_ELEMENTS] = event->numElements;
+
     // Truncate the buffer to the appropriate length in order to limit our
     // memory usage.
     if (event->truncate) event->buf = (uint8_t*)realloc(event->buf, event->size);
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index 69d0a9b..04eff36 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -89,7 +89,7 @@
 }
 
 void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
-                   uint32_t atomId) {
+                   uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
     // All events start with OBJECT_TYPE id.
     checkTypeHeader(buffer, OBJECT_TYPE);
 
@@ -104,7 +104,7 @@
     EXPECT_LE(timestamp, endTime);
 
     // Check atom id
-    checkTypeHeader(buffer, INT32_TYPE);
+    checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
     checkScalar(buffer, atomId);
 }
 
@@ -240,7 +240,7 @@
     AStatsEvent_release(event);
 }
 
-TEST(StatsEventTest, TestAnnotations) {
+TEST(StatsEventTest, TestFieldAnnotations) {
     uint32_t atomId = 100;
 
     // first element information
@@ -259,7 +259,7 @@
 
     int64_t startTime = android::elapsedRealtimeNano();
     AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
+    AStatsEvent_setAtomId(event, atomId);
     AStatsEvent_writeBool(event, boolValue);
     AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
     AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
@@ -292,6 +292,45 @@
     AStatsEvent_release(event);
 }
 
+TEST(StatsEventTest, TestAtomLevelAnnotations) {
+    uint32_t atomId = 100;
+    // atom-level annotation information
+    uint8_t boolAnnotationId = 1;
+    uint8_t int32AnnotationId = 2;
+    bool boolAnnotationValue = false;
+    int32_t int32AnnotationValue = 5;
+
+    float fieldValue = -3.5;
+
+    int64_t startTime = android::elapsedRealtimeNano();
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
+    AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
+    AStatsEvent_writeFloat(event, fieldValue);
+    AStatsEvent_build(event);
+    int64_t endTime = android::elapsedRealtimeNano();
+
+    size_t bufferSize;
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
+    uint8_t* bufferEnd = buffer + bufferSize;
+
+    checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
+                  /*numAtomLevelAnnotations=*/2);
+
+    // check atom-level annotations
+    checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
+    checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
+
+    // check first element
+    checkTypeHeader(&buffer, FLOAT_TYPE);
+    checkScalar(&buffer, fieldValue);
+
+    EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
+}
+
 TEST(StatsEventTest, TestNoAtomIdError) {
     AStatsEvent* event = AStatsEvent_obtain();
     // Don't set the atom id in order to trigger the error.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c59f911..324fa19 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -16,6 +16,11 @@
     # Disable sysrq from keyboard
     write /proc/sys/kernel/sysrq 0
 
+    # Android doesn't need kernel module autoloading, and it causes SELinux
+    # denials.  So disable it by setting modprobe to the empty string.  Note: to
+    # explicitly set a sysctl to an empty string, a trailing newline is needed.
+    write /proc/sys/kernel/modprobe \n
+
     # Set the security context of /adb_keys if present.
     restorecon /adb_keys
 
@@ -319,7 +324,7 @@
     chown system system /dev/freezer/frozen/freezer.state
     chown system system /dev/freezer/frozen/cgroup.procs
 
-    chmod 0444 /dev/freezer/frozen/freezer.state
+    chmod 0664 /dev/freezer/frozen/freezer.state
 
     # make the PSI monitor accessible to others
     chown system system /proc/pressure/memory
diff --git a/storaged/main.cpp b/storaged/main.cpp
index a7bda14..bbed210 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -71,6 +71,7 @@
     bool flag_dump_perf = false;
     int opt;
 
+    signal(SIGPIPE, SIG_IGN);
     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
 
     for (;;) {