Merge "liblog: run in isolated mode, disable flaky tests"
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 358c980..0579a3d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -782,6 +782,7 @@
     } else {
         fs_mgr_set_blk_ro(device_path, false);
     }
+    entry.fs_mgr_flags.check = true;
     auto save_errno = errno;
     auto mounted = fs_mgr_do_mount_one(entry) == 0;
     if (!mounted) {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 834bf3b..8cf0f3b 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -49,11 +49,17 @@
         "libfiemap_headers",
     ],
     export_include_dirs: ["include"],
+    proto: {
+        type: "lite",
+        export_proto_headers: true,
+        canonical_path_from_root: false,
+    },
 }
 
 filegroup {
     name: "libsnapshot_sources",
     srcs: [
+        "android/snapshot/snapshot.proto",
         "snapshot.cpp",
         "snapshot_metadata_updater.cpp",
         "partition_cow_creator.cpp",
@@ -132,9 +138,10 @@
         "libbinder",
         "libext4_utils",
         "libfs_mgr",
-        "libutils",
         "liblog",
         "liblp",
+        "libprotobuf-cpp-lite",
+        "libutils",
     ],
     init_rc: [
         "snapshotctl.rc",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
new file mode 100644
index 0000000..629c3a4
--- /dev/null
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -0,0 +1,87 @@
+// 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 = "proto3";
+package android.snapshot;
+
+option optimize_for = LITE_RUNTIME;
+
+// Next: 4
+enum SnapshotState {
+    // No snapshot is found.
+    NONE = 0;
+
+    // The snapshot has been created and possibly written to. Rollbacks are
+    // possible by destroying the snapshot.
+    CREATED = 1;
+
+    // Changes are being merged. No rollbacks are possible beyond this point.
+    MERGING = 2;
+
+    // Changes have been merged, Future reboots may map the base device
+    // directly.
+    MERGE_COMPLETED = 3;
+}
+
+// Next: 9
+message SnapshotStatus {
+    // Name of the snapshot. This is usually the name of the snapshotted
+    // logical partition; for example, "system_b".
+    string name = 1;
+
+    SnapshotState state = 2;
+
+    // Size of the full (base) device.
+    uint64 device_size = 3;
+
+    // Size of the snapshot. This is the sum of lengths of ranges in the base
+    // device that needs to be snapshotted during the update.
+    // This must be less than or equal to |device_size|.
+    // This value is 0 if no snapshot is needed for this device because
+    // no changes
+    uint64 snapshot_size = 4;
+
+    // Size of the "COW partition". A COW partition is a special logical
+    // partition represented in the super partition metadata. This partition and
+    // the "COW image" form the "COW device" that supports the snapshot device.
+    //
+    // When SnapshotManager creates a COW device, it first searches for unused
+    // blocks in the super partition, and use those before creating the COW
+    // image if the COW partition is not big enough.
+    //
+    // This value is 0 if no space in super is left for the COW partition.
+    // |cow_partition_size + cow_file_size| must not be zero if |snapshot_size|
+    // is non-zero.
+    uint64 cow_partition_size = 5;
+
+    // Size of the "COW file", or "COW image". A COW file / image is created
+    // when the "COW partition" is not big enough to store changes to the
+    // snapshot device.
+    //
+    // This value is 0 if |cow_partition_size| is big enough to hold all changes
+    // to the snapshot device.
+    uint64 cow_file_size = 6;
+
+    // Sectors allocated for the COW device. Recording this value right after
+    // the update and before the merge allows us to infer the progress of the
+    // merge process.
+    // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
+    uint64 sectors_allocated = 7;
+
+    // Metadata sectors allocated for the COW device. Recording this value right
+    // before the update and before the merge allows us to infer the progress of
+    // the merge process.
+    // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
+    uint64 metadata_sectors = 8;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 0d6aa2c..69f2895 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -53,8 +53,9 @@
 
 struct AutoDeleteCowImage;
 struct AutoDeleteSnapshot;
-struct PartitionCowCreator;
 struct AutoDeviceList;
+struct PartitionCowCreator;
+class SnapshotStatus;
 
 static constexpr const std::string_view kCowGroupName = "cow";
 
@@ -250,22 +251,6 @@
     std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags);
     bool Truncate(LockedFile* file);
 
-    enum class SnapshotState : int { None, Created, Merging, MergeCompleted };
-    static std::string to_string(SnapshotState state);
-
-    // This state is persisted per-snapshot in /metadata/ota/snapshots/.
-    struct SnapshotStatus {
-        SnapshotState state = SnapshotState::None;
-        uint64_t device_size = 0;
-        uint64_t snapshot_size = 0;
-        uint64_t cow_partition_size = 0;
-        uint64_t cow_file_size = 0;
-
-        // These are non-zero when merging.
-        uint64_t sectors_allocated = 0;
-        uint64_t metadata_sectors = 0;
-    };
-
     // Create a new snapshot record. This creates the backing COW store and
     // persists information needed to map the device. The device can be mapped
     // with MapSnapshot().
@@ -282,7 +267,7 @@
     //
     // All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes
     // must be a multiple of the sector size (512 bytes).
-    bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status);
+    bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status);
 
     // |name| should be the base partition name (e.g. "system_a"). Create the
     // backing COW image using the size previously passed to CreateSnapshot().
@@ -363,8 +348,7 @@
     UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
 
     // Interact with status files under /metadata/ota/snapshots.
-    bool WriteSnapshotStatus(LockedFile* lock, const std::string& name,
-                             const SnapshotStatus& status);
+    bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
     bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
     std::string GetSnapshotStatusFilePath(const std::string& name);
 
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 404ef27..eedc1cd 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include <android/snapshot/snapshot.pb.h>
 #include "utility.h"
 
 using android::dm::kSectorSize;
@@ -84,13 +85,14 @@
             << "logical_block_size is not power of 2";
 
     Return ret;
-    ret.snapshot_status.device_size = target_partition->size();
+    ret.snapshot_status.set_name(target_partition->name());
+    ret.snapshot_status.set_device_size(target_partition->size());
 
     // TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition
     // may be written directly.
-    ret.snapshot_status.snapshot_size = target_partition->size();
+    ret.snapshot_status.set_snapshot_size(target_partition->size());
 
-    auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size);
+    auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size());
     if (!cow_size.has_value()) return std::nullopt;
 
     // Compute regions that are free in both current and target metadata. These are the regions
@@ -106,18 +108,20 @@
     LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes";
 
     // Compute the COW partition size.
-    ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length);
+    uint64_t cow_partition_size = std::min(*cow_size, free_region_length);
     // Round it down to the nearest logical block. Logical partitions must be a multiple
     // of logical blocks.
-    ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1);
+    cow_partition_size &= ~(logical_block_size - 1);
+    ret.snapshot_status.set_cow_partition_size(cow_partition_size);
     // Assign cow_partition_usable_regions to indicate what regions should the COW partition uses.
     ret.cow_partition_usable_regions = std::move(free_regions);
 
     // The rest of the COW space is allocated on ImageManager.
-    ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size;
+    uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size();
     // Round it up to the nearest sector.
-    ret.snapshot_status.cow_file_size += kSectorSize - 1;
-    ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1);
+    cow_file_size += kSectorSize - 1;
+    cow_file_size &= ~(kSectorSize - 1);
+    ret.snapshot_status.set_cow_file_size(cow_file_size);
 
     return ret;
 }
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h
index 0e645c6..8888f78 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -20,8 +20,9 @@
 #include <string>
 
 #include <liblp/builder.h>
+#include <update_engine/update_metadata.pb.h>
 
-#include <libsnapshot/snapshot.h>
+#include <android/snapshot/snapshot.pb.h>
 
 namespace android {
 namespace snapshot {
@@ -51,7 +52,7 @@
     const RepeatedPtrField<InstallOperation>* operations = nullptr;
 
     struct Return {
-        SnapshotManager::SnapshotStatus snapshot_status;
+        SnapshotStatus snapshot_status;
         std::vector<Interval> cow_partition_usable_regions;
     };
 
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index ccd087e..feb3c2d 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -51,8 +51,8 @@
                                 .current_suffix = "_a"};
     auto ret = creator.Run();
     ASSERT_TRUE(ret.has_value());
-    ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size);
-    ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size);
+    ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size());
+    ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size());
 }
 
 TEST_F(PartitionCowCreatorTest, Holes) {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 02c7de6..5b758c9 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -38,6 +38,7 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
+#include <android/snapshot/snapshot.pb.h>
 #include "partition_cow_creator.h"
 #include "snapshot_metadata_updater.h"
 #include "utility.h"
@@ -234,42 +235,50 @@
     return WriteUpdateState(lock.get(), UpdateState::Unverified);
 }
 
-bool SnapshotManager::CreateSnapshot(LockedFile* lock, const std::string& name,
-                                     SnapshotManager::SnapshotStatus status) {
+bool SnapshotManager::CreateSnapshot(LockedFile* lock, SnapshotStatus* status) {
     CHECK(lock);
     CHECK(lock->lock_mode() == LOCK_EX);
+    CHECK(status);
+
+    if (status->name().empty()) {
+        LOG(ERROR) << "SnapshotStatus has no name.";
+        return false;
+    }
     // Sanity check these sizes. Like liblp, we guarantee the partition size
     // is respected, which means it has to be sector-aligned. (This guarantee
     // is useful for locating avb footers correctly). The COW file size, however,
     // can be arbitrarily larger than specified, so we can safely round it up.
-    if (status.device_size % kSectorSize != 0) {
-        LOG(ERROR) << "Snapshot " << name
-                   << " device size is not a multiple of the sector size: " << status.device_size;
+    if (status->device_size() % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << status->name()
+                   << " device size is not a multiple of the sector size: "
+                   << status->device_size();
         return false;
     }
-    if (status.snapshot_size % kSectorSize != 0) {
-        LOG(ERROR) << "Snapshot " << name << " snapshot size is not a multiple of the sector size: "
-                   << status.snapshot_size;
+    if (status->snapshot_size() % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << status->name()
+                   << " snapshot size is not a multiple of the sector size: "
+                   << status->snapshot_size();
         return false;
     }
-    if (status.cow_partition_size % kSectorSize != 0) {
-        LOG(ERROR) << "Snapshot " << name
+    if (status->cow_partition_size() % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << status->name()
                    << " cow partition size is not a multiple of the sector size: "
-                   << status.cow_partition_size;
+                   << status->cow_partition_size();
         return false;
     }
-    if (status.cow_file_size % kSectorSize != 0) {
-        LOG(ERROR) << "Snapshot " << name << " cow file size is not a multiple of the sector size: "
-                   << status.cow_partition_size;
+    if (status->cow_file_size() % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << status->name()
+                   << " cow file size is not a multiple of the sector size: "
+                   << status->cow_file_size();
         return false;
     }
 
-    status.state = SnapshotState::Created;
-    status.sectors_allocated = 0;
-    status.metadata_sectors = 0;
+    status->set_state(SnapshotState::CREATED);
+    status->set_sectors_allocated(0);
+    status->set_metadata_sectors(0);
 
-    if (!WriteSnapshotStatus(lock, name, status)) {
-        PLOG(ERROR) << "Could not write snapshot status: " << name;
+    if (!WriteSnapshotStatus(lock, *status)) {
+        PLOG(ERROR) << "Could not write snapshot status: " << status->name();
         return false;
     }
     return true;
@@ -287,15 +296,15 @@
 
     // The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
     // Sanity check this.
-    if (status.cow_file_size % kSectorSize != 0) {
+    if (status.cow_file_size() % kSectorSize != 0) {
         LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
-                   << status.cow_file_size;
+                   << status.cow_file_size();
         return false;
     }
 
     std::string cow_image_name = GetCowImageDeviceName(name);
     int cow_flags = IImageManager::CREATE_IMAGE_DEFAULT;
-    return images_->CreateBackingImage(cow_image_name, status.cow_file_size, cow_flags);
+    return images_->CreateBackingImage(cow_image_name, status.cow_file_size(), cow_flags);
 }
 
 bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
@@ -309,7 +318,7 @@
     if (!ReadSnapshotStatus(lock, name, &status)) {
         return false;
     }
-    if (status.state == SnapshotState::MergeCompleted) {
+    if (status.state() == SnapshotState::MERGE_COMPLETED) {
         LOG(ERROR) << "Should not create a snapshot device for " << name
                    << " after merging has completed.";
         return false;
@@ -328,24 +337,23 @@
             PLOG(ERROR) << "Could not determine block device size: " << base_device;
             return false;
         }
-        if (status.device_size != dev_size) {
+        if (status.device_size() != dev_size) {
             LOG(ERROR) << "Block device size for " << base_device << " does not match"
-                       << "(expected " << status.device_size << ", got " << dev_size << ")";
+                       << "(expected " << status.device_size() << ", got " << dev_size << ")";
             return false;
         }
     }
-    if (status.device_size % kSectorSize != 0) {
-        LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size;
+    if (status.device_size() % kSectorSize != 0) {
+        LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size();
         return false;
     }
-    if (status.snapshot_size % kSectorSize != 0 || status.snapshot_size > status.device_size) {
-        LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size;
+    if (status.snapshot_size() % kSectorSize != 0 ||
+        status.snapshot_size() > status.device_size()) {
+        LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size();
         return false;
     }
-    uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
-    uint64_t linear_sectors = (status.device_size - status.snapshot_size) / kSectorSize;
-
-
+    uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
+    uint64_t linear_sectors = (status.device_size() - status.snapshot_size()) / kSectorSize;
 
     auto& dm = DeviceMapper::Instance();
 
@@ -557,8 +565,9 @@
     if (!ReadSnapshotStatus(lock, name, &status)) {
         return false;
     }
-    if (status.state != SnapshotState::Created) {
-        LOG(WARNING) << "Snapshot " << name << " has unexpected state: " << to_string(status.state);
+    if (status.state() != SnapshotState::CREATED) {
+        LOG(WARNING) << "Snapshot " << name
+                     << " has unexpected state: " << SnapshotState_Name(status.state());
     }
 
     // After this, we return true because we technically did switch to a merge
@@ -568,15 +577,15 @@
         return false;
     }
 
-    status.state = SnapshotState::Merging;
+    status.set_state(SnapshotState::MERGING);
 
     DmTargetSnapshot::Status dm_status;
     if (!QuerySnapshotStatus(dm_name, nullptr, &dm_status)) {
         LOG(ERROR) << "Could not query merge status for snapshot: " << dm_name;
     }
-    status.sectors_allocated = dm_status.sectors_allocated;
-    status.metadata_sectors = dm_status.metadata_sectors;
-    if (!WriteSnapshotStatus(lock, name, status)) {
+    status.set_sectors_allocated(dm_status.sectors_allocated);
+    status.set_metadata_sectors(dm_status.metadata_sectors);
+    if (!WriteSnapshotStatus(lock, status)) {
         LOG(ERROR) << "Could not update status file for snapshot: " << name;
     }
     return true;
@@ -821,7 +830,7 @@
         // rebooted after this check, the device will still be a snapshot-merge
         // target. If the have rebooted, the device will now be a linear target,
         // and we can try cleanup again.
-        if (snapshot_status.state == SnapshotState::MergeCompleted) {
+        if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
             // NB: It's okay if this fails now, we gave cleanup our best effort.
             OnSnapshotMergeComplete(lock, name, snapshot_status);
             return UpdateState::MergeCompleted;
@@ -849,7 +858,7 @@
 
     // These two values are equal when merging is complete.
     if (status.sectors_allocated != status.metadata_sectors) {
-        if (snapshot_status.state == SnapshotState::MergeCompleted) {
+        if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
             LOG(ERROR) << "Snapshot " << name << " is merging after being marked merge-complete.";
             return UpdateState::MergeFailed;
         }
@@ -864,8 +873,8 @@
     // This makes it simpler to reason about the next reboot: no matter what
     // part of cleanup failed, first-stage init won't try to create another
     // snapshot device for this partition.
-    snapshot_status.state = SnapshotState::MergeCompleted;
-    if (!WriteSnapshotStatus(lock, name, snapshot_status)) {
+    snapshot_status.set_state(SnapshotState::MERGE_COMPLETED);
+    if (!WriteSnapshotStatus(lock, snapshot_status)) {
         return UpdateState::MergeFailed;
     }
     if (!OnSnapshotMergeComplete(lock, name, snapshot_status)) {
@@ -969,10 +978,10 @@
         return false;
     }
 
-    uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
-    if (snapshot_sectors * kSectorSize != status.snapshot_size) {
+    uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
+    if (snapshot_sectors * kSectorSize != status.snapshot_size()) {
         LOG(ERROR) << "Snapshot " << name
-                   << " size is not sector aligned: " << status.snapshot_size;
+                   << " size is not sector aligned: " << status.snapshot_size();
         return false;
     }
 
@@ -1003,7 +1012,7 @@
                        << " sectors, got: " << outer_table[0].spec.length;
             return false;
         }
-        uint64_t expected_device_sectors = status.device_size / kSectorSize;
+        uint64_t expected_device_sectors = status.device_size() / kSectorSize;
         uint64_t actual_device_sectors = outer_table[0].spec.length + outer_table[1].spec.length;
         if (expected_device_sectors != actual_device_sectors) {
             LOG(ERROR) << "Outer device " << name << " should have " << expected_device_sectors
@@ -1289,7 +1298,7 @@
             return false;
         }
         // No live snapshot if merge is completed.
-        if (live_snapshot_status->state == SnapshotState::MergeCompleted) {
+        if (live_snapshot_status->state() == SnapshotState::MERGE_COMPLETED) {
             live_snapshot_status.reset();
         }
     } while (0);
@@ -1390,7 +1399,7 @@
                                     AutoDeviceList* created_devices, std::string* cow_name) {
     CHECK(lock);
     if (!EnsureImageManager()) return false;
-    CHECK(snapshot_status.cow_partition_size + snapshot_status.cow_file_size > 0);
+    CHECK(snapshot_status.cow_partition_size() + snapshot_status.cow_file_size() > 0);
     auto begin = std::chrono::steady_clock::now();
 
     std::string partition_name = params.GetPartitionName();
@@ -1400,7 +1409,7 @@
     auto& dm = DeviceMapper::Instance();
 
     // Map COW image if necessary.
-    if (snapshot_status.cow_file_size > 0) {
+    if (snapshot_status.cow_file_size() > 0) {
         auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
         if (remaining_time.count() < 0) return false;
 
@@ -1411,7 +1420,7 @@
         created_devices->EmplaceBack<AutoUnmapImage>(images_.get(), cow_image_name);
 
         // If no COW partition exists, just return the image alone.
-        if (snapshot_status.cow_partition_size == 0) {
+        if (snapshot_status.cow_partition_size() == 0) {
             *cow_name = std::move(cow_image_name);
             LOG(INFO) << "Mapped COW image for " << partition_name << " at " << *cow_name;
             return true;
@@ -1421,7 +1430,7 @@
     auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
     if (remaining_time.count() < 0) return false;
 
-    CHECK(snapshot_status.cow_partition_size > 0);
+    CHECK(snapshot_status.cow_partition_size() > 0);
 
     // Create the DmTable for the COW device. It is the DmTable of the COW partition plus
     // COW image device as the last extent.
@@ -1434,14 +1443,14 @@
         return false;
     }
     // If the COW image exists, append it as the last extent.
-    if (snapshot_status.cow_file_size > 0) {
+    if (snapshot_status.cow_file_size() > 0) {
         std::string cow_image_device;
         if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
             LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
             return false;
         }
-        auto cow_partition_sectors = snapshot_status.cow_partition_size / kSectorSize;
-        auto cow_image_sectors = snapshot_status.cow_file_size / kSectorSize;
+        auto cow_partition_sectors = snapshot_status.cow_partition_size() / kSectorSize;
+        auto cow_image_sectors = snapshot_status.cow_file_size() / kSectorSize;
         table.Emplace<DmTargetLinear>(cow_partition_sectors, cow_image_sectors, cow_image_device,
                                       0);
     }
@@ -1602,101 +1611,38 @@
         return false;
     }
 
-    std::string contents;
-    if (!android::base::ReadFdToString(fd, &contents)) {
-        PLOG(ERROR) << "read failed: " << path;
-        return false;
-    }
-    auto pieces = android::base::Split(contents, " ");
-    if (pieces.size() != 7) {
-        LOG(ERROR) << "Invalid status line for snapshot: " << path;
+    if (!status->ParseFromFileDescriptor(fd.get())) {
+        PLOG(ERROR) << "Unable to parse " << path << " as SnapshotStatus";
         return false;
     }
 
-    if (pieces[0] == "none") {
-        status->state = SnapshotState::None;
-    } else if (pieces[0] == "created") {
-        status->state = SnapshotState::Created;
-    } else if (pieces[0] == "merging") {
-        status->state = SnapshotState::Merging;
-    } else if (pieces[0] == "merge-completed") {
-        status->state = SnapshotState::MergeCompleted;
-    } else {
-        LOG(ERROR) << "Unrecognized state " << pieces[0] << " for snapshot: " << name;
-        return false;
+    if (status->name() != name) {
+        LOG(WARNING) << "Found snapshot status named " << status->name() << " in " << path;
+        status->set_name(name);
     }
 
-    if (!android::base::ParseUint(pieces[1], &status->device_size)) {
-        LOG(ERROR) << "Invalid device size in status line for: " << path;
-        return false;
-    }
-    if (!android::base::ParseUint(pieces[2], &status->snapshot_size)) {
-        LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
-        return false;
-    }
-    if (!android::base::ParseUint(pieces[3], &status->cow_partition_size)) {
-        LOG(ERROR) << "Invalid cow linear size in status line for: " << path;
-        return false;
-    }
-    if (!android::base::ParseUint(pieces[4], &status->cow_file_size)) {
-        LOG(ERROR) << "Invalid cow file size in status line for: " << path;
-        return false;
-    }
-    if (!android::base::ParseUint(pieces[5], &status->sectors_allocated)) {
-        LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
-        return false;
-    }
-    if (!android::base::ParseUint(pieces[6], &status->metadata_sectors)) {
-        LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
-        return false;
-    }
     return true;
 }
 
-std::string SnapshotManager::to_string(SnapshotState state) {
-    switch (state) {
-        case SnapshotState::None:
-            return "none";
-        case SnapshotState::Created:
-            return "created";
-        case SnapshotState::Merging:
-            return "merging";
-        case SnapshotState::MergeCompleted:
-            return "merge-completed";
-        default:
-            LOG(ERROR) << "Unknown snapshot state: " << (int)state;
-            return "unknown";
-    }
-}
-
-bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const std::string& name,
-                                          const SnapshotStatus& status) {
+bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status) {
     // The caller must take an exclusive lock to modify snapshots.
     CHECK(lock);
     CHECK(lock->lock_mode() == LOCK_EX);
+    CHECK(!status.name().empty());
 
-    auto path = GetSnapshotStatusFilePath(name);
-    unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC, 0660));
+    auto path = GetSnapshotStatusFilePath(status.name());
+    unique_fd fd(
+            open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC | O_TRUNC, 0660));
     if (fd < 0) {
         PLOG(ERROR) << "Open failed: " << path;
         return false;
     }
 
-    std::vector<std::string> pieces = {
-            to_string(status.state),
-            std::to_string(status.device_size),
-            std::to_string(status.snapshot_size),
-            std::to_string(status.cow_partition_size),
-            std::to_string(status.cow_file_size),
-            std::to_string(status.sectors_allocated),
-            std::to_string(status.metadata_sectors),
-    };
-    auto contents = android::base::Join(pieces, " ");
-
-    if (!android::base::WriteStringToFd(contents, fd)) {
-        PLOG(ERROR) << "write failed: " << path;
+    if (!status.SerializeToFileDescriptor(fd.get())) {
+        PLOG(ERROR) << "Unable to write SnapshotStatus to " << path;
         return false;
     }
+
     return true;
 }
 
@@ -1714,7 +1660,7 @@
 
 std::string SnapshotManager::GetSnapshotDeviceName(const std::string& snapshot_name,
                                                    const SnapshotStatus& status) {
-    if (status.device_size != status.snapshot_size) {
+    if (status.device_size() != status.snapshot_size()) {
         return GetSnapshotExtraDeviceName(snapshot_name);
     }
     return snapshot_name;
@@ -1884,11 +1830,11 @@
         }
 
         LOG(INFO) << "For partition " << target_partition->name()
-                  << ", device size = " << cow_creator_ret->snapshot_status.device_size
-                  << ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size
+                  << ", device size = " << cow_creator_ret->snapshot_status.device_size()
+                  << ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size()
                   << ", cow partition size = "
-                  << cow_creator_ret->snapshot_status.cow_partition_size
-                  << ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size;
+                  << cow_creator_ret->snapshot_status.cow_partition_size()
+                  << ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size();
 
         // Delete any existing snapshot before re-creating one.
         if (!DeleteSnapshot(lock, target_partition->name())) {
@@ -1899,9 +1845,9 @@
 
         // It is possible that the whole partition uses free space in super, and snapshot / COW
         // would not be needed. In this case, skip the partition.
-        bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size > 0;
-        bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size +
-                          cow_creator_ret->snapshot_status.cow_file_size) > 0;
+        bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size() > 0;
+        bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size() +
+                          cow_creator_ret->snapshot_status.cow_file_size()) > 0;
         CHECK(needs_snapshot == needs_cow);
 
         if (!needs_snapshot) {
@@ -1911,17 +1857,17 @@
         }
 
         // Store these device sizes to snapshot status file.
-        if (!CreateSnapshot(lock, target_partition->name(), cow_creator_ret->snapshot_status)) {
+        if (!CreateSnapshot(lock, &cow_creator_ret->snapshot_status)) {
             return false;
         }
         created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
 
         // Create the COW partition. That is, use any remaining free space in super partition before
         // creating the COW images.
-        if (cow_creator_ret->snapshot_status.cow_partition_size > 0) {
-            CHECK(cow_creator_ret->snapshot_status.cow_partition_size % kSectorSize == 0)
+        if (cow_creator_ret->snapshot_status.cow_partition_size() > 0) {
+            CHECK(cow_creator_ret->snapshot_status.cow_partition_size() % kSectorSize == 0)
                     << "cow_partition_size == "
-                    << cow_creator_ret->snapshot_status.cow_partition_size
+                    << cow_creator_ret->snapshot_status.cow_partition_size()
                     << " is not a multiple of sector size " << kSectorSize;
             auto cow_partition = target_metadata->AddPartition(GetCowName(target_partition->name()),
                                                                kCowGroupName, 0 /* flags */);
@@ -1930,10 +1876,10 @@
             }
 
             if (!target_metadata->ResizePartition(
-                        cow_partition, cow_creator_ret->snapshot_status.cow_partition_size,
+                        cow_partition, cow_creator_ret->snapshot_status.cow_partition_size(),
                         cow_creator_ret->cow_partition_usable_regions)) {
                 LOG(ERROR) << "Cannot create COW partition on metadata with size "
-                           << cow_creator_ret->snapshot_status.cow_partition_size;
+                           << cow_creator_ret->snapshot_status.cow_partition_size();
                 return false;
             }
             // Only the in-memory target_metadata is modified; nothing to clean up if there is an
@@ -1941,7 +1887,7 @@
         }
 
         // Create the backing COW image if necessary.
-        if (cow_creator_ret->snapshot_status.cow_file_size > 0) {
+        if (cow_creator_ret->snapshot_status.cow_file_size() > 0) {
             if (!CreateCowImage(lock, target_partition->name())) {
                 return false;
             }
@@ -2049,13 +1995,13 @@
             ok = false;
             continue;
         }
-        ss << "    state: " << to_string(status.state) << std::endl;
-        ss << "    device size (bytes): " << status.device_size << std::endl;
-        ss << "    snapshot size (bytes): " << status.snapshot_size << std::endl;
-        ss << "    cow partition size (bytes): " << status.cow_partition_size << std::endl;
-        ss << "    cow file size (bytes): " << status.cow_file_size << std::endl;
-        ss << "    allocated sectors: " << status.sectors_allocated << std::endl;
-        ss << "    metadata sectors: " << status.metadata_sectors << std::endl;
+        ss << "    state: " << SnapshotState_Name(status.state()) << std::endl;
+        ss << "    device size (bytes): " << status.device_size() << std::endl;
+        ss << "    snapshot size (bytes): " << status.snapshot_size() << std::endl;
+        ss << "    cow partition size (bytes): " << status.cow_partition_size() << std::endl;
+        ss << "    cow file size (bytes): " << status.cow_file_size() << std::endl;
+        ss << "    allocated sectors: " << status.sectors_allocated() << std::endl;
+        ss << "    metadata sectors: " << status.metadata_sectors() << std::endl;
     }
     os << ss.rdbuf();
     return ok;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f3994c1..fd7754e 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -33,6 +33,7 @@
 #include <liblp/builder.h>
 #include <storage_literals/storage_literals.h>
 
+#include <android/snapshot/snapshot.pb.h>
 #include "test_helpers.h"
 #include "utility.h"
 
@@ -272,10 +273,12 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test-snapshot");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::vector<std::string> snapshots;
@@ -285,11 +288,11 @@
 
     // Scope so delete can re-acquire the snapshot file lock.
     {
-        SnapshotManager::SnapshotStatus status;
+        SnapshotStatus status;
         ASSERT_TRUE(sm->ReadSnapshotStatus(lock_.get(), "test-snapshot", &status));
-        ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
-        ASSERT_EQ(status.device_size, kDeviceSize);
-        ASSERT_EQ(status.snapshot_size, kDeviceSize);
+        ASSERT_EQ(status.state(), SnapshotState::CREATED);
+        ASSERT_EQ(status.device_size(), kDeviceSize);
+        ASSERT_EQ(status.snapshot_size(), kDeviceSize);
     }
 
     ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
@@ -301,10 +304,12 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test-snapshot");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::string base_device;
@@ -324,10 +329,12 @@
 
     static const uint64_t kSnapshotSize = 1024 * 1024;
     static const uint64_t kDeviceSize = 1024 * 1024 * 2;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kSnapshotSize,
-                                    .cow_file_size = kSnapshotSize}));
+    SnapshotStatus status;
+    status.set_name("test-snapshot");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kSnapshotSize);
+    status.set_cow_file_size(kSnapshotSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::string base_device;
@@ -377,10 +384,12 @@
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
     ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b-base", &base_device));
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test_partition_b");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test_partition_b"));
     ASSERT_TRUE(MapCowImage("test_partition_b", 10s, &cow_device));
     ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
@@ -436,10 +445,12 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test-snapshot");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::string base_device, cow_device, snap_device;
@@ -492,10 +503,12 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test_partition_b");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test_partition_b"));
 
     // Simulate a reboot into the new slot.
@@ -511,9 +524,8 @@
     ASSERT_TRUE(AcquireLock());
 
     // Validate that we have a snapshot device.
-    SnapshotManager::SnapshotStatus status;
     ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
-    ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
+    ASSERT_EQ(status.state(), SnapshotState::CREATED);
 
     DeviceMapper::TargetInfo target;
     auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
@@ -528,10 +540,12 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test_partition_b");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test_partition_b"));
 
     // Simulate a reboot into the new slot.
@@ -550,7 +564,6 @@
 
     ASSERT_TRUE(AcquireLock());
 
-    SnapshotManager::SnapshotStatus status;
     ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
 
     // We should not get a snapshot device now.
@@ -570,10 +583,12 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
-                                   {.device_size = kDeviceSize,
-                                    .snapshot_size = kDeviceSize,
-                                    .cow_file_size = kDeviceSize}));
+    SnapshotStatus status;
+    status.set_name("test_partition_b");
+    status.set_device_size(kDeviceSize);
+    status.set_snapshot_size(kDeviceSize);
+    status.set_cow_file_size(kDeviceSize);
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
     ASSERT_TRUE(CreateCowImage("test_partition_b"));
 
     // Simulate a reboot into the new slot.
@@ -699,11 +714,11 @@
         }
         auto local_lock = std::move(lock_);
 
-        SnapshotManager::SnapshotStatus status;
+        SnapshotStatus status;
         if (!sm->ReadSnapshotStatus(local_lock.get(), name, &status)) {
             return std::nullopt;
         }
-        return status.snapshot_size;
+        return status.snapshot_size();
     }
 
     AssertionResult UnmapAll() {
@@ -869,8 +884,9 @@
     {
         ASSERT_TRUE(AcquireLock());
         auto local_lock = std::move(lock_);
-        ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), "sys_b",
-                                            SnapshotManager::SnapshotStatus{}));
+        SnapshotStatus status;
+        status.set_name("sys_b");
+        ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), status));
         ASSERT_TRUE(image_manager_->CreateBackingImage("sys_b-cow-img", 1_MiB,
                                                        IImageManager::CREATE_IMAGE_DEFAULT));
     }
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index f445703..4226e95 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -38,6 +38,8 @@
 
 EMPTY=""
 SPACE=" "
+# Line up wrap to [  XXXXXXX ] messages.
+INDENT="             "
 # A _real_ embedded tab character
 TAB="`echo | tr '\n' '\t'`"
 # A _real_ embedded escape character
@@ -159,8 +161,7 @@
     return
   fi
   echo "${ORANGE}[  WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
-  echo "${L}" |
-    sed 's/^/             /' >&2
+  echo "${L}" | sed "s/^/${INDENT}/" >&2
 }
 
 [ "USAGE: get_property <prop>
@@ -639,10 +640,10 @@
 *}" ]; then
       echo "${prefix} expected \"${lval}\""
       echo "${prefix} got \"${rval}\"" |
-        sed ': again
+        sed ": again
              N
-             s/\(\n\)\([^ ]\)/\1             \2/
-             t again'
+             s/\(\n\)\([^ ]\)/\1${INDENT}\2/
+             t again"
       if [ -n "${*}" ] ; then
         echo "${prefix} ${*}"
       fi
@@ -657,10 +658,10 @@
       if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
         echo "${prefix} ok \"${lval}\""
         echo "       = \"${rval}\"" |
-          sed ': again
+          sed ": again
                N
-               s/\(\n\)\([^ ]\)/\1          \2/
-               t again'
+               s/\(\n\)\([^ ]\)/\1${INDENT}\2/
+               t again"
         if [ -n "${*}" ] ; then
           echo "${prefix} ${*}"
         fi
@@ -955,13 +956,24 @@
   echo "${GREEN}[ RUN      ]${NORMAL} Testing adb shell su root remount -R command" >&2
 
   avc_check
-  adb_su remount -R system </dev/null || true
+  T=`adb_date`
+  adb_su remount -R system </dev/null
+  err=${?}
+  if [ "${err}" != 0 ]; then
+    echo "${ORANGE}[  WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
+    T="-t ${T}"
+  else
+    # Rebooted, logcat will be meaningless, and last logcat will likely be clear
+    T=""
+  fi
   sleep 2
   adb_wait ${ADB_WAIT} ||
-    die "waiting for device after remount -R `usb_status`"
+    die "waiting for device after adb shell su root remount -R system `usb_status`"
   if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
        "2" = "`get_property partition.system.verified`" ]; then
-    die "remount -R command failed"
+    die ${T} "remount -R command failed
+${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
+${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
   fi
 
   echo "${GREEN}[       OK ]${NORMAL} adb shell su root remount -R command" >&2
@@ -1643,15 +1655,24 @@
 if ${overlayfs_supported}; then
   echo "${GREEN}[ RUN      ]${NORMAL} test 'adb remount -R'" >&2
   avc_check
-  adb_root &&
-    adb remount -R &&
-    adb_wait ${ADB_WAIT} ||
-    die "adb remount -R"
+  adb_root ||
+    die "adb root in preparation for adb remount -R"
+  T=`adb_date`
+  adb remount -R
+  err=${?}
+  if [ "${err}" != 0 ]; then
+    die -t ${T} "adb remount -R = ${err}"
+  fi
+  sleep 2
+  adb_wait ${ADB_WAIT} ||
+    die "waiting for device after adb remount -R `usb_status`"
   if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
        "2" = "`get_property partition.system.verified`" ] &&
      [ -n "`get_property ro.boot.verifiedbootstate`" -o \
        -n "`get_property partition.system.verified`" ]; then
-    die "remount -R command failed to disable verity"
+    die "remount -R command failed to disable verity
+${INDENT}ro.boot.verifiedbootstate=\"`get_property ro.boot.verifiedbootstate`\"
+${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
   fi
 
   echo "${GREEN}[       OK ]${NORMAL} 'adb remount -R' command" >&2
diff --git a/init/Android.mk b/init/Android.mk
index 62e452f..8fc44da 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
     libbacktrace \
     libmodprobe \
     libext2_uuid \
+    libprotobuf-cpp-lite \
     libsnapshot_nobinder \
 
 LOCAL_SANITIZE := signed-integer-overflow
diff --git a/init/service.cpp b/init/service.cpp
index 0b73dc5..a2db070 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -300,7 +300,7 @@
                     LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
                                << (boot_completed ? "in 4 minutes" : "before boot completed");
                     // Notifies update_verifier and apexd
-                    property_set("ro.init.updatable_crashing", "1");
+                    property_set("sys.init.updatable_crashing", "1");
                 }
             }
         } else {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index d0d83de..5fb11a5 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -161,7 +161,6 @@
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
-    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00550, AID_LOGD,      AID_LOGD,      0, "system/bin/logd" },
     { 00700, AID_ROOT,      AID_ROOT,      0, "system/bin/secilc" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
@@ -173,9 +172,10 @@
     { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
-    { 00440, AID_ROOT,      AID_ROOT,      0, "system/etc/recovery.img" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "vendor/bin/install-recovery.sh" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "vendor/build.prop" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "vendor/default.prop" },
+    { 00440, AID_ROOT,      AID_ROOT,      0, "vendor/etc/recovery.img" },
     { 00444, AID_ROOT,      AID_ROOT,      0, ven_conf_dir + 1 },
     { 00444, AID_ROOT,      AID_ROOT,      0, ven_conf_file + 1 },
 
diff --git a/libion/include/ion/ion.h b/libion/include/ion/ion.h
index a60d24e..1480bd9 100644
--- a/libion/include/ion/ion.h
+++ b/libion/include/ion/ion.h
@@ -49,6 +49,7 @@
 int ion_query_get_heaps(int fd, int cnt, void* buffers);
 
 int ion_is_legacy(int fd);
+int ion_is_using_modular_heaps(int fd);
 
 __END_DECLS
 
diff --git a/libion/ion.c b/libion/ion.c
index 1ecfc78..5141ea8 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -31,10 +31,12 @@
 #include <unistd.h>
 
 #include <ion/ion.h>
-#include "ion_4.12.h"
+#include "ion_4.19.h"
 
 #include <log/log.h>
 
+#define ION_ABI_VERSION_MODULAR_HEAPS 2
+
 enum ion_version { ION_VERSION_UNKNOWN, ION_VERSION_MODERN, ION_VERSION_LEGACY };
 
 static atomic_int g_ion_version = ATOMIC_VAR_INIT(ION_VERSION_UNKNOWN);
@@ -75,6 +77,14 @@
     return ret;
 }
 
+int ion_is_using_modular_heaps(int fd) {
+    int ion_abi_version = 0;
+    int ret = 0;
+
+    ret = ion_ioctl(fd, ION_IOC_ABI_VERSION, &ion_abi_version);
+    return (ret == 0 && ion_abi_version >= ION_ABI_VERSION_MODULAR_HEAPS);
+}
+
 int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags,
               ion_user_handle_t* handle) {
     int ret = 0;
diff --git a/libion/ion_4.19.h b/libion/ion_4.19.h
new file mode 100644
index 0000000..f5b59f1
--- /dev/null
+++ b/libion/ion_4.19.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_ION_NEW_H
+#define _UAPI_LINUX_ION_NEW_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
+enum ion_heap_type_ext {
+    ION_HEAP_TYPE_CUSTOM_EXT = 16,
+    ION_HEAP_TYPE_MAX = 31,
+};
+enum ion_heap_id {
+    ION_HEAP_SYSTEM = (1 << ION_HEAP_TYPE_SYSTEM),
+    ION_HEAP_SYSTEM_CONTIG = (ION_HEAP_SYSTEM << 1),
+    ION_HEAP_CARVEOUT_START = (ION_HEAP_SYSTEM_CONTIG << 1),
+    ION_HEAP_CARVEOUT_END = (ION_HEAP_CARVEOUT_START << 4),
+    ION_HEAP_CHUNK = (ION_HEAP_CARVEOUT_END << 1),
+    ION_HEAP_DMA_START = (ION_HEAP_CHUNK << 1),
+    ION_HEAP_DMA_END = (ION_HEAP_DMA_START << 7),
+    ION_HEAP_CUSTOM_START = (ION_HEAP_DMA_END << 1),
+    ION_HEAP_CUSTOM_END = (ION_HEAP_CUSTOM_START << 15),
+};
+#define ION_NUM_MAX_HEAPS (32)
+struct ion_new_allocation_data {
+    __u64 len;
+    __u32 heap_id_mask;
+    __u32 flags;
+    __u32 fd;
+    __u32 unused;
+};
+#define MAX_HEAP_NAME 32
+struct ion_heap_data {
+    char name[MAX_HEAP_NAME];
+    __u32 type;
+    __u32 heap_id;
+    __u32 reserved0;
+    __u32 reserved1;
+    __u32 reserved2;
+};
+struct ion_heap_query {
+    __u32 cnt;
+    __u32 reserved0;
+    __u64 heaps;
+    __u32 reserved1;
+    __u32 reserved2;
+};
+#define ION_IOC_MAGIC 'I'
+#define ION_IOC_NEW_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_new_allocation_data)
+#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query)
+#define ION_IOC_ABI_VERSION _IOR(ION_IOC_MAGIC, 9, __u32)
+#endif
diff --git a/libion/original-kernel-headers/linux/ion_4.19.h b/libion/original-kernel-headers/linux/ion_4.19.h
new file mode 100644
index 0000000..75fef39
--- /dev/null
+++ b/libion/original-kernel-headers/linux/ion_4.19.h
@@ -0,0 +1,170 @@
+/*
+ * Adapted from drivers/staging/android/uapi/ion.h
+ *
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_ION_NEW_H
+#define _UAPI_LINUX_ION_NEW_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
+
+enum ion_heap_type_ext {
+    ION_HEAP_TYPE_CUSTOM_EXT = 16,
+    ION_HEAP_TYPE_MAX = 31,
+};
+
+/**
+ * ion_heap_id - list of standard heap ids that Android can use
+ *
+ * @ION_HEAP_SYSTEM		Id for the ION_HEAP_TYPE_SYSTEM
+ * @ION_HEAP_SYSTEM_CONTIG	Id for the ION_HEAP_TYPE_SYSTEM_CONTIG
+ * @ION_HEAP_CHUNK		Id for the ION_HEAP_TYPE_CHUNK
+ * @ION_HEAP_CARVEOUT_START	Start of reserved id range for heaps of type
+ *				ION_HEAP_TYPE_CARVEOUT
+ * @ION_HEAP_CARVEOUT_END	End of reserved id range for heaps of type
+ *				ION_HEAP_TYPE_CARVEOUT
+ * @ION_HEAP_DMA_START 		Start of reserved id range for heaps of type
+ *				ION_HEAP_TYPE_DMA
+ * @ION_HEAP_DMA_END		End of reserved id range for heaps of type
+ *				ION_HEAP_TYPE_DMA
+ * @ION_HEAP_CUSTOM_START	Start of reserved id range for heaps of custom
+ *				type
+ * @ION_HEAP_CUSTOM_END		End of reserved id range for heaps of custom
+ *				type
+ */
+enum ion_heap_id {
+    ION_HEAP_SYSTEM = (1 << ION_HEAP_TYPE_SYSTEM),
+    ION_HEAP_SYSTEM_CONTIG = (ION_HEAP_SYSTEM << 1),
+    ION_HEAP_CARVEOUT_START = (ION_HEAP_SYSTEM_CONTIG << 1),
+    ION_HEAP_CARVEOUT_END = (ION_HEAP_CARVEOUT_START << 4),
+    ION_HEAP_CHUNK = (ION_HEAP_CARVEOUT_END << 1),
+    ION_HEAP_DMA_START = (ION_HEAP_CHUNK << 1),
+    ION_HEAP_DMA_END = (ION_HEAP_DMA_START << 7),
+    ION_HEAP_CUSTOM_START = (ION_HEAP_DMA_END << 1),
+    ION_HEAP_CUSTOM_END = (ION_HEAP_CUSTOM_START << 15),
+};
+
+#define ION_NUM_MAX_HEAPS (32)
+
+/**
+ * DOC: Ion Userspace API
+ *
+ * create a client by opening /dev/ion
+ * most operations handled via following ioctls
+ *
+ */
+
+/**
+ * struct ion_new_allocation_data - metadata passed from userspace for allocations
+ * @len:		size of the allocation
+ * @heap_id_mask:	mask of heap ids to allocate from
+ * @flags:		flags passed to heap
+ * @handle:		pointer that will be populated with a cookie to use to
+ *			refer to this allocation
+ *
+ * Provided by userspace as an argument to the ioctl - added _new to denote
+ * this belongs to the new ION interface.
+ */
+struct ion_new_allocation_data {
+    __u64 len;
+    __u32 heap_id_mask;
+    __u32 flags;
+    __u32 fd;
+    __u32 unused;
+};
+
+#define MAX_HEAP_NAME 32
+
+/**
+ * struct ion_heap_data - data about a heap
+ * @name - first 32 characters of the heap name
+ * @type - heap type
+ * @heap_id - heap id for the heap
+ */
+struct ion_heap_data {
+    char name[MAX_HEAP_NAME];
+    __u32 type;
+    __u32 heap_id;
+    __u32 reserved0;
+    __u32 reserved1;
+    __u32 reserved2;
+};
+
+/**
+ * struct ion_heap_query - collection of data about all heaps
+ * @cnt - total number of heaps to be copied
+ * @heaps - buffer to copy heap data
+ */
+struct ion_heap_query {
+    __u32 cnt;       /* Total number of heaps to be copied */
+    __u32 reserved0; /* align to 64bits */
+    __u64 heaps;     /* buffer to be populated */
+    __u32 reserved1;
+    __u32 reserved2;
+};
+
+#define ION_IOC_MAGIC 'I'
+
+/**
+ * DOC: ION_IOC_NEW_ALLOC - allocate memory
+ *
+ * Takes an ion_allocation_data struct and returns it with the handle field
+ * populated with the opaque handle for the allocation.
+ * TODO: This IOCTL will clash by design; however, only one of
+ *  ION_IOC_ALLOC or ION_IOC_NEW_ALLOC paths will be exercised,
+ *  so this should not conflict.
+ */
+#define ION_IOC_NEW_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_new_allocation_data)
+
+/**
+ * DOC: ION_IOC_FREE - free memory
+ *
+ * Takes an ion_handle_data struct and frees the handle.
+ *
+ * #define ION_IOC_FREE		_IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
+ * This will come from the older kernels, so don't redefine here
+ */
+
+/**
+ * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
+ *
+ * Takes an ion_fd_data struct with the handle field populated with a valid
+ * opaque handle.  Returns the struct with the fd field set to a file
+ * descriptor open in the current address space.  This file descriptor
+ * can then be passed to another process.  The corresponding opaque handle can
+ * be retrieved via ION_IOC_IMPORT.
+ *
+ * #define ION_IOC_SHARE		_IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+ * This will come from the older kernels, so don't redefine here
+ */
+
+/**
+ * DOC: ION_IOC_HEAP_QUERY - information about available heaps
+ *
+ * Takes an ion_heap_query structure and populates information about
+ * available Ion heaps.
+ */
+#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query)
+
+/**
+ * DOC: ION_IOC_HEAP_ABI_VERSION - return ABI version
+ *
+ * Returns ABI version for this driver
+ */
+#define ION_IOC_ABI_VERSION _IOR(ION_IOC_MAGIC, 9, __u32)
+
+#endif /* _UAPI_LINUX_ION_NEW_H */
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
index 5600702..989e029 100644
--- a/libion/tests/Android.bp
+++ b/libion/tests/Android.bp
@@ -29,5 +29,6 @@
         "invalid_values_test.cpp",
         "ion_test_fixture.cpp",
         "map_test.cpp",
+        "modular_heap_check.cpp",
     ],
 }
diff --git a/libion/tests/modular_heap_check.cpp b/libion/tests/modular_heap_check.cpp
new file mode 100644
index 0000000..5505c5a
--- /dev/null
+++ b/libion/tests/modular_heap_check.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <ion/ion.h>
+#include "ion_test_fixture.h"
+
+class ModularHeapCheck : public IonTest {};
+
+TEST_F(ModularHeapCheck, ModularHeapCheckSimple) {
+    if (ion_is_using_modular_heaps(ionfd)) {
+        std::cout << "Heaps are modular." << std::endl;
+    } else {
+        std::cout << "Heaps are built-in." << std::endl;
+    }
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index c8f0a8b..a705071 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -236,12 +236,10 @@
 ifeq ($(_enforce_vndk_at_runtime),true)
 
 # for VNDK enforced devices
-LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
-include $(BUILD_SYSTEM)/base_rules.mk
-ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
-check_backward_compatibility := true
-vndk_version := $(PLATFORM_VNDK_VERSION)
-include $(LOCAL_PATH)/update_and_install_ld_config.mk
+# This file will be replaced with dynamically generated one from system/linkerconfig
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+LOCAL_SRC_FILES := etc/ld.config.txt
+include $(BUILD_PREBUILT)
 
 else ifeq ($(_enforce_vndk_lite_at_runtime),true)
 
@@ -277,7 +275,6 @@
 LOCAL_MODULE_STEM := $$(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
 ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
-check_backward_compatibility := true
 vndk_version := $(1)
 lib_list_from_prebuilts := true
 include $(LOCAL_PATH)/update_and_install_ld_config.mk
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 60035aa..5c87843 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -1,803 +1,3 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-dir.system = /%SYSTEM_EXT%/bin/
-dir.system = /%PRODUCT%/bin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.unrestricted = /data/nativetest/unrestricted
-dir.unrestricted = /data/nativetest64/unrestricted
-
-# TODO(b/123864775): Ensure tests are run from /data/nativetest{,64} or (if
-# necessary) the unrestricted subdirs above. Then clean this up.
-dir.unrestricted = /data/local/tmp
-
-dir.postinstall = /postinstall
-
-# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
-# This must be last.
-dir.system = /data
-
-[system]
-additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. Libs from /vendor partition
-# can't be loaded in this namespace.
-###############################################################################
-namespace.default.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
-
-# We can't have entire /system/${LIB} as permitted paths because doing so
-# makes it possible to load libs in /system/${LIB}/vndk* directories by
-# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
-# VNDK libs are built with previous versions of Android and thus must not be
-# loaded into this namespace where libs built with the current version of
-# Android are loaded. Mixing the two types of libs in the same namespace can
-# cause unexpected problem.
-namespace.default.permitted.paths  = /system/${LIB}/drm
-namespace.default.permitted.paths += /system/${LIB}/extractors
-namespace.default.permitted.paths += /system/${LIB}/hw
-namespace.default.permitted.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.permitted.paths += /%PRODUCT%/${LIB}
-# These are where odex files are located. libart has to be able to dlopen the files
-namespace.default.permitted.paths += /system/framework
-namespace.default.permitted.paths += /system/app
-namespace.default.permitted.paths += /system/priv-app
-namespace.default.permitted.paths += /%SYSTEM_EXT%/framework
-namespace.default.permitted.paths += /%SYSTEM_EXT%/app
-namespace.default.permitted.paths += /%SYSTEM_EXT%/priv-app
-namespace.default.permitted.paths += /vendor/framework
-namespace.default.permitted.paths += /vendor/app
-namespace.default.permitted.paths += /vendor/priv-app
-namespace.default.permitted.paths += /system/vendor/framework
-namespace.default.permitted.paths += /system/vendor/app
-namespace.default.permitted.paths += /system/vendor/priv-app
-namespace.default.permitted.paths += /odm/framework
-namespace.default.permitted.paths += /odm/app
-namespace.default.permitted.paths += /odm/priv-app
-namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /%PRODUCT%/framework
-namespace.default.permitted.paths += /%PRODUCT%/app
-namespace.default.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.permitted.paths += /data
-namespace.default.permitted.paths += /mnt/expand
-namespace.default.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
-namespace.default.permitted.paths += /system/${LIB}/bootstrap
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-
-namespace.default.asan.permitted.paths  = /data
-namespace.default.asan.permitted.paths += /system/${LIB}/drm
-namespace.default.asan.permitted.paths += /system/${LIB}/extractors
-namespace.default.asan.permitted.paths += /system/${LIB}/hw
-namespace.default.asan.permitted.paths += /system/framework
-namespace.default.asan.permitted.paths += /system/app
-namespace.default.asan.permitted.paths += /system/priv-app
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/framework
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/app
-namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/priv-app
-namespace.default.asan.permitted.paths += /vendor/framework
-namespace.default.asan.permitted.paths += /vendor/app
-namespace.default.asan.permitted.paths += /vendor/priv-app
-namespace.default.asan.permitted.paths += /system/vendor/framework
-namespace.default.asan.permitted.paths += /system/vendor/app
-namespace.default.asan.permitted.paths += /system/vendor/priv-app
-namespace.default.asan.permitted.paths += /odm/framework
-namespace.default.asan.permitted.paths += /odm/app
-namespace.default.asan.permitted.paths += /odm/priv-app
-namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /%PRODUCT%/${LIB}
-namespace.default.asan.permitted.paths += /%PRODUCT%/framework
-namespace.default.asan.permitted.paths += /%PRODUCT%/app
-namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.asan.permitted.paths += /mnt/expand
-namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
-namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-# If a shared library or an executable requests a shared library that
-# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the runtime namespace. And then, if the
-# shared library cannot be loaded from the runtime namespace either, the
-# dynamic linker tries to load the shared library from the resolv namespace.
-# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs  = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.so
-namespace.default.link.runtime.shared_libs += libnativebridge.so
-namespace.default.link.runtime.shared_libs += libnativehelper.so
-namespace.default.link.runtime.shared_libs += libnativeloader.so
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
-namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# When libnetd_resolv.so can't be found in the default namespace, search for it
-# in the resolv namespace. Don't allow any other libraries from the resolv namespace
-# to be loaded in the default namespace.
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
-# Need allow_all_shared_libs because libart.so can dlopen oat files in
-# /system/framework and /data.
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libcgrouprc.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
-namespace.conscrypt.link.default.shared_libs  = libc.so
-namespace.conscrypt.link.default.shared_libs += libm.so
-namespace.conscrypt.link.default.shared_libs += libdl.so
-namespace.conscrypt.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs  = libc.so
-namespace.resolv.link.default.shared_libs += libcgrouprc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-namespace.resolv.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths  = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}/hw
-
-namespace.sphal.permitted.paths  = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-namespace.sphal.permitted.paths += /system/vendor/${LIB}
-
-namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths +=           /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths +=           /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths +=           /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths +=           /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used. Order is important here as the namespaces are
-# tried in this order. rs should be before vndk because both are capable
-# of loading libRS_internal.so
-namespace.sphal.links = rs,default,vndk,neuralnetworks
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-namespace.sphal.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.sphal.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths  = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths  = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /system/vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths +=           /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths +=           /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths +=           /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,neuralnetworks
-
-namespace.rs.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
-# namespace because RS framework libs are using them.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.rs.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths  = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths  = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-namespace.vndk.permitted.paths += /system/vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /system/vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths  = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/egl
-
-namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
-namespace.vndk.asan.permitted.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-# The "vndk" namespace links to "default" namespace for LLNDK libs and links to
-# "sphal" namespace for vendor libs.  The ordering matters.  The "default"
-# namespace has higher priority than the "sphal" namespace.
-namespace.vndk.links = default,sphal,runtime,neuralnetworks
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the default namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-# Allow VNDK-SP extensions to use vendor libraries
-namespace.vndk.link.sphal.allow_all_shared_libs = true
-
-# LLNDK library moved into apex
-namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# Namespace config for vendor processes. In O, no restriction is enforced for
-# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = runtime,system,neuralnetworks,vndk%VNDK_IN_SYSTEM_NS%
-
-###############################################################################
-# "default" namespace
-#
-# This is the default linker namespace for a vendor process (a process started
-# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
-# are loaded directly into this namespace. However, other libs under the system
-# partition (VNDK and LLNDK libraries) are not loaded here but from the
-# separate namespace 'system'. The delegation to the system namespace is done
-# via the 'namespace.default.link.system.shared_libs' property below.
-#
-# '#VNDK27#' TAG is only for building ld.config.27.txt for backward
-# compatibility. (TODO:b/123390078) Move them to a separate file.
-###############################################################################
-namespace.default.isolated = true
-namespace.default.visible = true
-
-namespace.default.search.paths  = /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.permitted.paths  = /odm
-namespace.default.permitted.paths += /vendor
-namespace.default.permitted.paths += /system/vendor
-#VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
-#VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
-
-namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/hw
-#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/hw
-#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/egl
-#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/egl
-
-namespace.default.asan.permitted.paths  = /data/asan/odm
-namespace.default.asan.permitted.paths +=           /odm
-namespace.default.asan.permitted.paths += /data/asan/vendor
-namespace.default.asan.permitted.paths +=           /vendor
-
-namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
-namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.system.shared_libs  = %LLNDK_LIBRARIES%
-namespace.default.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = system
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.system.allow_all_shared_libs = true
-
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is where VNDK and VNDK-SP libraries are loaded for
-# a vendor process.
-###############################################################################
-namespace.vndk.isolated = false
-
-namespace.vndk.search.paths  = /odm/${LIB}/vndk
-namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the system namespace. This is possible since their ABI is stable across
-# Android releases.  The links here should be identical to that of the
-# 'vndk_in_system' namespace, except for the link between 'vndk' and
-# 'vndk_in_system'.
-namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
-
-namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.default.allow_all_shared_libs = true
-
-namespace.vndk.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "system" namespace
-#
-# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
-# a vendor process.
-###############################################################################
-namespace.system.isolated = false
-
-namespace.system.search.paths  = /system/${LIB}
-namespace.system.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.system.search.paths += /%PRODUCT%/${LIB}
-
-namespace.system.asan.search.paths  = /data/asan/system/${LIB}
-namespace.system.asan.search.paths +=           /system/${LIB}
-namespace.system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.system.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
-namespace.system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.system.asan.search.paths +=           /%PRODUCT%/${LIB}
-
-namespace.system.links = runtime
-namespace.system.link.runtime.shared_libs  = libdexfile_external.so
-namespace.system.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.system.link.runtime.shared_libs += libicui18n.so
-namespace.system.link.runtime.shared_libs += libicuuc.so
-namespace.system.link.runtime.shared_libs += libnativebridge.so
-namespace.system.link.runtime.shared_libs += libnativehelper.so
-namespace.system.link.runtime.shared_libs += libnativeloader.so
-# Workaround for b/124772622
-namespace.system.link.runtime.shared_libs += libandroidicu.so
-namespace.system.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "vndk_in_system" namespace
-#
-# This namespace is where no-vendor-variant VNDK libraries are loaded for a
-# vendor process.  Note that we do not simply export these libraries from
-# "system" namespace, because in some case both the core variant and the
-# vendor variant of a VNDK library may be loaded.  In such case, we do not
-# want to eliminate double-loading because doing so means the global states
-# of the library would be shared.
-#
-# Only the no-vendor-variant VNDK libraries are whitelisted in this namespace.
-# This is to ensure that we do not load libraries needed by no-vendor-variant
-# VNDK libraries into vndk_in_system namespace.
-###############################################################################
-namespace.vndk_in_system.isolated = true
-namespace.vndk_in_system.visible = true
-
-# The search paths here should be kept the same as that of the 'system'
-# namespace.
-namespace.vndk_in_system.search.paths  = /system/${LIB}
-namespace.vndk_in_system.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
-
-namespace.vndk_in_system.asan.search.paths  = /data/asan/system/${LIB}
-namespace.vndk_in_system.asan.search.paths +=           /system/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT%/${LIB}
-
-namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
-
-# The links here should be identical to that of the 'vndk' namespace, with the
-# following exception:
-#   1. 'vndk_in_system' needs to be freely linked back to 'vndk'.
-#   2. 'vndk_in_system' does not need to link to 'default', as any library that
-#      requires anything vendor would not be a vndk_in_system library.
-namespace.vndk_in_system.links = vndk,system,runtime,neuralnetworks
-namespace.vndk_in_system.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk_in_system.link.system.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk_in_system.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk_in_system.link.vndk.allow_all_shared_libs = true
-namespace.vndk_in_system.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = system
-namespace.neuralnetworks.link.system.shared_libs  = libc.so
-namespace.neuralnetworks.link.system.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.system.shared_libs += libdl.so
-namespace.neuralnetworks.link.system.shared_libs += liblog.so
-namespace.neuralnetworks.link.system.shared_libs += libm.so
-namespace.neuralnetworks.link.system.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.system.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.system.shared_libs += libsync.so
-namespace.neuralnetworks.link.system.shared_libs += libvndksupport.so
-
-###############################################################################
-# Namespace config for native tests that need access to both system and vendor
-# libraries. This replicates the default linker config (done by
-# init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
-# includes the requisite namespace setup for APEXes.
-###############################################################################
-[unrestricted]
-additional.namespaces = runtime,media,conscrypt,resolv,neuralnetworks
-
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = runtime,resolv,neuralnetworks
-namespace.default.link.runtime.shared_libs  = libandroidicu.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
-namespace.default.link.runtime.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.runtime.shared_libs += libicui18n.so
-namespace.default.link.runtime.shared_libs += libicuuc.so
-namespace.default.link.runtime.shared_libs += libnativebridge.so
-namespace.default.link.runtime.shared_libs += libnativehelper.so
-namespace.default.link.runtime.shared_libs += libnativeloader.so
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.runtime.shared_libs += libpac.so
-namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "runtime" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the Runtime APEX.
-# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-# TODO(b/139408016): Rename this namespace to "art".
-namespace.runtime.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.runtime.visible = true
-
-namespace.runtime.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
-namespace.conscrypt.link.default.shared_libs  = libc.so
-namespace.conscrypt.link.default.shared_libs += libm.so
-namespace.conscrypt.link.default.shared_libs += libdl.so
-namespace.conscrypt.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs  = libc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# Namespace config for binaries under /postinstall.
-# Only default namespace is defined and default has no directories
-# other than /system/lib in the search paths. This is because linker calls
-# realpath on the search paths and this causes selinux denial if the paths
-# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
-# reason to allow the binaries to access the paths.
-###############################################################################
-[postinstall]
-namespace.default.isolated = false
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
+# This file is no longer in use.
+# Please update linker configuration generator instead.
+# You can find the code from /system/linkerconfig
\ No newline at end of file
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index b9b95a6..7c8b3e7 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -108,12 +108,13 @@
 
 namespace.runtime.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.runtime.links = default
+namespace.runtime.links = default,neuralnetworks
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
 namespace.runtime.link.default.allow_all_shared_libs = true
+namespace.runtime.link.neuralnetworks.shared_libs = libneuralnetworks.so
 
 ###############################################################################
 # "media" APEX namespace
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bad0642..3b64b82 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -917,7 +917,3 @@
 
 on init && property:ro.debuggable=1
     start console
-
-service flash_recovery /system/bin/install-recovery.sh
-    class main
-    oneshot