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.