Merge "fastbootd: copy AVB footer on boot image to end of block device" into rvc-dev
diff --git a/adb/Android.bp b/adb/Android.bp
index 0394bf6..cb5c1df 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -679,6 +679,8 @@
         "mdns_test.cpp",
     ],
 
+    test_config: "adb_test.xml",
+
     shared_libs: [
         "liblog",
     ],
diff --git a/adb/adb_test.xml b/adb/adb_test.xml
new file mode 100644
index 0000000..cc3302d
--- /dev/null
+++ b/adb/adb_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs adbd_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="adbd_test->/data/local/tmp/adbd_test" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="adbd_test" />
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+      <option name="mainline-module-package-name" value="com.google.android.adbd" />
+    </object>
+</configuration>
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 092a866..610e985 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -155,6 +155,14 @@
     *buf = '\0';
 }
 
+static unique_fd send_command(const std::vector<std::string>& cmd_args, std::string* error) {
+    if (is_abb_exec_supported()) {
+        return send_abb_exec_command(cmd_args, error);
+    } else {
+        return unique_fd(adb_connect(android::base::Join(cmd_args, " "), error));
+    }
+}
+
 static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy) {
     printf("Performing Streamed Install\n");
 
@@ -227,12 +235,7 @@
         cmd_args.push_back("--apex");
     }
 
-    unique_fd remote_fd;
-    if (use_abb_exec) {
-        remote_fd = send_abb_exec_command(cmd_args, &error);
-    } else {
-        remote_fd.reset(adb_connect(android::base::Join(cmd_args, " "), &error));
-    }
+    unique_fd remote_fd = send_command(cmd_args, &error);
     if (remote_fd < 0) {
         fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
         return 1;
@@ -308,7 +311,7 @@
     const auto start = clock::now();
     int first_apk = -1;
     int last_apk = -1;
-    std::vector<std::string_view> args = {"package"sv};
+    incremental::Args passthrough_args = {};
     for (int i = 0; i < argc; ++i) {
         const auto arg = std::string_view(argv[i]);
         if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
@@ -316,12 +319,11 @@
             if (first_apk == -1) {
                 first_apk = i;
             }
-        } else if (arg.starts_with("install-"sv)) {
+        } else if (arg.starts_with("install"sv)) {
             // incremental installation command on the device is the same for all its variations in
             // the adb, e.g. install-multiple or install-multi-package
-            args.push_back("install"sv);
         } else {
-            args.push_back(arg);
+            passthrough_args.push_back(arg);
         }
     }
 
@@ -342,7 +344,7 @@
     }
 
     printf("Performing Incremental Install\n");
-    auto server_process = incremental::install(files, silent);
+    auto server_process = incremental::install(files, passthrough_args, silent);
     if (!server_process) {
         return -1;
     }
@@ -548,24 +550,28 @@
 
     if (first_apk == -1) error_exit("need APK file on command line");
 
-    std::string install_cmd;
-    if (best_install_mode() == INSTALL_PUSH) {
-        install_cmd = "exec:pm";
-    } else {
-        install_cmd = "exec:cmd package";
-    }
+    const bool use_abb_exec = is_abb_exec_supported();
 
-    std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64,
-                                                  install_cmd.c_str(), total_size);
+    const std::string install_cmd =
+            use_abb_exec ? "package"
+                         : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package";
+
+    std::vector<std::string> cmd_args = {install_cmd, "install-create", "-S",
+                                         std::to_string(total_size)};
+    cmd_args.reserve(first_apk + 4);
     for (int i = 1; i < first_apk; i++) {
-        cmd += " " + escape_arg(argv[i]);
+        if (use_abb_exec) {
+            cmd_args.push_back(argv[i]);
+        } else {
+            cmd_args.push_back(escape_arg(argv[i]));
+        }
     }
 
     // Create install session
     std::string error;
     char buf[BUFSIZ];
     {
-        unique_fd fd(adb_connect(cmd, &error));
+        unique_fd fd = send_command(cmd_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
             return EXIT_FAILURE;
@@ -587,6 +593,7 @@
         fputs(buf, stderr);
         return EXIT_FAILURE;
     }
+    const auto session_id_str = std::to_string(session_id);
 
     // Valid session, now stream the APKs
     bool success = true;
@@ -599,10 +606,15 @@
             goto finalize_session;
         }
 
-        std::string cmd =
-                android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %s -",
-                                            install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
-                                            session_id, android::base::Basename(file).c_str());
+        std::vector<std::string> cmd_args = {
+                install_cmd,
+                "install-write",
+                "-S",
+                std::to_string(sb.st_size),
+                session_id_str,
+                android::base::Basename(file),
+                "-",
+        };
 
         unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
         if (local_fd < 0) {
@@ -612,7 +624,7 @@
         }
 
         std::string error;
-        unique_fd remote_fd(adb_connect(cmd, &error));
+        unique_fd remote_fd = send_command(cmd_args, &error);
         if (remote_fd < 0) {
             fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
             success = false;
@@ -637,10 +649,13 @@
 
 finalize_session:
     // Commit session if we streamed everything okay; otherwise abandon.
-    std::string service = android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
-                                                      success ? "commit" : "abandon", session_id);
+    std::vector<std::string> service_args = {
+            install_cmd,
+            success ? "install-commit" : "install-abandon",
+            session_id_str,
+    };
     {
-        unique_fd fd(adb_connect(service, &error));
+        unique_fd fd = send_command(service_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             return EXIT_FAILURE;
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index f56ef9a..c8f69c3 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -93,12 +93,10 @@
 
 // Send install-incremental to the device along with properly configured file descriptors in
 // streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, bool silent) {
+static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
     std::vector<std::string> command_args{"package", "install-incremental"};
+    command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
 
-    // fd's with positions at the beginning of fs-verity
-    std::vector<unique_fd> signature_fds;
-    signature_fds.reserve(files.size());
     for (int i = 0, size = files.size(); i < size; ++i) {
         const auto& file = files[i];
 
@@ -118,8 +116,6 @@
         auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
                                       (long long)st.st_size, i, signature.c_str());
         command_args.push_back(std::move(file_desc));
-
-        signature_fds.push_back(std::move(signature_fd));
     }
 
     std::string error;
@@ -150,8 +146,8 @@
     return true;
 }
 
-std::optional<Process> install(const Files& files, bool silent) {
-    auto connection_fd = start_install(files, silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
+    auto connection_fd = start_install(files, passthrough_args, silent);
     if (connection_fd < 0) {
         if (!silent) {
             fprintf(stderr, "adb: failed to initiate installation on device.\n");
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 1fb1e0b..40e928a 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -26,9 +26,10 @@
 namespace incremental {
 
 using Files = std::vector<std::string>;
+using Args = std::vector<std::string_view>;
 
 bool can_install(const Files& files);
-std::optional<Process> install(const Files& files, bool silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent);
 
 enum class Result { Success, Failure, None };
 Result wait_for_installation(int read_fd);
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b8eee4a..2553353 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -625,7 +625,7 @@
         if (!sm) {
             return device->WriteFail("Unable to create SnapshotManager");
         }
-        if (!sm->HandleImminentDataWipe()) {
+        if (!sm->FinishMergeInRecovery()) {
             return device->WriteFail("Unable to finish snapshot merge");
         }
     } else {
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 5388b44..6663391 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -131,132 +131,6 @@
     ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
 }
 
-// This fixture is for tests against a simulated device environment. Rather
-// than use /data, we create an image and then layer a new filesystem within
-// it. Each test then decides how to mount and create layered images. This
-// allows us to test FBE vs FDE configurations.
-class ImageTest : public ::testing::Test {
-  public:
-    ImageTest() : dm_(DeviceMapper::Instance()) {}
-
-    void SetUp() override {
-        manager_ = ImageManager::Open(kMetadataPath, gDataPath);
-        ASSERT_NE(manager_, nullptr);
-
-        manager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
-        submanager_ = ImageManager::Open(kMetadataPath + "/mnt"s, gDataPath + "/mnt"s);
-        ASSERT_NE(submanager_, nullptr);
-
-        submanager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
-        // Ensure that metadata is cleared in between runs.
-        submanager_->RemoveAllImages();
-        manager_->RemoveAllImages();
-
-        const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
-        base_name_ = tinfo->name();
-        test_image_name_ = base_name_ + "-base";
-        wrapper_device_name_ = base_name_ + "-wrapper";
-
-        ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize * 16, false, nullptr));
-        ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &base_device_));
-    }
-
-    void TearDown() override {
-        submanager_->UnmapImageDevice(test_image_name_);
-        umount(gDataMountPath.c_str());
-        dm_.DeleteDeviceIfExists(wrapper_device_name_);
-        manager_->UnmapImageDevice(base_name_);
-        manager_->DeleteBackingImage(base_name_);
-    }
-
-  protected:
-    bool DoFormat(const std::string& device) {
-        // clang-format off
-        std::vector<std::string> mkfs_args = {
-            "/system/bin/mke2fs",
-            "-F",
-            "-b 4096",
-            "-t ext4",
-            "-m 0",
-            "-O has_journal",
-            device,
-            ">/dev/null",
-            "2>/dev/null",
-            "</dev/null",
-        };
-        // clang-format on
-        auto command = android::base::Join(mkfs_args, " ");
-        return system(command.c_str()) == 0;
-    }
-
-    std::unique_ptr<ImageManager> manager_;
-    std::unique_ptr<ImageManager> submanager_;
-
-    DeviceMapper& dm_;
-    std::string base_name_;
-    std::string base_device_;
-    std::string test_image_name_;
-    std::string wrapper_device_name_;
-};
-
-TEST_F(ImageTest, DirectMount) {
-    ASSERT_TRUE(DoFormat(base_device_));
-    ASSERT_EQ(mount(base_device_.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
-    ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
-    std::string path;
-    ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
-    ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/loop"));
-}
-
-TEST_F(ImageTest, IndirectMount) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
-    GTEST_SKIP() << "WIP failure b/148874852";
-#endif
-    // Create a simple wrapper around the base device that we'll mount from
-    // instead. This will simulate the code paths for dm-crypt/default-key/bow
-    // and force us to use device-mapper rather than loop devices.
-    uint64_t device_size = 0;
-    {
-        unique_fd fd(open(base_device_.c_str(), O_RDWR | O_CLOEXEC));
-        ASSERT_GE(fd, 0);
-        device_size = get_block_device_size(fd);
-        ASSERT_EQ(device_size, kTestImageSize * 16);
-    }
-    uint64_t num_sectors = device_size / 512;
-
-    auto& dm = DeviceMapper::Instance();
-
-    DmTable table;
-    table.Emplace<DmTargetLinear>(0, num_sectors, base_device_, 0);
-    ASSERT_TRUE(dm.CreateDevice(wrapper_device_name_, table));
-
-    // Format and mount.
-    std::string wrapper_device;
-    ASSERT_TRUE(dm.GetDmDevicePathByName(wrapper_device_name_, &wrapper_device));
-    ASSERT_TRUE(WaitForFile(wrapper_device, 5s));
-    ASSERT_TRUE(DoFormat(wrapper_device));
-    ASSERT_EQ(mount(wrapper_device.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
-
-    ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
-    std::set<std::string> backing_devices;
-    auto init = [&](std::set<std::string> devices) -> bool {
-        backing_devices = std::move(devices);
-        return true;
-    };
-
-    std::string path;
-    ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
-    ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/dm-"));
-    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
-    ASSERT_TRUE(submanager_->MapAllImages(init));
-    ASSERT_FALSE(backing_devices.empty());
-    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
-}
-
 bool Mkdir(const std::string& path) {
     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
         std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1daa83b..ac8a25e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -223,6 +223,10 @@
     // optional callback fires periodically to query progress via GetUpdateState.
     bool HandleImminentDataWipe(const std::function<void()>& callback = {});
 
+    // Force a merge to complete in recovery. This is similar to HandleImminentDataWipe
+    // but does not expect a data wipe after.
+    bool FinishMergeInRecovery();
+
     // This method is only allowed in recovery and is used as a helper to
     // initialize the snapshot devices as a requirement to mount a snapshotted
     // /system in recovery.
@@ -536,11 +540,16 @@
     bool ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
                                       const std::function<bool()>& callback);
 
+    // Return device string of a mapped image, or if it is not available, the mapped image path.
+    bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
+                                          std::string* device_string_or_mapped_path);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
     std::unique_ptr<IImageManager> images_;
     bool has_local_image_manager_ = false;
+    bool in_factory_data_reset_ = false;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c9fa28e..d4a3f62 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -577,8 +577,16 @@
         return false;
     }
 
+    auto other_suffix = device_->GetOtherSlotSuffix();
+
     auto& dm = DeviceMapper::Instance();
     for (const auto& snapshot : snapshots) {
+        if (android::base::EndsWith(snapshot, other_suffix)) {
+            // Allow the merge to continue, but log this unexpected case.
+            LOG(ERROR) << "Unexpected snapshot found during merge: " << snapshot;
+            continue;
+        }
+
         // The device has to be mapped, since everything should be merged at
         // the same time. This is a fairly serious error. We could forcefully
         // map everything here, but it should have been mapped during first-
@@ -1008,6 +1016,15 @@
 }
 
 void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
+    // It's not possible to remove update state in recovery, so write an
+    // indicator that cleanup is needed on reboot. If a factory data reset
+    // was requested, it doesn't matter, everything will get wiped anyway.
+    // To make testing easier we consider a /data wipe as cleaned up.
+    if (device_->IsRecovery() && !in_factory_data_reset_) {
+        WriteUpdateState(lock, UpdateState::MergeCompleted);
+        return;
+    }
+
     RemoveAllUpdateState(lock);
 }
 
@@ -1674,7 +1691,7 @@
         return false;
     }
     std::string cow_device;
-    if (!dm.GetDeviceString(cow_name, &cow_device)) {
+    if (!GetMappedImageDeviceStringOrPath(cow_name, &cow_device)) {
         LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
         return false;
     }
@@ -1771,7 +1788,7 @@
     // If the COW image exists, append it as the last extent.
     if (snapshot_status.cow_file_size() > 0) {
         std::string cow_image_device;
-        if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
+        if (!GetMappedImageDeviceStringOrPath(cow_image_name, &cow_image_device)) {
             LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
             return false;
         }
@@ -2347,7 +2364,6 @@
         const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
     CHECK(lock);
 
-    auto& dm = DeviceMapper::Instance();
     CreateLogicalPartitionParams cow_params{
             .block_device = LP_METADATA_DEFAULT_PARTITION_NAME,
             .metadata = exported_target_metadata,
@@ -2372,7 +2388,7 @@
         }
 
         std::string cow_path;
-        if (!dm.GetDmDevicePathByName(cow_name, &cow_path)) {
+        if (!images_->GetMappedImageDevice(cow_name, &cow_path)) {
             LOG(ERROR) << "Cannot determine path for " << cow_name;
             return Return::Error();
         }
@@ -2528,7 +2544,43 @@
         }
         return true;
     };
-    if (!ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback)) {
+
+    in_factory_data_reset_ = true;
+    bool ok = ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback);
+    in_factory_data_reset_ = false;
+
+    if (!ok) {
+        return false;
+    }
+
+    // Nothing should be depending on partitions now, so unmap them all.
+    if (!UnmapAllPartitions()) {
+        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
+    }
+    return true;
+}
+
+bool SnapshotManager::FinishMergeInRecovery() {
+    if (!device_->IsRecovery()) {
+        LOG(ERROR) << "Data wipes are only allowed in recovery.";
+        return false;
+    }
+
+    auto mount = EnsureMetadataMounted();
+    if (!mount || !mount->HasDevice()) {
+        return false;
+    }
+
+    auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+    auto super_path = device_->GetSuperDevice(slot_number);
+    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+        LOG(ERROR) << "Unable to map partitions to complete merge.";
+        return false;
+    }
+
+    UpdateState state = ProcessUpdateState();
+    if (state != UpdateState::MergeCompleted) {
+        LOG(ERROR) << "Merge returned unexpected status: " << state;
         return false;
     }
 
@@ -2685,5 +2737,24 @@
     return true;
 }
 
+bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
+                                                       std::string* device_string_or_mapped_path) {
+    auto& dm = DeviceMapper::Instance();
+    // Try getting the device string if it is a device mapper device.
+    if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+        return dm.GetDeviceString(device_name, device_string_or_mapped_path);
+    }
+
+    // Otherwise, get path from IImageManager.
+    if (!images_->GetMappedImageDevice(device_name, device_string_or_mapped_path)) {
+        return false;
+    }
+
+    LOG(WARNING) << "Calling GetMappedImageDevice with local image manager; device "
+                 << (device_string_or_mapped_path ? *device_string_or_mapped_path : "(nullptr)")
+                 << "may not be available in first stage init! ";
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f82c082..9ca2412 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1454,6 +1454,52 @@
     ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
 }
 
+// Test that a merge does not clear the snapshot state in fastboot.
+TEST_F(SnapshotUpdateTest, MergeInFastboot) {
+    // Execute the first update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+    ASSERT_TRUE(MapUpdateSnapshots());
+    ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+    // Simulate shutting down the device.
+    ASSERT_TRUE(UnmapAll());
+
+    // After reboot, init does first stage mount.
+    auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+    ASSERT_NE(init, nullptr);
+    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+    init = nullptr;
+
+    // Initiate the merge and then immediately stop it to simulate a reboot.
+    auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
+    ASSERT_TRUE(new_sm->InitiateMerge());
+    ASSERT_TRUE(UnmapAll());
+
+    // Simulate a reboot into recovery.
+    auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    test_device->set_recovery(true);
+    new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+
+    ASSERT_TRUE(new_sm->FinishMergeInRecovery());
+
+    auto mount = new_sm->EnsureMetadataMounted();
+    ASSERT_TRUE(mount && mount->HasDevice());
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+
+    // Finish the merge in a normal boot.
+    test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    init = SnapshotManager::NewForFirstStageMount(test_device.release());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+    init = nullptr;
+
+    test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
+}
+
 // Test that after an OTA, before a merge, we can wipe data in recovery.
 TEST_F(SnapshotUpdateTest, DataWipeRollbackInRecovery) {
     // Execute the first update.
diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp
index cae53f4..cfa0d99 100644
--- a/init/first_stage_console.cpp
+++ b/init/first_stage_console.cpp
@@ -16,6 +16,7 @@
 
 #include "first_stage_console.h"
 
+#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
@@ -87,8 +88,18 @@
     _exit(127);
 }
 
-bool FirstStageConsole(const std::string& cmdline) {
-    return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
+int FirstStageConsole(const std::string& cmdline) {
+    auto pos = cmdline.find("androidboot.first_stage_console=");
+    if (pos != std::string::npos) {
+        int val = 0;
+        if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) {
+            return FirstStageConsoleParam::DISABLED;
+        }
+        if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) {
+            return val;
+        }
+    }
+    return FirstStageConsoleParam::DISABLED;
 }
 
 }  // namespace init
diff --git a/init/first_stage_console.h b/init/first_stage_console.h
index 7485339..8f36a7c 100644
--- a/init/first_stage_console.h
+++ b/init/first_stage_console.h
@@ -21,8 +21,15 @@
 namespace android {
 namespace init {
 
+enum FirstStageConsoleParam {
+    DISABLED = 0,
+    CONSOLE_ON_FAILURE = 1,
+    IGNORE_FAILURE = 2,
+    MAX_PARAM_VALUE = IGNORE_FAILURE,
+};
+
 void StartConsole();
-bool FirstStageConsole(const std::string& cmdline);
+int FirstStageConsole(const std::string& cmdline);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 5eca644..1a608f6 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -200,16 +200,16 @@
     }
 
     Modprobe m({"/lib/modules"}, module_load_file);
-    auto want_console = ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline);
+    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
     if (!m.LoadListedModules(!want_console)) {
-        if (want_console) {
+        if (want_console != FirstStageConsoleParam::DISABLED) {
             LOG(ERROR) << "Failed to load kernel modules, starting console";
         } else {
             LOG(FATAL) << "Failed to load kernel modules";
         }
     }
 
-    if (want_console) {
+    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
         StartConsole();
     }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e89f74a..ffd58a3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -66,8 +66,6 @@
 #include "sigchld_handler.h"
 #include "util.h"
 
-#define PROC_SYSRQ "/proc/sysrq-trigger"
-
 using namespace std::literals;
 
 using android::base::boot_clock;
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 485188b..76460a5 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -29,6 +29,7 @@
 #include <cutils/android_reboot.h>
 
 #include "capabilities.h"
+#include "reboot_utils.h"
 
 namespace android {
 namespace init {
@@ -138,6 +139,9 @@
         LOG(ERROR) << backtrace->FormatFrameData(i);
     }
     if (init_fatal_panic) {
+        LOG(ERROR) << __FUNCTION__ << ": Trigger crash";
+        android::base::WriteStringToFile("c", PROC_SYSRQ);
+        LOG(ERROR) << __FUNCTION__ << ": Sys-Rq failed to crash the system; fallback to exit().";
         _exit(signal_number);
     }
     RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 878ad96..05bb9ae 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -18,6 +18,8 @@
 
 #include <string>
 
+#define PROC_SYSRQ "/proc/sysrq-trigger"
+
 namespace android {
 namespace init {
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 9ed7927..24110ee 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -33,6 +33,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     target: {
@@ -59,6 +60,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 
     export_include_dirs: ["include"],
 
@@ -142,6 +144,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
     native_bridge_supported: true,
     srcs: [
         "config_utils.cpp",
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index ce0c3c8..33ae13d 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -26,4 +26,5 @@
     export_include_dirs: ["include"],
     shared_libs: ["android.hardware.graphics.allocator@2.0"],
     header_libs: ["libhardware_headers"],
+    min_sdk_version: "29",
 }
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 9ecdd4f..64de00e 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -37,25 +37,22 @@
 
 #include "dhcpmsg.h"
 
-int fatal();
+int fatal(const char*);
 
-int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
-{
-    int s;
-    struct sockaddr_ll bindaddr;
+int open_raw_socket(const char* ifname __unused, uint8_t hwaddr[ETH_ALEN], int if_index) {
+    int s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (s < 0) return fatal("socket(PF_PACKET)");
 
-    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
-        return fatal("socket(PF_PACKET)");
-    }
-
-    memset(&bindaddr, 0, sizeof(bindaddr));
-    bindaddr.sll_family = AF_PACKET;
-    bindaddr.sll_protocol = htons(ETH_P_IP);
-    bindaddr.sll_halen = ETH_ALEN;
+    struct sockaddr_ll bindaddr = {
+            .sll_family = AF_PACKET,
+            .sll_protocol = htons(ETH_P_IP),
+            .sll_ifindex = if_index,
+            .sll_halen = ETH_ALEN,
+    };
     memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
-    bindaddr.sll_ifindex = if_index;
 
     if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
+        close(s);
         return fatal("Cannot bind raw socket to interface");
     }
 
diff --git a/libnetutils/packet.h b/libnetutils/packet.h
index aade392..66186fc 100644
--- a/libnetutils/packet.h
+++ b/libnetutils/packet.h
@@ -17,7 +17,9 @@
 #ifndef _WIFI_PACKET_H_
 #define _WIFI_PACKET_H_
 
-int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
+#include <linux/if_ether.h>
+
+int open_raw_socket(const char* ifname, uint8_t hwaddr[ETH_ALEN], int if_index);
 int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
                 uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
 int receive_packet(int s, struct dhcp_msg *msg);
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 2c1b255..bda11e9 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -17,6 +17,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library {
@@ -60,4 +61,5 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 }
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index 766ea0f..ccc6f62 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -89,15 +89,15 @@
         "test_vendor.cpp",
     ],
     static_libs: [
+        "libbase",
         "libgmock",
+        "liblog",
+        "libjsoncpp",
         "libjsonpbverify",
         "libjsonpbparse",
         "libprocessgroup_proto",
     ],
     shared_libs: [
-        "libbase",
-        "liblog",
-        "libjsoncpp",
         "libprotobuf-cpp-full",
     ],
     test_suites: [
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 0c9a2b8..15b0d89 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -51,6 +51,12 @@
             enabled: false,
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.art.debug",
+        "com.android.art.release",
+    ],
 }
 
 // Tests
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index e1a86ae..c17ca61 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -28,17 +28,8 @@
 using android::base::GetProperty;
 
 const static int kStatsEventTag = 1937006964;
-
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
 const bool StatsEventCompat::mPlatformAtLeastR =
-        GetProperty("ro.build.version.codename", "") == "R" ||
-        android_get_device_api_level() > __ANDROID_API_Q__;
+        android_get_device_api_level() >= __ANDROID_API_R__;
 
 // initializations of static class variables
 bool StatsEventCompat::mAttemptedLoad = false;
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
index dcb3797..2a70db5 100644
--- a/libstats/push_compat/tests/StatsEventCompat_test.cpp
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -21,16 +21,7 @@
 
 using android::base::GetProperty;
 
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
-const static bool mPlatformAtLeastR = GetProperty("ro.build.version.codename", "") == "R" ||
-                                      android_get_device_api_level() > __ANDROID_API_Q__;
+const static bool mPlatformAtLeastR = android_get_device_api_level() >= __ANDROID_API_R__;
 
 TEST(StatsEventCompatTest, TestDynamicLoading) {
     StatsEventCompat event;
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index ff886fd..db61669 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -8,6 +8,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "apex_inherit",
     export_include_dirs: ["include"],
 
     target: {
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 627f0d4..3b98bab 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -43,6 +43,7 @@
         "//apex_available:anyapex",
         "//apex_available:platform",
     ],
+    min_sdk_version: "apex_inherit",
 }
 
 cc_test {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 5efe03f..9c1621b 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -180,6 +180,7 @@
     struct ifa_cacheinfo *cacheinfo = nullptr;
     char addrstr[INET6_ADDRSTRLEN] = "";
     char ifname[IFNAMSIZ] = "";
+    uint32_t flags;
 
     if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
         return false;
@@ -194,6 +195,9 @@
     // For log messages.
     const char *msgtype = rtMessageName(type);
 
+    // First 8 bits of flags. In practice will always be overridden when parsing IFA_FLAGS below.
+    flags = ifaddr->ifa_flags;
+
     struct rtattr *rta;
     int len = IFA_PAYLOAD(nh);
     for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
@@ -242,6 +246,9 @@
             }
 
             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
+
+        } else if (rta->rta_type == IFA_FLAGS) {
+            flags = *(uint32_t*)RTA_DATA(rta);
         }
     }
 
@@ -256,7 +263,7 @@
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
     asprintf(&mParams[1], "INTERFACE=%s", ifname);
-    asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+    asprintf(&mParams[2], "FLAGS=%u", flags);
     asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
     asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index);
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 1f3ba59..563c2c2 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -135,6 +135,12 @@
             exclude_shared_libs: ["libdexfile_support"],
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.art.debug",
+        "com.android.art.release",
+    ],
 }
 
 // Static library without DEX support to avoid dependencies on the ART APEX.
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7405c96..3a30a9e 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,6 +22,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "apex_inherit",
 
     header_libs: [
         "liblog_headers",
@@ -168,6 +169,7 @@
         "//apex_available:anyapex",
         "//apex_available:platform",
     ],
+    min_sdk_version: "apex_inherit",
 }
 
 cc_library {
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 1202c15..1d899ab 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -195,7 +195,7 @@
     int prot = PROT_READ;
     if (!readOnly) prot |= PROT_WRITE;
 
-    void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+    void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
         if (errno == EINVAL && length == 0) {
             ptr = nullptr;
diff --git a/libutils/FileMap_test.cpp b/libutils/FileMap_test.cpp
index 576d89b..9f7ce85 100644
--- a/libutils/FileMap_test.cpp
+++ b/libutils/FileMap_test.cpp
@@ -32,3 +32,23 @@
     ASSERT_EQ(0u, m.getDataLength());
     ASSERT_EQ(4096, m.getDataOffset());
 }
+
+TEST(FileMap, large_offset) {
+    // Make sure that an offset > INT32_MAX will not fail the create
+    // function. See http://b/155662887.
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+
+    off64_t offset = INT32_MAX + 1024LL;
+
+    // Make the temporary file large enough to pass the mmap.
+    ASSERT_EQ(offset, lseek64(tf.fd, offset, SEEK_SET));
+    char value = 0;
+    ASSERT_EQ(1, write(tf.fd, &value, 1));
+
+    android::FileMap m;
+    ASSERT_TRUE(m.create("test", tf.fd, offset, 0, true));
+    ASSERT_STREQ("test", m.getFileName());
+    ASSERT_EQ(0u, m.getDataLength());
+    ASSERT_EQ(offset, m.getDataOffset());
+}
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index dee577e..6002567 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -19,12 +19,20 @@
 
 #include <unistd.h>
 
+#if !defined(__MINGW32__)
+#include <sys/mman.h>
+#endif
+
 #if defined(__APPLE__)
 
 /* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
-
+static_assert(sizeof(off_t) >= 8, "This code requires that Mac OS have at least a 64-bit off_t.");
 typedef off_t off64_t;
 
+static inline void* mmap64(void* addr, size_t length, int prot, int flags, int fd, off64_t offset) {
+    return mmap(addr, length, prot, flags, fd, offset);
+}
+
 static inline off64_t lseek64(int fd, off64_t offset, int whence) {
     return lseek(fd, offset, whence);
 }
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1bbffaf..553136a 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -109,6 +109,12 @@
             enabled: true,
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.art.debug",
+        "com.android.art.release",
+    ],
 }
 
 // Tests.