Merge "libsnapshot: Add helper for first-stage init mounting"
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 2b11da2..f0142bb 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -55,13 +55,14 @@
     export_include_dirs: ["include"],
 }
 
-cc_test {
-    name: "liblp_test_static",
+cc_defaults {
+    name: "liblp_test_defaults",
     defaults: ["fs_mgr_defaults"],
     cppflags: [
         "-Wno-unused-parameter",
     ],
     static_libs: [
+        "libcutils",
         "libgmock",
         "libfs_mgr",
         "liblp",
@@ -74,11 +75,20 @@
         "test_partition_opener.cpp",
         "utility_test.cpp",
     ],
-    target: {
-        android: {
-            static_libs: [
-                "libcutils",
-            ],
-        },
-    },
 }
+
+cc_test {
+    name: "liblp_test",
+    defaults: ["liblp_test_defaults"],
+    test_config: "liblp_test.xml",
+    test_suites: [
+        "device-tests",
+        "vts-core",
+    ],
+}
+
+cc_test {
+    name: "vts_kernel_liblp_test",
+    defaults: ["liblp_test_defaults"],
+}
+
diff --git a/fs_mgr/liblp/AndroidTest.xml b/fs_mgr/liblp/AndroidTest.xml
index fe1002c..2eb0ad1 100644
--- a/fs_mgr/liblp/AndroidTest.xml
+++ b/fs_mgr/liblp/AndroidTest.xml
@@ -21,8 +21,8 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
       <option name="test-module-name" value="VtsKernelLiblpTest"/>
-        <option name="binary-test-source" value="_32bit::DATA/nativetest/liblp_test_static/liblp_test_static" />
-        <option name="binary-test-source" value="_64bit::DATA/nativetest64/liblp_test_static/liblp_test_static" />
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_kernel_liblp_test/vts_kernel_liblp_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_kernel_liblp_test/vts_kernel_liblp_test" />
         <option name="binary-test-type" value="gtest"/>
         <option name="test-timeout" value="1m"/>
         <option name="precondition-first-api-level" value="29" />
diff --git a/fs_mgr/liblp/TEST_MAPPING b/fs_mgr/liblp/TEST_MAPPING
new file mode 100644
index 0000000..04bcbda
--- /dev/null
+++ b/fs_mgr/liblp/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "liblp_test"
+    }
+  ]
+}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index ecad7d4..dde6d07 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -19,29 +19,20 @@
 #include <liblp/builder.h>
 
 #include "liblp_test.h"
-#include "mock_property_fetcher.h"
 #include "utility.h"
 
 using namespace std;
 using namespace android::fs_mgr;
-using ::android::fs_mgr::MockPropertyFetcher;
+using namespace android::fs_mgr::testing;
 using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::ElementsAre;
 using ::testing::NiceMock;
 using ::testing::Return;
 
-void ResetPropertyFetcher() {
-    IPropertyFetcher::OverrideForTesting(std::make_unique<NiceMock<MockPropertyFetcher>>());
-}
-
-MockPropertyFetcher* GetMockedPropertyFetcher() {
-    return static_cast<MockPropertyFetcher*>(IPropertyFetcher::GetInstance());
-}
-
 class Environment : public ::testing::Environment {
   public:
-    void SetUp() override { ResetPropertyFetcher(); }
+    void SetUp() override { ResetMockPropertyFetcher(); }
 };
 
 int main(int argc, char** argv) {
diff --git a/fs_mgr/liblp/device_test.cpp b/fs_mgr/liblp/device_test.cpp
index b759fd1..382d53d 100644
--- a/fs_mgr/liblp/device_test.cpp
+++ b/fs_mgr/liblp/device_test.cpp
@@ -24,9 +24,9 @@
 #include <liblp/property_fetcher.h>
 
 #include "liblp_test.h"
-#include "mock_property_fetcher.h"
 
 using namespace android::fs_mgr;
+using namespace android::fs_mgr::testing;
 using ::testing::Return;
 
 // Compliance test on the actual device with dynamic partitions.
diff --git a/fs_mgr/liblp/mock_property_fetcher.h b/fs_mgr/liblp/include/liblp/mock_property_fetcher.h
similarity index 79%
rename from fs_mgr/liblp/mock_property_fetcher.h
rename to fs_mgr/liblp/include/liblp/mock_property_fetcher.h
index 4612c52..f15611b 100644
--- a/fs_mgr/liblp/mock_property_fetcher.h
+++ b/fs_mgr/liblp/include/liblp/mock_property_fetcher.h
@@ -22,6 +22,7 @@
 
 namespace android {
 namespace fs_mgr {
+namespace testing {
 
 class MockPropertyFetcher : public IPropertyFetcher {
   public:
@@ -41,8 +42,15 @@
     }
 };
 
+static inline void ResetMockPropertyFetcher() {
+    IPropertyFetcher::OverrideForTesting(
+            std::make_unique<::testing::NiceMock<MockPropertyFetcher>>());
+}
+
+static inline MockPropertyFetcher* GetMockedPropertyFetcher() {
+    return static_cast<MockPropertyFetcher*>(IPropertyFetcher::GetInstance());
+}
+
+}  // namespace testing
 }  // namespace fs_mgr
 }  // namespace android
-
-android::fs_mgr::MockPropertyFetcher* GetMockedPropertyFetcher();
-void ResetPropertyFetcher();
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 4d00944..df89e9c 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -27,7 +27,6 @@
 
 #include "images.h"
 #include "liblp_test.h"
-#include "mock_property_fetcher.h"
 #include "reader.h"
 #include "test_partition_opener.h"
 #include "utility.h"
@@ -35,6 +34,7 @@
 
 using namespace std;
 using namespace android::fs_mgr;
+using namespace android::fs_mgr::testing;
 using ::testing::_;
 using ::testing::Return;
 using unique_fd = android::base::unique_fd;
diff --git a/fs_mgr/liblp/liblp_test.h b/fs_mgr/liblp/liblp_test.h
index 892f43d..c61aaa5 100644
--- a/fs_mgr/liblp/liblp_test.h
+++ b/fs_mgr/liblp/liblp_test.h
@@ -18,10 +18,18 @@
 
 #include <gtest/gtest.h>
 
-#include "mock_property_fetcher.h"
+#include <liblp/mock_property_fetcher.h>
+
+namespace android {
+namespace fs_mgr {
+namespace testing {
 
 class LiblpTest : public ::testing::Test {
   public:
-    void SetUp() override { ResetPropertyFetcher(); }
-    void TearDown() override { ResetPropertyFetcher(); }
+    void SetUp() override { ResetMockPropertyFetcher(); }
+    void TearDown() override { ResetMockPropertyFetcher(); }
 };
+
+}  // namespace testing
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/liblp/liblp_test.xml b/fs_mgr/liblp/liblp_test.xml
new file mode 100644
index 0000000..d9ee12e
--- /dev/null
+++ b/fs_mgr/liblp/liblp_test.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for liblp_test">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="liblp_test->/data/local/tmp/liblp_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="vts-core" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="liblp_test" />
+    </test>
+</configuration>
diff --git a/healthd/api/charger_sysprop-current.txt b/healthd/api/charger_sysprop-current.txt
new file mode 100644
index 0000000..678c847
--- /dev/null
+++ b/healthd/api/charger_sysprop-current.txt
@@ -0,0 +1,29 @@
+props {
+  module: "android.sysprop.ChargerProperties"
+  prop {
+    api_name: "disable_init_blank"
+    scope: Internal
+    prop_name: "ro.charger.disable_init_blank"
+  }
+  prop {
+    api_name: "draw_split_offset"
+    type: Long
+    scope: Internal
+    prop_name: "ro.charger.draw_split_offset"
+  }
+  prop {
+    api_name: "draw_split_screen"
+    scope: Internal
+    prop_name: "ro.charger.draw_split_screen"
+  }
+  prop {
+    api_name: "enable_suspend"
+    scope: Internal
+    prop_name: "ro.charger.enable_suspend"
+  }
+  prop {
+    api_name: "no_ui"
+    scope: Internal
+    prop_name: "ro.charger.no_ui"
+  }
+}
diff --git a/healthd/api/charger_sysprop-latest.txt b/healthd/api/charger_sysprop-latest.txt
new file mode 100644
index 0000000..678c847
--- /dev/null
+++ b/healthd/api/charger_sysprop-latest.txt
@@ -0,0 +1,29 @@
+props {
+  module: "android.sysprop.ChargerProperties"
+  prop {
+    api_name: "disable_init_blank"
+    scope: Internal
+    prop_name: "ro.charger.disable_init_blank"
+  }
+  prop {
+    api_name: "draw_split_offset"
+    type: Long
+    scope: Internal
+    prop_name: "ro.charger.draw_split_offset"
+  }
+  prop {
+    api_name: "draw_split_screen"
+    scope: Internal
+    prop_name: "ro.charger.draw_split_screen"
+  }
+  prop {
+    api_name: "enable_suspend"
+    scope: Internal
+    prop_name: "ro.charger.enable_suspend"
+  }
+  prop {
+    api_name: "no_ui"
+    scope: Internal
+    prop_name: "ro.charger.no_ui"
+  }
+}
diff --git a/healthd/api/current.txt b/healthd/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/removed.txt b/healthd/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/system-current.txt b/healthd/api/system-current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/system-removed.txt b/healthd/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/test-current.txt b/healthd/api/test-current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/test-removed.txt b/healthd/api/test-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/init/Android.bp b/init/Android.bp
index 7dfb828..6f02555 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -117,6 +117,7 @@
         "firmware_handler.cpp",
         "first_stage_init.cpp",
         "first_stage_mount.cpp",
+        "fscrypt_init_extensions.cpp",
         "import_parser.cpp",
         "init.cpp",
         "interface_utils.cpp",
@@ -128,7 +129,6 @@
         "persistent_properties.cpp",
         "persistent_properties.proto",
         "property_service.cpp",
-        "property_service.proto",
         "property_type.cpp",
         "reboot.cpp",
         "reboot_utils.cpp",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 7076926..ed24026 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -55,7 +55,6 @@
 #include <cutils/android_reboot.h>
 #include <fs_mgr.h>
 #include <fscrypt/fscrypt.h>
-#include <fscrypt/fscrypt_init_extensions.h>
 #include <libgsi/libgsi.h>
 #include <selinux/android.h>
 #include <selinux/label.h>
@@ -64,6 +63,7 @@
 
 #include "action_manager.h"
 #include "bootchart.h"
+#include "fscrypt_init_extensions.h"
 #include "init.h"
 #include "mount_namespace.h"
 #include "parser.h"
@@ -80,7 +80,6 @@
 using namespace std::literals::string_literals;
 
 using android::base::Basename;
-using android::base::StartsWith;
 using android::base::unique_fd;
 using android::fs_mgr::Fstab;
 using android::fs_mgr::ReadFstabFromFile;
@@ -688,15 +687,6 @@
 }
 
 static Result<void> do_setprop(const BuiltinArguments& args) {
-    if (StartsWith(args[1], "ctl.")) {
-        return Error()
-               << "Cannot set ctl. properties from init; call the Service functions directly";
-    }
-    if (args[1] == kRestoreconProperty) {
-        return Error() << "Cannot set '" << kRestoreconProperty
-                       << "' from init; use the restorecon builtin directly";
-    }
-
     property_set(args[1], args[2]);
     return {};
 }
@@ -1012,20 +1002,7 @@
 }
 
 static Result<void> do_load_persist_props(const BuiltinArguments& args) {
-    // Devices with FDE have load_persist_props called twice; the first time when the temporary
-    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
-    // read persistent properties from the temporary /data partition or mark persistent properties
-    // as having been loaded during the first call, so we return in that case.
-    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
-    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
-    if (crypto_state == "encrypted" && crypto_type == "block") {
-        static size_t num_calls = 0;
-        if (++num_calls == 1) return {};
-    }
-
-    SendLoadPersistentPropertiesMessage();
-
-    start_waiting_for_property("ro.persistent_properties.ready", "true");
+    load_persist_props();
     return {};
 }
 
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
new file mode 100644
index 0000000..956228a
--- /dev/null
+++ b/init/fscrypt_init_extensions.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fscrypt_init_extensions.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fts.h>
+#include <fscrypt/fscrypt.h>
+#include <keyutils.h>
+#include <logwrap/logwrap.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+
+#define TAG "fscrypt"
+
+static int set_system_de_policy_on(char const* dir);
+
+int fscrypt_install_keyring()
+{
+    key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0,
+                                          KEY_SPEC_SESSION_KEYRING);
+
+    if (device_keyring == -1) {
+        PLOG(ERROR) << "Failed to create keyring";
+        return -1;
+    }
+
+    LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
+
+    return 0;
+}
+
+// TODO(b/139378601): use a single central implementation of this.
+static void delete_dir_contents(const char* dir) {
+    char* const paths[2] = {const_cast<char*>(dir), nullptr};
+    FTS* fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr);
+    FTSENT* cur;
+    while ((cur = fts_read(fts)) != nullptr) {
+        if (cur->fts_info == FTS_ERR) {
+            PLOG(ERROR) << "fts_read";
+            break;
+        }
+        if (strcmp(dir, cur->fts_path) == 0) {
+            continue;
+        }
+        switch (cur->fts_info) {
+            case FTS_D:
+                break;  // Ignore these
+            case FTS_DP:
+                if (rmdir(cur->fts_path) == -1) {
+                    PLOG(ERROR) << "rmdir " << cur->fts_path;
+                }
+                break;
+            default:
+                PLOG(ERROR) << "FTS unexpected type " << cur->fts_info << " at " << cur->fts_path;
+                if (rmdir(cur->fts_path) != -1) break;
+                // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
+                FALLTHROUGH_INTENDED;
+            case FTS_F:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (unlink(cur->fts_path) == -1) {
+                    PLOG(ERROR) << "unlink " << cur->fts_path;
+                }
+                break;
+        }
+    }
+
+    if (fts_close(fts) != 0) {
+        PLOG(ERROR) << "fts_close";
+    }
+}
+
+int fscrypt_set_directory_policy(const char* dir)
+{
+    const std::string prefix = "/data/";
+
+    if (!dir || strncmp(dir, prefix.c_str(), prefix.size())) {
+        return 0;
+    }
+
+    // Special-case /data/media/obb per b/64566063
+    if (strcmp(dir, "/data/media/obb") == 0) {
+        // Try to set policy on this directory, but if it is non-empty this may fail.
+        set_system_de_policy_on(dir);
+        return 0;
+    }
+
+    // Only set policy on first level /data directories
+    // To make this less restrictive, consider using a policy file.
+    // However this is overkill for as long as the policy is simply
+    // to apply a global policy to all /data folders created via makedir
+    if (strchr(dir + prefix.size(), '/')) {
+        return 0;
+    }
+
+    // Special case various directories that must not be encrypted,
+    // often because their subdirectories must be encrypted.
+    // This isn't a nice way to do this, see b/26641735
+    std::vector<std::string> directories_to_exclude = {
+        "lost+found",
+        "system_ce", "system_de",
+        "misc_ce", "misc_de",
+        "vendor_ce", "vendor_de",
+        "media",
+        "data", "user", "user_de",
+        "apex", "preloads", "app-staging",
+        "gsi",
+    };
+    for (const auto& d: directories_to_exclude) {
+        if ((prefix + d) == dir) {
+            LOG(INFO) << "Not setting policy on " << dir;
+            return 0;
+        }
+    }
+    int err = set_system_de_policy_on(dir);
+    if (err == 0) {
+        return 0;
+    }
+    // Empty these directories if policy setting fails.
+    std::vector<std::string> wipe_on_failure = {
+        "rollback", "rollback-observer",  // b/139193659
+    };
+    for (const auto& d : wipe_on_failure) {
+        if ((prefix + d) == dir) {
+            LOG(ERROR) << "Setting policy failed, deleting: " << dir;
+            delete_dir_contents(dir);
+            err = set_system_de_policy_on(dir);
+            break;
+        }
+    }
+    return err;
+}
+
+static int set_system_de_policy_on(char const* dir) {
+    std::string ref_filename = std::string("/data") + fscrypt_key_ref;
+    std::string policy;
+    if (!android::base::ReadFileToString(ref_filename, &policy)) {
+        LOG(ERROR) << "Unable to read system policy to set on " << dir;
+        return -1;
+    }
+
+    auto type_filename = std::string("/data") + fscrypt_key_mode;
+    std::string modestring;
+    if (!android::base::ReadFileToString(type_filename, &modestring)) {
+        LOG(ERROR) << "Cannot read mode";
+    }
+
+    std::vector<std::string> modes = android::base::Split(modestring, ":");
+
+    if (modes.size() < 1 || modes.size() > 2) {
+        LOG(ERROR) << "Invalid encryption mode string: " << modestring;
+        return -1;
+    }
+
+    LOG(INFO) << "Setting policy on " << dir;
+    int result = fscrypt_policy_ensure(dir, policy.c_str(), policy.length(),
+                                       modes[0].c_str(),
+                                       modes.size() >= 2 ?
+                                            modes[1].c_str() : "aes-256-cts");
+    if (result) {
+        LOG(ERROR) << android::base::StringPrintf(
+            "Setting %02x%02x%02x%02x policy on %s failed!",
+            policy[0], policy[1], policy[2], policy[3], dir);
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/init/fscrypt_init_extensions.h b/init/fscrypt_init_extensions.h
new file mode 100644
index 0000000..2b6c46e
--- /dev/null
+++ b/init/fscrypt_init_extensions.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _FSCRYPT_INIT_EXTENSIONS_H_
+#define _FSCRYPT_INIT_EXTENSIONS_H_
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <cutils/multiuser.h>
+
+__BEGIN_DECLS
+
+// These functions assume they are being called from init
+// They will not operate properly outside of init
+int fscrypt_install_keyring();
+int fscrypt_set_directory_policy(const char* path);
+
+__END_DECLS
+
+#endif // _FSCRYPT_INIT_EXTENSIONS_H_
diff --git a/init/init.cpp b/init/init.cpp
index e8eb571..18fb0c3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -61,7 +61,6 @@
 #include "mount_handler.h"
 #include "mount_namespace.h"
 #include "property_service.h"
-#include "proto_utils.h"
 #include "reboot.h"
 #include "reboot_utils.h"
 #include "security.h"
@@ -70,7 +69,6 @@
 #include "service.h"
 #include "service_parser.h"
 #include "sigchld_handler.h"
-#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::chrono_literals;
@@ -92,7 +90,6 @@
 static char qemu[32];
 
 static int signal_fd = -1;
-static int property_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
@@ -616,54 +613,6 @@
                                 selinux_start_time_ns));
 }
 
-void SendLoadPersistentPropertiesMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_load_persistent_properties(true);
-    if (auto result = SendMessage(property_fd, init_message); !result) {
-        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
-    }
-}
-
-static void HandlePropertyFd() {
-    auto message = ReadMessage(property_fd);
-    if (!message) {
-        LOG(ERROR) << "Could not read message from property service: " << message.error();
-        return;
-    }
-
-    auto property_message = PropertyMessage{};
-    if (!property_message.ParseFromString(*message)) {
-        LOG(ERROR) << "Could not parse message from property service";
-        return;
-    }
-
-    switch (property_message.msg_case()) {
-        case PropertyMessage::kControlMessage: {
-            auto& control_message = property_message.control_message();
-            bool response = HandleControlMessage(control_message.msg(), control_message.name(),
-                                                 control_message.pid());
-
-            auto init_message = InitMessage{};
-            auto* control_response = init_message.mutable_control_response();
-
-            control_response->set_result(response);
-
-            if (auto result = SendMessage(property_fd, init_message); !result) {
-                LOG(ERROR) << "Failed to send control response: " << result.error();
-            }
-            break;
-        }
-        case PropertyMessage::kChangedMessage: {
-            auto& changed_message = property_message.changed_message();
-            property_changed(changed_message.name(), changed_message.value());
-            break;
-        }
-        default:
-            LOG(ERROR) << "Unknown message type from property service: "
-                       << property_message.msg_case();
-    }
-}
-
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -735,12 +684,7 @@
     UmountDebugRamdisk();
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
-
-    StartPropertyService(&property_fd);
-    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
-        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
-    }
-
+    StartPropertyService(&epoll);
     MountHandler mount_handler(&epoll);
     set_usb_controller();
 
diff --git a/init/init.h b/init/init.h
index 832ce3f..cfc28f1 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,14 +31,16 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 Parser CreateServiceOnlyParser(ServiceList& service_list);
 
+bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
+
+void property_changed(const std::string& name, const std::string& value);
+
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
 
 void ResetWaitForProp();
 
-void SendLoadPersistentPropertiesMessage();
-
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b7d5743..3408ff3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,7 +42,6 @@
 #include <map>
 #include <memory>
 #include <mutex>
-#include <optional>
 #include <queue>
 #include <thread>
 #include <vector>
@@ -64,10 +63,8 @@
 #include "init.h"
 #include "persistent_properties.h"
 #include "property_type.h"
-#include "proto_utils.h"
 #include "selinux.h"
 #include "subcontext.h"
-#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::literals;
@@ -79,7 +76,6 @@
 using android::base::StringPrintf;
 using android::base::Timer;
 using android::base::Trim;
-using android::base::unique_fd;
 using android::base::WriteStringToFile;
 using android::properties::BuildTrie;
 using android::properties::ParsePropertyInfoFile;
@@ -89,15 +85,14 @@
 namespace android {
 namespace init {
 
+static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
+
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
-static int init_socket = -1;
 
 static PropertyInfoAreaFile property_info_area;
 
-uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr, std::string* error);
 uint32_t InitPropertySet(const std::string& name, const std::string& value);
 
 uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
@@ -169,17 +164,6 @@
     return has_access;
 }
 
-static void SendPropertyChanged(const std::string& name, const std::string& value) {
-    auto property_msg = PropertyMessage{};
-    auto* changed_message = property_msg.mutable_changed_message();
-    changed_message->set_name(name);
-    changed_message->set_value(value);
-
-    if (auto result = SendMessage(init_socket, property_msg); !result) {
-        LOG(ERROR) << "Failed to send property changed message: " << result.error();
-    }
-}
-
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -215,11 +199,7 @@
     if (persistent_properties_loaded && StartsWith(name, "persist.")) {
         WritePersistentProperty(name, value);
     }
-    // If init hasn't started its main loop, then it won't be handling property changed messages
-    // anyway, so there's no need to try to send them.
-    if (init_socket != -1) {
-        SendPropertyChanged(name, value);
-    }
+    property_changed(name, value);
     return PROP_SUCCESS;
 }
 
@@ -260,6 +240,17 @@
 };
 
 uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+    if (StartsWith(name, "ctl.")) {
+        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
+                      "functions directly";
+        return PROP_ERROR_INVALID_NAME;
+    }
+    if (name == kRestoreconProperty) {
+        LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty
+                   << "' from init; use the restorecon builtin directly";
+        return PROP_ERROR_INVALID_NAME;
+    }
+
     uint32_t result = 0;
     ucred cr = {.pid = 1, .uid = 0, .gid = 0};
     std::string error;
@@ -275,6 +266,8 @@
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
 
+    ~SocketConnection() { close(socket_); }
+
     bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
         return RecvFully(value, sizeof(*value), timeout_ms);
     }
@@ -396,62 +389,12 @@
         return bytes_left == 0;
     }
 
-    unique_fd socket_;
+    int socket_;
     ucred cred_;
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
 };
 
-// Init responds with whether or not the control message was successful.  However, init may set
-// properties in the process of handling the control message, particularly when starting services.
-// Therefore we cannot block in SendControlMessage() to wait for init's response.  Instead, we store
-// the SocketConnection for the socket that sent the control message.  We then return to the main
-// poll loop and handle messages until we get the response from init.
-//
-// Note that this is a queue, since it is possible for more control messages to come while init is
-// handling the first.  Both init and property service will handle these in order.
-//
-// Also note that the 1st version of the property service does not expect a result to be sent, so
-// we have a nullopt as a placeholder in the queue to keep track of which control messages have been
-// responded to.
-static std::queue<std::optional<SocketConnection>> pending_control_message_results;
-
-static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
-                                   std::string* error) {
-    auto property_msg = PropertyMessage{};
-    auto* control_message = property_msg.mutable_control_message();
-    control_message->set_msg(msg);
-    control_message->set_name(name);
-    control_message->set_pid(pid);
-
-    if (auto result = SendMessage(init_socket, property_msg); !result) {
-        *error = "Failed to send control message: " + result.error().message();
-        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-    }
-
-    return PROP_SUCCESS;
-}
-
-void HandleControlResponse(const InitMessage& init_message) {
-    if (pending_control_message_results.empty()) {
-        LOG(ERROR) << "Got a control response without pending control messages";
-        return;
-    }
-
-    if (!pending_control_message_results.front().has_value()) {
-        pending_control_message_results.pop();
-        return;
-    }
-
-    if (!pending_control_message_results.front().has_value()) {
-        return;
-    }
-
-    auto& control_response = init_message.control_response();
-    uint32_t response =
-            control_response.result() ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-    pending_control_message_results.front()->SendUint32(response);
-    pending_control_message_results.pop();
-}
-
 bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                                const std::string& source_context, const ucred& cr) {
     // We check the legacy method first but these properties are dontaudit, so we only log an audit
@@ -525,7 +468,9 @@
     }
 
     if (StartsWith(name, "ctl.")) {
-        return SendControlMessage(name.c_str() + 4, value, cr.pid, error);
+        return HandleControlMessage(name.c_str() + 4, value, cr.pid)
+                       ? PROP_SUCCESS
+                       : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
     }
 
     // sys.powerctl is a special property that is used to make the device reboot.  We want to log
@@ -610,10 +555,6 @@
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
         }
 
-        if (result == PROP_SUCCESS && StartsWith(prop_name, "ctl.")) {
-            pending_control_message_results.emplace(std::nullopt);
-        }
-
         break;
       }
 
@@ -641,12 +582,7 @@
             LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
         }
-
-        if (result == PROP_SUCCESS && StartsWith(name, "ctl.")) {
-            pending_control_message_results.emplace(std::move(socket));
-        } else {
-            socket.SendUint32(result);
-        }
+        socket.SendUint32(result);
         break;
       }
 
@@ -805,6 +741,33 @@
     }
 }
 
+/* When booting an encrypted system, /data is not mounted when the
+ * property service is started, so any properties stored there are
+ * not loaded.  Vold triggers init to load these properties once it
+ * has mounted /data.
+ */
+void load_persist_props(void) {
+    // Devices with FDE have load_persist_props called twice; the first time when the temporary
+    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
+    // read persistent properties from the temporary /data partition or mark persistent properties
+    // as having been loaded during the first call, so we return in that case.
+    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+    if (crypto_state == "encrypted" && crypto_type == "block") {
+        static size_t num_calls = 0;
+        if (++num_calls == 1) return;
+    }
+
+    load_override_properties();
+    /* Read persistent properties after all default values have been loaded. */
+    auto persistent_properties = LoadPersistentProperties();
+    for (const auto& persistent_property_record : persistent_properties.properties()) {
+        property_set(persistent_property_record.name(), persistent_property_record.value());
+    }
+    persistent_properties_loaded = true;
+    property_set("ro.persistent_properties.ready", "true");
+}
+
 // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
 // set, derive them from ro.product.${partition}.* properties
 static void property_initialize_ro_product_props() {
@@ -1022,87 +985,21 @@
     selinux_android_restorecon(kPropertyInfosPath, 0);
 }
 
-static void HandleInitSocket() {
-    auto message = ReadMessage(init_socket);
-    if (!message) {
-        LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
-        return;
-    }
-
-    auto init_message = InitMessage{};
-    if (!init_message.ParseFromString(*message)) {
-        LOG(ERROR) << "Could not parse message from init";
-        return;
-    }
-
-    switch (init_message.msg_case()) {
-        case InitMessage::kControlResponse: {
-            HandleControlResponse(init_message);
-            break;
-        }
-        case InitMessage::kLoadPersistentProperties: {
-            load_override_properties();
-            // Read persistent properties after all default values have been loaded.
-            auto persistent_properties = LoadPersistentProperties();
-            for (const auto& persistent_property_record : persistent_properties.properties()) {
-                InitPropertySet(persistent_property_record.name(),
-                                persistent_property_record.value());
-            }
-            InitPropertySet("ro.persistent_properties.ready", "true");
-            persistent_properties_loaded = true;
-            break;
-        }
-        default:
-            LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
-    }
-}
-
-static void PropertyServiceThread() {
-    Epoll epoll;
-    if (auto result = epoll.Open(); !result) {
-        LOG(FATAL) << result.error();
-    }
-
-    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
-        LOG(FATAL) << result.error();
-    }
-
-    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
-        LOG(FATAL) << result.error();
-    }
-
-    while (true) {
-        if (auto result = epoll.Wait(std::nullopt); !result) {
-            LOG(ERROR) << result.error();
-        }
-    }
-}
-
-void StartPropertyService(int* epoll_socket) {
+void StartPropertyService(Epoll* epoll) {
     property_set("ro.property_service.version", "2");
 
-    int sockets[2];
-    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
-        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
-    }
-    *epoll_socket = sockets[0];
-    init_socket = sockets[1];
-
-    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC, false, 0666, 0, 0,
-                                   {})) {
+    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   false, 0666, 0, 0, {})) {
         property_set_fd = *result;
     } else {
-        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
+        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
 
-    std::thread{PropertyServiceThread}.detach();
-
-    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
-        android::base::SetProperty(key, value);
-        return 0;
-    };
+    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
+        PLOG(FATAL) << result.error();
+    }
 }
 
 }  // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 8f7d8d9..7f9f844 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,15 +25,17 @@
 namespace android {
 namespace init {
 
-static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
-
 bool CanReadProperty(const std::string& source_context, const std::string& name);
 
 extern uint32_t (*property_set)(const std::string& name, const std::string& value);
 
+uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+                           const std::string& source_context, const ucred& cr, std::string* error);
+
 void property_init();
 void property_load_boot_defaults(bool load_debug_prop);
-void StartPropertyService(int* epoll_socket);
+void load_persist_props();
+void StartPropertyService(Epoll* epoll);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
deleted file mode 100644
index 894fa13..0000000
--- a/init/property_service.proto
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-message PropertyMessage {
-    message ControlMessage {
-        optional string msg = 1;
-        optional string name = 2;
-        optional int32 pid = 3;
-    }
-
-    message ChangedMessage {
-        optional string name = 1;
-        optional string value = 2;
-    }
-
-    oneof msg {
-        ControlMessage control_message = 1;
-        ChangedMessage changed_message = 2;
-    };
-}
-
-message InitMessage {
-    message ControlResponse { optional bool result = 1; }
-
-    oneof msg {
-        ControlResponse control_response = 1;
-        bool load_persistent_properties = 2;
-    };
-}
diff --git a/init/proto_utils.h b/init/proto_utils.h
deleted file mode 100644
index 93a7d57..0000000
--- a/init/proto_utils.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "result.h"
-
-namespace android {
-namespace init {
-
-constexpr size_t kBufferSize = 4096;
-
-inline Result<std::string> ReadMessage(int socket) {
-    char buffer[kBufferSize] = {};
-    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
-    if (result == 0) {
-        return Error();
-    } else if (result < 0) {
-        return ErrnoError();
-    }
-    return std::string(buffer, result);
-}
-
-template <typename T>
-Result<void> SendMessage(int socket, const T& message) {
-    std::string message_string;
-    if (!message.SerializeToString(&message_string)) {
-        return Error() << "Unable to serialize message";
-    }
-
-    if (message_string.size() > kBufferSize) {
-        return Error() << "Serialized message too long to send";
-    }
-
-    if (auto result =
-                TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
-        result != static_cast<long>(message_string.size())) {
-        return ErrnoError() << "send() failed to send message contents";
-    }
-    return {};
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index ec93b58..00f91d8 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -18,17 +18,16 @@
 
 #include <fcntl.h>
 #include <poll.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <selinux/android.h>
 
 #include "action.h"
 #include "builtins.h"
-#include "proto_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -60,6 +59,45 @@
 
 namespace {
 
+constexpr size_t kBufferSize = 4096;
+
+Result<std::string> ReadMessage(int socket) {
+    char buffer[kBufferSize] = {};
+    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
+    if (result == 0) {
+        return Error();
+    } else if (result < 0) {
+        return ErrnoError();
+    }
+    return std::string(buffer, result);
+}
+
+template <typename T>
+Result<void> SendMessage(int socket, const T& message) {
+    std::string message_string;
+    if (!message.SerializeToString(&message_string)) {
+        return Error() << "Unable to serialize message";
+    }
+
+    if (message_string.size() > kBufferSize) {
+        return Error() << "Serialized message too long to send";
+    }
+
+    if (auto result =
+            TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
+        result != static_cast<long>(message_string.size())) {
+        return ErrnoError() << "send() failed to send message contents";
+    }
+    return {};
+}
+
+std::vector<std::pair<std::string, std::string>> properties_to_set;
+
+uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
+    properties_to_set.emplace_back(name, value);
+    return 0;
+}
+
 class SubcontextProcess {
   public:
     SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
@@ -93,6 +131,14 @@
         result = RunBuiltinFunction(map_result->function, args, context_);
     }
 
+    for (const auto& [name, value] : properties_to_set) {
+        auto property = reply->add_properties_to_set();
+        property->set_name(name);
+        property->set_value(value);
+    }
+
+    properties_to_set.clear();
+
     if (result) {
         reply->set_success(true);
     } else {
@@ -178,10 +224,7 @@
 
     SelabelInitialize();
 
-    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
-        android::base::SetProperty(key, value);
-        return 0;
-    };
+    property_set = SubcontextPropertySet;
 
     auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
     subcontext_process.MainLoop();
@@ -268,6 +311,15 @@
         return subcontext_reply.error();
     }
 
+    for (const auto& property : subcontext_reply->properties_to_set()) {
+        ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
+        std::string error;
+        if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
+            LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
+                       << property.value() << "': " << error;
+        }
+    }
+
     if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
         auto& failure = subcontext_reply->failure();
         return ResultError(failure.error_string(), failure.error_errno());
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e..c31f4fb 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,10 @@
         Failure failure = 2;
         ExpandArgsReply expand_args_reply = 3;
     }
+
+    message PropertyToSet {
+        optional string name = 1;
+        optional string value = 2;
+    }
+    repeated PropertyToSet properties_to_set = 4;
 }
\ No newline at end of file
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 1f87b3e..d931ed1 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -3004,21 +3004,6 @@
   EXPECT_LE(0, android_log_destroy(&ctx));
   ASSERT_TRUE(NULL == ctx);
 }
-
-TEST(liblog, android_log_write_list_buffer) {
-  __android_log_event_list ctx(1005);
-  ctx << 1005 << "tag_def"
-      << "(tag|1),(name|3),(format|3)";
-  std::string buffer(ctx);
-  ctx.close();
-
-  char msgBuf[1024];
-  memset(msgBuf, 0, sizeof(msgBuf));
-  EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(), msgBuf,
-                                         sizeof(msgBuf)),
-            0);
-  EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
-}
 #endif  // USING_LOGGER_DEFAULT
 
 #ifdef USING_LOGGER_DEFAULT  // Do not retest pmsg functionality
diff --git a/liblog/tests/liblog_test_default.cpp b/liblog/tests/liblog_test_default.cpp
index 9fc443c..2edea27 100644
--- a/liblog/tests/liblog_test_default.cpp
+++ b/liblog/tests/liblog_test_default.cpp
@@ -2,4 +2,5 @@
 #include <log/log_transport.h>
 #define TEST_LOGGER LOGGER_DEFAULT
 #endif
+#define USING_LOGGER_DEFAULT
 #include "liblog_test.cpp"
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 15f03d0..0c9a2b8 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -34,6 +34,7 @@
     host_supported: true,
     srcs: [
         "process.cpp",
+        "process_map.cpp",
     ],
 
     local_include_dirs: ["include"],
@@ -58,6 +59,7 @@
     name: "libprocinfo_test",
     defaults: ["libprocinfo_defaults"],
     host_supported: true,
+    isolated: true,
     srcs: [
         "process_test.cpp",
         "process_map_test.cpp",
diff --git a/libprocinfo/include/procinfo/process_map.h b/libprocinfo/include/procinfo/process_map.h
index b6ec3cb..569a022 100644
--- a/libprocinfo/include/procinfo/process_map.h
+++ b/libprocinfo/include/procinfo/process_map.h
@@ -176,5 +176,9 @@
                const char* name) { maps->emplace_back(start, end, flags, pgoff, inode, name); });
 }
 
+bool ReadMapFileAsyncSafe(const char* map_file, void* buffer, size_t buffer_size,
+                          const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
+                                                   const char*)>& callback);
+
 } /* namespace procinfo */
 } /* namespace android */
diff --git a/libprocinfo/process_map.cpp b/libprocinfo/process_map.cpp
new file mode 100644
index 0000000..5e240b9
--- /dev/null
+++ b/libprocinfo/process_map.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procinfo/process_map.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <procinfo/process.h>
+
+namespace android {
+namespace procinfo {
+
+bool ReadMapFileAsyncSafe(const char* map_file, void* buffer, size_t buffer_size,
+                          const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
+                                                   const char*)>& callback) {
+  if (buffer == nullptr || buffer_size == 0) {
+    return false;
+  }
+
+  int fd = open(map_file, O_RDONLY | O_CLOEXEC);
+  if (fd == -1) {
+    return false;
+  }
+
+  char* char_buffer = reinterpret_cast<char*>(buffer);
+  size_t start = 0;
+  size_t read_bytes = 0;
+  char* line = nullptr;
+  bool read_complete = false;
+  while (true) {
+    ssize_t bytes =
+        TEMP_FAILURE_RETRY(read(fd, char_buffer + read_bytes, buffer_size - read_bytes - 1));
+    if (bytes <= 0) {
+      if (read_bytes == 0) {
+        close(fd);
+        return bytes == 0;
+      }
+      // Treat the last piece of data as the last line.
+      char_buffer[start + read_bytes] = '\n';
+      bytes = 1;
+      read_complete = true;
+    }
+    read_bytes += bytes;
+
+    while (read_bytes > 0) {
+      char* newline = reinterpret_cast<char*>(memchr(&char_buffer[start], '\n', read_bytes));
+      if (newline == nullptr) {
+        break;
+      }
+      *newline = '\0';
+      line = &char_buffer[start];
+      start = newline - char_buffer + 1;
+      read_bytes -= newline - line + 1;
+
+      // Ignore the return code, errors are okay.
+      ReadMapFileContent(line, callback);
+    }
+
+    if (read_complete) {
+      close(fd);
+      return true;
+    }
+
+    if (start == 0 && read_bytes == buffer_size - 1) {
+      // The buffer provided is too small to contain this line, give up
+      // and indicate failure.
+      close(fd);
+      return false;
+    }
+
+    // Copy any leftover data to the front  of the buffer.
+    if (start > 0) {
+      if (read_bytes > 0) {
+        memmove(char_buffer, &char_buffer[start], read_bytes);
+      }
+      start = 0;
+    }
+  }
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_map_test.cpp b/libprocinfo/process_map_test.cpp
index 562d864..b1bdc08 100644
--- a/libprocinfo/process_map_test.cpp
+++ b/libprocinfo/process_map_test.cpp
@@ -16,9 +16,14 @@
 
 #include <procinfo/process_map.h>
 
+#include <inttypes.h>
+#include <sys/mman.h>
+
 #include <string>
+#include <vector>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 
 #include <gtest/gtest.h>
 
@@ -63,3 +68,215 @@
   ASSERT_TRUE(android::procinfo::ReadProcessMaps(getpid(), &maps));
   ASSERT_GT(maps.size(), 0u);
 }
+
+extern "C" void malloc_disable();
+extern "C" void malloc_enable();
+
+struct TestMapInfo {
+  TestMapInfo() = default;
+  TestMapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
+              const char* new_name)
+      : start(start), end(end), flags(flags), pgoff(pgoff), inode(inode) {
+    strcpy(name, new_name);
+  }
+  uint64_t start = 0;
+  uint64_t end = 0;
+  uint16_t flags = 0;
+  uint64_t pgoff = 0;
+  ino_t inode = 0;
+  char name[100] = {};
+};
+
+void VerifyReadMapFileAsyncSafe(const char* maps_data,
+                                const std::vector<TestMapInfo>& expected_info) {
+  TemporaryFile tf;
+  ASSERT_TRUE(android::base::WriteStringToFd(maps_data, tf.fd));
+
+  std::vector<TestMapInfo> saved_info(expected_info.size());
+  size_t num_maps = 0;
+
+  auto callback = [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
+                      const char* name) {
+    if (num_maps != saved_info.size()) {
+      TestMapInfo& saved = saved_info[num_maps];
+      saved.start = start;
+      saved.end = end;
+      saved.flags = flags;
+      saved.pgoff = pgoff;
+      saved.inode = inode;
+      strcpy(saved.name, name);
+    }
+    num_maps++;
+  };
+
+  std::vector<char> buffer(64 * 1024);
+
+#if defined(__BIONIC__)
+  // Any allocations will block after this call.
+  malloc_disable();
+#endif
+
+  bool parsed =
+      android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer.data(), buffer.size(), callback);
+
+#if defined(__BIONIC__)
+  malloc_enable();
+#endif
+
+  ASSERT_TRUE(parsed) << "Parsing of data failed:\n" << maps_data;
+  ASSERT_EQ(expected_info.size(), num_maps);
+  for (size_t i = 0; i < expected_info.size(); i++) {
+    const TestMapInfo& expected = expected_info[i];
+    const TestMapInfo& saved = saved_info[i];
+    EXPECT_EQ(expected.start, saved.start);
+    EXPECT_EQ(expected.end, saved.end);
+    EXPECT_EQ(expected.flags, saved.flags);
+    EXPECT_EQ(expected.pgoff, saved.pgoff);
+    EXPECT_EQ(expected.inode, saved.inode);
+    EXPECT_STREQ(expected.name, saved.name);
+  }
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_invalid) {
+  std::vector<TestMapInfo> expected_info;
+
+  VerifyReadMapFileAsyncSafe("12c00000-2ac00000", expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_single) {
+  std::vector<TestMapInfo> expected_info;
+  expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643,
+                             "/lib/fake.so");
+
+  VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so",
+                             expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_single_with_newline) {
+  std::vector<TestMapInfo> expected_info;
+  expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643,
+                             "/lib/fake.so");
+
+  VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so\n",
+                             expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_single_no_library) {
+  std::vector<TestMapInfo> expected_info;
+  expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 0xb00, 101, "");
+
+  VerifyReadMapFileAsyncSafe("a0000-c0000 rwxp 00000b00 00:05 101", expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_multiple) {
+  std::vector<TestMapInfo> expected_info;
+  expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 1, 100, "");
+  expected_info.emplace_back(0xd0000, 0xe0000, PROT_READ, 2, 101, "/lib/libsomething1.so");
+  expected_info.emplace_back(0xf0000, 0x100000, PROT_WRITE, 3, 102, "/lib/libsomething2.so");
+  expected_info.emplace_back(0x110000, 0x120000, PROT_EXEC, 4, 103, "[anon:something or another]");
+
+  std::string map_data =
+      "0a0000-0c0000 rwxp 00000001 00:05 100\n"
+      "0d0000-0e0000 r--p 00000002 00:05 101  /lib/libsomething1.so\n"
+      "0f0000-100000 -w-p 00000003 00:05 102  /lib/libsomething2.so\n"
+      "110000-120000 --xp 00000004 00:05 103  [anon:something or another]\n";
+
+  VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_multiple_reads) {
+  std::vector<TestMapInfo> expected_info;
+  std::string map_data;
+  uint64_t start = 0xa0000;
+  for (size_t i = 0; i < 10000; i++) {
+    map_data += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r--p %zx 01:20 %zu fake.so\n",
+                                            start, start + 0x1000, i, 1000 + i);
+    expected_info.emplace_back(start, start + 0x1000, PROT_READ, i, 1000 + i, "fake.so");
+  }
+
+  VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_buffer_nullptr) {
+  size_t num_calls = 0;
+  auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
+
+#if defined(__BIONIC__)
+  // Any allocations will block after this call.
+  malloc_disable();
+#endif
+
+  bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", nullptr, 10, callback);
+
+#if defined(__BIONIC__)
+  malloc_enable();
+#endif
+
+  ASSERT_FALSE(parsed);
+  EXPECT_EQ(0UL, num_calls);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_buffer_size_zero) {
+  size_t num_calls = 0;
+  auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
+
+#if defined(__BIONIC__)
+  // Any allocations will block after this call.
+  malloc_disable();
+#endif
+
+  char buffer[10];
+  bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, 0, callback);
+
+#if defined(__BIONIC__)
+  malloc_enable();
+#endif
+
+  ASSERT_FALSE(parsed);
+  EXPECT_EQ(0UL, num_calls);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_no_calls) {
+  size_t num_calls = 0;
+  auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
+
+#if defined(__BIONIC__)
+  // Any allocations will block after this call.
+  malloc_disable();
+#endif
+
+  char buffer[10];
+  bool parsed =
+      android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, sizeof(buffer), callback);
+
+#if defined(__BIONIC__)
+  malloc_enable();
+#endif
+
+  ASSERT_FALSE(parsed);
+  EXPECT_EQ(0UL, num_calls);
+}
+
+TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_could_parse) {
+  TemporaryFile tf;
+  ASSERT_TRUE(android::base::WriteStringToFd(
+      "0a0000-0c0000 rwxp 00000001 00:05 100    /fake/lib.so\n", tf.fd));
+
+  size_t num_calls = 0;
+  auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
+
+#if defined(__BIONIC__)
+  // Any allocations will block after this call.
+  malloc_disable();
+#endif
+
+  char buffer[39];
+  bool parsed = android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer, sizeof(buffer), callback);
+
+#if defined(__BIONIC__)
+  malloc_enable();
+#endif
+
+  ASSERT_FALSE(parsed);
+  EXPECT_EQ(0UL, num_calls);
+}
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 2fd9f95..82c4fb9 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -56,14 +56,7 @@
       mLogId(elem.mLogId),
       mDropped(elem.mDropped) {
     if (mDropped) {
-        if (elem.isBinary() && elem.mMsg != nullptr) {
-            // for the following "len" value, refer to : setDropped(uint16_t value), getTag()
-            const int len = sizeof(android_event_header_t);
-            mMsg = new char[len];
-            memcpy(mMsg, elem.mMsg, len);
-        } else {
-            mMsg = nullptr;
-        }
+        mTag = elem.getTag();
     } else {
         mMsg = new char[mMsgLen];
         memcpy(mMsg, elem.mMsg, mMsgLen);
@@ -71,31 +64,43 @@
 }
 
 LogBufferElement::~LogBufferElement() {
-    delete[] mMsg;
+    if (!mDropped) {
+        delete[] mMsg;
+    }
 }
 
 uint32_t LogBufferElement::getTag() const {
-    return (isBinary() &&
-            ((mDropped && mMsg != nullptr) ||
-             (!mDropped && mMsgLen >= sizeof(android_event_header_t))))
-               ? reinterpret_cast<const android_event_header_t*>(mMsg)->tag
-               : 0;
+    // Binary buffers have no tag.
+    if (!isBinary()) {
+        return 0;
+    }
+
+    // Dropped messages store the tag in place of mMsg.
+    if (mDropped) {
+        return mTag;
+    }
+
+    // For non-dropped messages, we get the tag from the message header itself.
+    if (mMsgLen < sizeof(android_event_header_t)) {
+        return 0;
+    }
+
+    return reinterpret_cast<const android_event_header_t*>(mMsg)->tag;
 }
 
 uint16_t LogBufferElement::setDropped(uint16_t value) {
-    // The tag information is saved in mMsg data, if the tag is non-zero
-    // save only the information needed to get the tag.
-    if (getTag() != 0) {
-        if (mMsgLen > sizeof(android_event_header_t)) {
-            char* truncated_msg = new char[sizeof(android_event_header_t)];
-            memcpy(truncated_msg, mMsg, sizeof(android_event_header_t));
-            delete[] mMsg;
-            mMsg = truncated_msg;
-        }  // mMsgLen == sizeof(android_event_header_t), already at minimum.
-    } else {
-        delete[] mMsg;
-        mMsg = nullptr;
+    if (mDropped) {
+        return mDroppedCount = value;
     }
+
+    // The tag information is saved in mMsg data, which is in a union with mTag, used after mDropped
+    // is set to true. Therefore we save the tag value aside, delete mMsg, then set mTag to the tag
+    // value in its place.
+    auto old_tag = getTag();
+    delete[] mMsg;
+    mMsg = nullptr;
+
+    mTag = old_tag;
     mDropped = true;
     return mDroppedCount = value;
 }
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 57b0a95..da4991b 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -41,7 +41,10 @@
     const uint32_t mPid;
     const uint32_t mTid;
     log_time mRealTime;
-    char* mMsg;
+    union {
+        char* mMsg;    // mDropped == false
+        int32_t mTag;  // mDropped == true
+    };
     union {
         const uint16_t mMsgLen;  // mDropped == false
         uint16_t mDroppedCount;  // mDropped == true
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9b0075d..0f61a61 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -618,6 +618,9 @@
     mkdir /data/cache/backup_stage 0700 system system
     mkdir /data/cache/backup 0700 system system
 
+    mkdir /data/rollback 0700 system system
+    mkdir /data/rollback-observer 0700 system system
+
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
     parse_apex_configs
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index ca2421b..6668cf3 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -41,7 +41,6 @@
 using android::hardware::health::V2_0::StorageInfo;
 
 const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
-const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
 const char* emmc_info_t::emmc_ver_str[9] = {
     "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
 };
@@ -62,10 +61,8 @@
     if (healthService != nullptr) {
         return new health_storage_info_t(healthService);
     }
-    if (FileExists(emmc_info_t::emmc_sysfs) ||
-        FileExists(emmc_info_t::emmc_debugfs)) {
-        return new emmc_info_t;
-    }
+    if (FileExists(emmc_info_t::emmc_sysfs)) return new emmc_info_t;
+
     if (FileExists(ufs_info_t::health_file)) {
         return new ufs_info_t;
     }
@@ -241,8 +238,7 @@
 
 void emmc_info_t::report()
 {
-    if (!report_sysfs() && !report_debugfs())
-        return;
+    if (!report_sysfs()) return;
 
     publish();
 }
@@ -284,54 +280,6 @@
     return true;
 }
 
-namespace {
-
-const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
-/* 2 characters in string for each byte */
-const size_t EXT_CSD_REV_IDX = 192 * 2;
-const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2;
-const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
-const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
-
-} // namespace
-
-bool emmc_info_t::report_debugfs()
-{
-    string buffer;
-    uint16_t rev = 0;
-
-    if (!ReadFileToString(emmc_debugfs, &buffer) ||
-        buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
-        return false;
-    }
-
-    string str = buffer.substr(EXT_CSD_REV_IDX, 2);
-    if (!ParseUint(str, &rev) ||
-        rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
-        return false;
-    }
-
-    version = "emmc ";
-    version += emmc_ver_str[rev];
-
-    str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2);
-    if (!ParseUint(str, &eol)) {
-        return false;
-    }
-
-    str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2);
-    if (!ParseUint(str, &lifetime_a)) {
-        return false;
-    }
-
-    str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2);
-    if (!ParseUint(str, &lifetime_b)) {
-        return false;
-    }
-
-    return true;
-}
-
 void ufs_info_t::report()
 {
     string buffer;