Merge "Added test for version check"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 0c75e49..cdcd036 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -2399,7 +2399,7 @@
}
}
}
- std::unique_ptr<Task> reboot_task = nullptr;
+ std::vector<std::unique_ptr<Task>> tasks;
std::vector<std::string> args(argv, argv + argc);
while (!args.empty()) {
std::string command = next_arg(&args);
@@ -2453,17 +2453,17 @@
} else if (command == FB_CMD_REBOOT) {
if (args.size() == 1) {
std::string reboot_target = next_arg(&args);
- reboot_task = std::make_unique<RebootTask>(fp.get(), reboot_target);
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), reboot_target));
} else if (!fp->skip_reboot) {
- reboot_task = std::make_unique<RebootTask>(fp.get());
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
}
if (!args.empty()) syntax_error("junk after reboot command");
} else if (command == FB_CMD_REBOOT_BOOTLOADER) {
- reboot_task = std::make_unique<RebootTask>(fp.get(), "bootloader");
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "bootloader"));
} else if (command == FB_CMD_REBOOT_RECOVERY) {
- reboot_task = std::make_unique<RebootTask>(fp.get(), "recovery");
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "recovery"));
} else if (command == FB_CMD_REBOOT_FASTBOOT) {
- reboot_task = std::make_unique<RebootTask>(fp.get(), "fastboot");
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "fastboot"));
} else if (command == FB_CMD_CONTINUE) {
fb->Continue();
} else if (command == FB_CMD_BOOT) {
@@ -2505,12 +2505,11 @@
fprintf(stderr,
"Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
fp->skip_secondary = true;
- do_flashall(fp.get());
- } else {
- do_flashall(fp.get());
}
+ do_flashall(fp.get());
+
if (!fp->skip_reboot) {
- reboot_task = std::make_unique<RebootTask>(fp.get());
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
}
} else if (command == "update") {
bool slot_all = (fp->slot_override == "all");
@@ -2524,7 +2523,7 @@
}
do_update(filename.c_str(), fp.get());
if (!fp->skip_reboot) {
- reboot_task = std::make_unique<RebootTask>(fp.get());
+ tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
}
} else if (command == FB_CMD_SET_ACTIVE) {
std::string slot = verify_slot(next_arg(&args), false);
@@ -2558,8 +2557,7 @@
fb->CreatePartition(partition, size);
} else if (command == FB_CMD_DELETE_PARTITION) {
std::string partition = next_arg(&args);
- auto delete_task = std::make_unique<DeleteTask>(fp.get(), partition);
- fb->DeletePartition(partition);
+ tasks.emplace_back(std::make_unique<DeleteTask>(fp.get(), partition));
} else if (command == FB_CMD_RESIZE_PARTITION) {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
@@ -2607,15 +2605,14 @@
}
std::vector<std::string> partitions = {"userdata", "cache", "metadata"};
for (const auto& partition : partitions) {
- std::unique_ptr<WipeTask> wipe_task = std::make_unique<WipeTask>(fp.get(), partition);
- wipe_task->Run();
+ tasks.emplace_back(std::make_unique<WipeTask>(fp.get(), partition));
}
}
if (fp->wants_set_active) {
fb->SetActive(next_active);
}
- if (reboot_task) {
- reboot_task->Run();
+ for (auto& task : tasks) {
+ task->Run();
}
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 3bfa4d5..3dd1f1a 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -252,13 +252,6 @@
header_libs: [
"libstorage_literals_headers",
],
- test_suites: [
- "vts",
- "device-tests"
- ],
- test_options: {
- min_shipping_api_level: 29,
- },
auto_gen_config: true,
require_root: true,
compile_multilib: "first",
@@ -267,6 +260,13 @@
cc_test {
name: "vts_libsnapshot_test",
defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"],
+ test_suites: [
+ "vts",
+ "device-tests"
+ ],
+ test_options: {
+ min_shipping_api_level: 30,
+ },
}
cc_test {
@@ -275,6 +275,13 @@
cppflags: [
"-DLIBSNAPSHOT_TEST_VAB_LEGACY",
],
+ test_suites: [
+ "device-tests"
+ ],
+ test_options: {
+ // Legacy VAB launched in Android R.
+ min_shipping_api_level: 30,
+ },
}
cc_test {
@@ -283,6 +290,13 @@
cppflags: [
"-DLIBSNAPSHOT_TEST_VABC_LEGACY",
],
+ test_suites: [
+ "device-tests"
+ ],
+ test_options: {
+ // Legacy VABC launched in Android S.
+ min_shipping_api_level: 31,
+ },
}
cc_test {
@@ -349,24 +363,6 @@
}
cc_test {
- name: "snapshot_power_test",
- srcs: [
- "power_test.cpp",
- ],
- static_libs: [
- "libc++fs",
- "libsnapshot",
- "update_metadata-protos",
- ],
- shared_libs: [
- "libbase",
- "libfs_mgr_binder",
- "liblog",
- ],
- gtest: false,
-}
-
-cc_test {
name: "cow_api_test",
defaults: [
"fs_mgr_defaults",
@@ -403,78 +399,6 @@
}
cc_binary {
- name: "make_cow_from_ab_ota",
- host_supported: true,
- device_supported: false,
- cflags: [
- "-D_FILE_OFFSET_BITS=64",
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libbase",
- "libbspatch",
- "libbrotli",
- "libbz",
- "libchrome",
- "libcrypto",
- "libgflags",
- "liblog",
- "libprotobuf-cpp-lite",
- "libpuffpatch",
- "libsnapshot_cow",
- "libsparse",
- "libxz",
- "libz",
- "liblz4",
- "libziparchive",
- "update_metadata-protos",
- ],
- srcs: [
- "make_cow_from_ab_ota.cpp",
- ],
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
-cc_binary {
- name: "estimate_cow_from_nonab_ota",
- defaults: [
- "libsnapshot_cow_defaults",
- ],
- host_supported: true,
- device_supported: false,
- cflags: [
- "-D_FILE_OFFSET_BITS=64",
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libbase",
- "libbrotli",
- "libbz",
- "libcrypto",
- "libgflags",
- "liblog",
- "libsnapshot_cow",
- "libsparse",
- "libz",
- "libziparchive",
- ],
- srcs: [
- "estimate_cow_from_nonab_ota.cpp",
- ],
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
-cc_binary {
name: "inspect_cow",
host_supported: true,
device_supported: true,
diff --git a/fs_mgr/libsnapshot/PowerTest.md b/fs_mgr/libsnapshot/PowerTest.md
deleted file mode 100644
index 0b0cb5d..0000000
--- a/fs_mgr/libsnapshot/PowerTest.md
+++ /dev/null
@@ -1,40 +0,0 @@
-snapshot\_power\_test
----------------------
-
-snapshot\_power\_test is a standalone test to simulate power failures during a snapshot-merge operation.
-
-### Test Setup
-
-Start by creating two large files that will be used as the pre-merge and post-merge state. You can take two different partition images (for example, a product.img from two separate builds), or just create random data:
-
- dd if=/dev/urandom of=pre-merge count=1024 bs=1048576
- dd if=/dev/urandom of=post-merge count=1024 bs=1048576
-
-Next, push these files to an unencrypted directory on the device:
-
- adb push pre-merge /data/local/unencrypted
- adb push post-merge /data/local/unencrypted
-
-Next, run the test setup:
-
- adb sync data
- adb shell /data/nativetest64/snapshot_power_test/snapshot_power_test \
- /data/local/unencrypted/pre-merge \
- /data/local/unencrypted/post-merge
-
-This will create the necessary fiemap-based images.
-
-### Running
-The actual test can be run via `run_power_test.sh`. Its syntax is:
-
- run_power_test.sh <POST_MERGE_FILE>
-
-`POST_MERGE_FILE` should be the path on the device of the image to validate the merge against. Example:
-
- run_power_test.sh /data/local/unencrypted/post-merge
-
-The device will begin the merge with a 5% chance of injecting a kernel crash every 10ms. The device should be capable of rebooting normally without user intervention. Once the merge has completed, the test will run a final check command to validate the contents of the snapshot against the post-merge file. It will error if there are any incorrect blocks.
-
-Two environment variables can be passed to `run_power_test.sh`:
-1. `FAIL_RATE` - A fraction between 0 and 100 (inclusive) indicating the probability the device should inject a kernel crash every 10ms.
-2. `DEVICE_SERIAL` - If multiple devices are attached to adb, this argument is passed as the serial to select (to `adb -s`).
diff --git a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
deleted file mode 100644
index 45833e1..0000000
--- a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
+++ /dev/null
@@ -1,432 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <iostream>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <gflags/gflags.h>
-#include <libsnapshot/cow_writer.h>
-#include <openssl/sha.h>
-#include <sparse/sparse.h>
-#include <ziparchive/zip_archive.h>
-
-DEFINE_string(source_tf, "", "Source target files (dir or zip file)");
-DEFINE_string(ota_tf, "", "Target files of the build for an OTA");
-DEFINE_string(compression, "gz", "Compression (options: none, gz, brotli)");
-
-namespace android {
-namespace snapshot {
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
-static constexpr size_t kBlockSize = 4096;
-
-void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
- unsigned int, const char* message) {
- if (severity == android::base::ERROR) {
- fprintf(stderr, "%s\n", message);
- } else {
- fprintf(stdout, "%s\n", message);
- }
-}
-
-class TargetFilesPackage final {
- public:
- explicit TargetFilesPackage(const std::string& path);
-
- bool Open();
- bool HasFile(const std::string& path);
- std::unordered_set<std::string> GetDynamicPartitionNames();
- unique_fd OpenFile(const std::string& path);
- unique_fd OpenImage(const std::string& path);
-
- private:
- std::string path_;
- unique_fd fd_;
- std::unique_ptr<ZipArchive, decltype(&CloseArchive)> zip_;
-};
-
-TargetFilesPackage::TargetFilesPackage(const std::string& path)
- : path_(path), zip_(nullptr, &CloseArchive) {}
-
-bool TargetFilesPackage::Open() {
- fd_.reset(open(path_.c_str(), O_RDONLY));
- if (fd_ < 0) {
- PLOG(ERROR) << "open failed: " << path_;
- return false;
- }
-
- struct stat s;
- if (fstat(fd_.get(), &s) < 0) {
- PLOG(ERROR) << "fstat failed: " << path_;
- return false;
- }
- if (S_ISDIR(s.st_mode)) {
- return true;
- }
-
- // Otherwise, assume it's a zip file.
- ZipArchiveHandle handle;
- if (OpenArchiveFd(fd_.get(), path_.c_str(), &handle, false)) {
- LOG(ERROR) << "Could not open " << path_ << " as a zip archive.";
- return false;
- }
- zip_.reset(handle);
- return true;
-}
-
-bool TargetFilesPackage::HasFile(const std::string& path) {
- if (zip_) {
- ZipEntry64 entry;
- return !FindEntry(zip_.get(), path, &entry);
- }
-
- auto full_path = path_ + "/" + path;
- return access(full_path.c_str(), F_OK) == 0;
-}
-
-unique_fd TargetFilesPackage::OpenFile(const std::string& path) {
- if (!zip_) {
- auto full_path = path_ + "/" + path;
- unique_fd fd(open(full_path.c_str(), O_RDONLY));
- if (fd < 0) {
- PLOG(ERROR) << "open failed: " << full_path;
- return {};
- }
- return fd;
- }
-
- ZipEntry64 entry;
- if (FindEntry(zip_.get(), path, &entry)) {
- LOG(ERROR) << path << " not found in archive: " << path_;
- return {};
- }
-
- TemporaryFile temp;
- if (temp.fd < 0) {
- PLOG(ERROR) << "mkstemp failed";
- return {};
- }
-
- LOG(INFO) << "Extracting " << path << " from " << path_ << " ...";
- if (ExtractEntryToFile(zip_.get(), &entry, temp.fd)) {
- LOG(ERROR) << "could not extract " << path << " from " << path_;
- return {};
- }
- if (lseek(temp.fd, 0, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek failed";
- return {};
- }
- return unique_fd{temp.release()};
-}
-
-unique_fd TargetFilesPackage::OpenImage(const std::string& path) {
- auto fd = OpenFile(path);
- if (fd < 0) {
- return {};
- }
-
- LOG(INFO) << "Unsparsing " << path << " ...";
- std::unique_ptr<struct sparse_file, decltype(&sparse_file_destroy)> s(
- sparse_file_import(fd.get(), false, false), &sparse_file_destroy);
- if (!s) {
- return fd;
- }
-
- TemporaryFile temp;
- if (temp.fd < 0) {
- PLOG(ERROR) << "mkstemp failed";
- return {};
- }
- if (sparse_file_write(s.get(), temp.fd, false, false, false) < 0) {
- LOG(ERROR) << "sparse_file_write failed";
- return {};
- }
- if (lseek(temp.fd, 0, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek failed";
- return {};
- }
-
- fd.reset(temp.release());
- return fd;
-}
-
-std::unordered_set<std::string> TargetFilesPackage::GetDynamicPartitionNames() {
- auto fd = OpenFile("META/misc_info.txt");
- if (fd < 0) {
- return {};
- }
-
- std::string contents;
- if (!android::base::ReadFdToString(fd, &contents)) {
- PLOG(ERROR) << "read failed";
- return {};
- }
-
- std::unordered_set<std::string> set;
-
- auto lines = android::base::Split(contents, "\n");
- for (const auto& line : lines) {
- auto parts = android::base::Split(line, "=");
- if (parts.size() == 2 && parts[0] == "dynamic_partition_list") {
- auto partitions = android::base::Split(parts[1], " ");
- for (const auto& name : partitions) {
- if (!name.empty()) {
- set.emplace(name);
- }
- }
- break;
- }
- }
- return set;
-}
-
-class NonAbEstimator final {
- public:
- NonAbEstimator(const std::string& ota_tf_path, const std::string& source_tf_path)
- : ota_tf_path_(ota_tf_path), source_tf_path_(source_tf_path) {}
-
- bool Run();
-
- private:
- bool OpenPackages();
- bool AnalyzePartition(const std::string& partition_name);
- std::unordered_map<std::string, uint64_t> GetBlockMap(borrowed_fd fd);
-
- std::string ota_tf_path_;
- std::string source_tf_path_;
- std::unique_ptr<TargetFilesPackage> ota_tf_;
- std::unique_ptr<TargetFilesPackage> source_tf_;
- uint64_t size_ = 0;
-};
-
-bool NonAbEstimator::Run() {
- if (!OpenPackages()) {
- return false;
- }
-
- auto partitions = ota_tf_->GetDynamicPartitionNames();
- if (partitions.empty()) {
- LOG(ERROR) << "No dynamic partitions found in META/misc_info.txt";
- return false;
- }
- for (const auto& partition : partitions) {
- if (!AnalyzePartition(partition)) {
- return false;
- }
- }
-
- int64_t size_in_mb = int64_t(double(size_) / 1024.0 / 1024.0);
-
- std::cout << "Estimated COW size: " << size_ << " (" << size_in_mb << "MiB)\n";
- return true;
-}
-
-bool NonAbEstimator::OpenPackages() {
- ota_tf_ = std::make_unique<TargetFilesPackage>(ota_tf_path_);
- if (!ota_tf_->Open()) {
- return false;
- }
- if (!source_tf_path_.empty()) {
- source_tf_ = std::make_unique<TargetFilesPackage>(source_tf_path_);
- if (!source_tf_->Open()) {
- return false;
- }
- }
- return true;
-}
-
-static std::string SHA256(const std::string& input) {
- std::string hash(32, '\0');
- SHA256_CTX c;
- SHA256_Init(&c);
- SHA256_Update(&c, input.data(), input.size());
- SHA256_Final(reinterpret_cast<unsigned char*>(hash.data()), &c);
- return hash;
-}
-
-bool NonAbEstimator::AnalyzePartition(const std::string& partition_name) {
- auto path = "IMAGES/" + partition_name + ".img";
- auto fd = ota_tf_->OpenImage(path);
- if (fd < 0) {
- return false;
- }
-
- unique_fd source_fd;
- uint64_t source_size = 0;
- std::unordered_map<std::string, uint64_t> source_blocks;
- if (source_tf_) {
- auto dap = source_tf_->GetDynamicPartitionNames();
-
- source_fd = source_tf_->OpenImage(path);
- if (source_fd >= 0) {
- struct stat s;
- if (fstat(source_fd.get(), &s)) {
- PLOG(ERROR) << "fstat failed";
- return false;
- }
- source_size = s.st_size;
-
- std::cout << "Hashing blocks for " << partition_name << "...\n";
- source_blocks = GetBlockMap(source_fd);
- if (source_blocks.empty()) {
- LOG(ERROR) << "Could not build a block map for source partition: "
- << partition_name;
- return false;
- }
- } else {
- if (dap.count(partition_name)) {
- return false;
- }
- LOG(ERROR) << "Warning: " << partition_name
- << " has no incremental diff since it's not in the source image.";
- }
- }
-
- TemporaryFile cow;
- if (cow.fd < 0) {
- PLOG(ERROR) << "mkstemp failed";
- return false;
- }
-
- CowOptions options;
- options.block_size = kBlockSize;
- options.compression = FLAGS_compression;
-
- auto writer = std::make_unique<CowWriter>(options);
- if (!writer->Initialize(borrowed_fd{cow.fd})) {
- LOG(ERROR) << "Could not initialize COW writer";
- return false;
- }
-
- LOG(INFO) << "Analyzing " << partition_name << " ...";
-
- std::string zeroes(kBlockSize, '\0');
- std::string chunk(kBlockSize, '\0');
- std::string src_chunk(kBlockSize, '\0');
- uint64_t next_block_number = 0;
- while (true) {
- if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
- if (errno) {
- PLOG(ERROR) << "read failed";
- return false;
- }
- break;
- }
-
- uint64_t block_number = next_block_number++;
- if (chunk == zeroes) {
- if (!writer->AddZeroBlocks(block_number, 1)) {
- LOG(ERROR) << "Could not add zero block";
- return false;
- }
- continue;
- }
-
- uint64_t source_offset = block_number * kBlockSize;
- if (source_fd >= 0 && source_offset <= source_size) {
- off64_t offset = block_number * kBlockSize;
- if (android::base::ReadFullyAtOffset(source_fd, src_chunk.data(), src_chunk.size(),
- offset)) {
- if (chunk == src_chunk) {
- continue;
- }
- } else if (errno) {
- PLOG(ERROR) << "pread failed";
- return false;
- }
- }
-
- auto hash = SHA256(chunk);
- if (auto iter = source_blocks.find(hash); iter != source_blocks.end()) {
- if (!writer->AddCopy(block_number, iter->second)) {
- return false;
- }
- continue;
- }
-
- if (!writer->AddRawBlocks(block_number, chunk.data(), chunk.size())) {
- return false;
- }
- }
-
- if (!writer->Finalize()) {
- return false;
- }
-
- struct stat s;
- if (fstat(cow.fd, &s) < 0) {
- PLOG(ERROR) << "fstat failed";
- return false;
- }
-
- size_ += s.st_size;
- return true;
-}
-
-std::unordered_map<std::string, uint64_t> NonAbEstimator::GetBlockMap(borrowed_fd fd) {
- std::string chunk(kBlockSize, '\0');
-
- std::unordered_map<std::string, uint64_t> block_map;
- uint64_t block_number = 0;
- while (true) {
- if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
- if (errno) {
- PLOG(ERROR) << "read failed";
- return {};
- }
- break;
- }
- auto hash = SHA256(chunk);
- block_map[hash] = block_number;
- block_number++;
- }
- return block_map;
-}
-
-} // namespace snapshot
-} // namespace android
-
-using namespace android::snapshot;
-
-int main(int argc, char** argv) {
- android::base::InitLogging(argv, android::snapshot::MyLogger);
- gflags::SetUsageMessage("Estimate VAB disk usage from Non A/B builds");
- gflags::ParseCommandLineFlags(&argc, &argv, false);
-
- if (FLAGS_ota_tf.empty()) {
- std::cerr << "Must specify -ota_tf on the command-line." << std::endl;
- return 1;
- }
-
- NonAbEstimator estimator(FLAGS_ota_tf, FLAGS_source_tf);
- if (!estimator.Run()) {
- return 1;
- }
- return 0;
-}
diff --git a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
deleted file mode 100644
index 6a5754d..0000000
--- a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
+++ /dev/null
@@ -1,692 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <iostream>
-#include <limits>
-#include <string>
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <bsdiff/bspatch.h>
-#include <bzlib.h>
-#include <gflags/gflags.h>
-#include <libsnapshot/cow_writer.h>
-#include <puffin/puffpatch.h>
-#include <sparse/sparse.h>
-#include <update_engine/update_metadata.pb.h>
-#include <xz.h>
-#include <ziparchive/zip_archive.h>
-
-namespace android {
-namespace snapshot {
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-using chromeos_update_engine::DeltaArchiveManifest;
-using chromeos_update_engine::Extent;
-using chromeos_update_engine::InstallOperation;
-using chromeos_update_engine::PartitionUpdate;
-
-static constexpr uint64_t kBlockSize = 4096;
-
-DEFINE_string(source_tf, "", "Source target files (dir or zip file) for incremental payloads");
-DEFINE_string(compression, "gz", "Compression type to use (none or gz)");
-DEFINE_uint32(cluster_ops, 0, "Number of Cow Ops per cluster (0 or >1)");
-
-void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
- unsigned int, const char* message) {
- if (severity == android::base::ERROR) {
- fprintf(stderr, "%s\n", message);
- } else {
- fprintf(stdout, "%s\n", message);
- }
-}
-
-uint64_t ToLittleEndian(uint64_t value) {
- union {
- uint64_t u64;
- char bytes[8];
- } packed;
- packed.u64 = value;
- std::swap(packed.bytes[0], packed.bytes[7]);
- std::swap(packed.bytes[1], packed.bytes[6]);
- std::swap(packed.bytes[2], packed.bytes[5]);
- std::swap(packed.bytes[3], packed.bytes[4]);
- return packed.u64;
-}
-
-class PayloadConverter final {
- public:
- PayloadConverter(const std::string& in_file, const std::string& out_dir)
- : in_file_(in_file), out_dir_(out_dir), source_tf_zip_(nullptr, &CloseArchive) {}
-
- bool Run();
-
- private:
- bool OpenPayload();
- bool OpenSourceTargetFiles();
- bool ProcessPartition(const PartitionUpdate& update);
- bool ProcessOperation(const InstallOperation& op);
- bool ProcessZero(const InstallOperation& op);
- bool ProcessCopy(const InstallOperation& op);
- bool ProcessReplace(const InstallOperation& op);
- bool ProcessDiff(const InstallOperation& op);
- borrowed_fd OpenSourceImage();
-
- std::string in_file_;
- std::string out_dir_;
- unique_fd in_fd_;
- uint64_t payload_offset_ = 0;
- DeltaArchiveManifest manifest_;
- std::unordered_set<std::string> dap_;
- unique_fd source_tf_fd_;
- std::unique_ptr<ZipArchive, decltype(&CloseArchive)> source_tf_zip_;
-
- // Updated during ProcessPartition().
- std::string partition_name_;
- std::unique_ptr<CowWriter> writer_;
- unique_fd source_image_;
-};
-
-bool PayloadConverter::Run() {
- if (!OpenPayload()) {
- return false;
- }
-
- if (manifest_.has_dynamic_partition_metadata()) {
- const auto& dpm = manifest_.dynamic_partition_metadata();
- for (const auto& group : dpm.groups()) {
- for (const auto& partition : group.partition_names()) {
- dap_.emplace(partition);
- }
- }
- }
-
- if (dap_.empty()) {
- LOG(ERROR) << "No dynamic partitions found.";
- return false;
- }
-
- if (!OpenSourceTargetFiles()) {
- return false;
- }
-
- for (const auto& update : manifest_.partitions()) {
- if (!ProcessPartition(update)) {
- return false;
- }
- writer_ = nullptr;
- source_image_.reset();
- }
- return true;
-}
-
-bool PayloadConverter::OpenSourceTargetFiles() {
- if (FLAGS_source_tf.empty()) {
- return true;
- }
-
- source_tf_fd_.reset(open(FLAGS_source_tf.c_str(), O_RDONLY));
- if (source_tf_fd_ < 0) {
- LOG(ERROR) << "open failed: " << FLAGS_source_tf;
- return false;
- }
-
- struct stat s;
- if (fstat(source_tf_fd_.get(), &s) < 0) {
- LOG(ERROR) << "fstat failed: " << FLAGS_source_tf;
- return false;
- }
- if (S_ISDIR(s.st_mode)) {
- return true;
- }
-
- // Otherwise, assume it's a zip file.
- ZipArchiveHandle handle;
- if (OpenArchiveFd(source_tf_fd_.get(), FLAGS_source_tf.c_str(), &handle, false)) {
- LOG(ERROR) << "Could not open " << FLAGS_source_tf << " as a zip archive.";
- return false;
- }
- source_tf_zip_.reset(handle);
- return true;
-}
-
-bool PayloadConverter::ProcessPartition(const PartitionUpdate& update) {
- auto partition_name = update.partition_name();
- if (dap_.find(partition_name) == dap_.end()) {
- // Skip non-DAP partitions.
- return true;
- }
-
- auto path = out_dir_ + "/" + partition_name + ".cow";
- unique_fd fd(open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
- if (fd < 0) {
- PLOG(ERROR) << "open failed: " << path;
- return false;
- }
-
- CowOptions options;
- options.block_size = kBlockSize;
- options.compression = FLAGS_compression;
- options.cluster_ops = FLAGS_cluster_ops;
-
- writer_ = std::make_unique<CowWriter>(options);
- if (!writer_->Initialize(std::move(fd))) {
- LOG(ERROR) << "Unable to initialize COW writer";
- return false;
- }
-
- partition_name_ = partition_name;
-
- for (const auto& op : update.operations()) {
- if (!ProcessOperation(op)) {
- return false;
- }
- }
-
- if (!writer_->Finalize()) {
- LOG(ERROR) << "Unable to finalize COW for " << partition_name;
- return false;
- }
- return true;
-}
-
-bool PayloadConverter::ProcessOperation(const InstallOperation& op) {
- switch (op.type()) {
- case InstallOperation::SOURCE_COPY:
- return ProcessCopy(op);
- case InstallOperation::BROTLI_BSDIFF:
- case InstallOperation::PUFFDIFF:
- return ProcessDiff(op);
- case InstallOperation::REPLACE:
- case InstallOperation::REPLACE_XZ:
- case InstallOperation::REPLACE_BZ:
- return ProcessReplace(op);
- case InstallOperation::ZERO:
- return ProcessZero(op);
- default:
- LOG(ERROR) << "Unsupported op: " << (int)op.type();
- return false;
- }
- return true;
-}
-
-bool PayloadConverter::ProcessZero(const InstallOperation& op) {
- for (const auto& extent : op.dst_extents()) {
- if (!writer_->AddZeroBlocks(extent.start_block(), extent.num_blocks())) {
- LOG(ERROR) << "Could not add zero operation";
- return false;
- }
- }
- return true;
-}
-
-template <typename T>
-static uint64_t SizeOfAllExtents(const T& extents) {
- uint64_t total = 0;
- for (const auto& extent : extents) {
- total += extent.num_blocks() * kBlockSize;
- }
- return total;
-}
-
-class PuffInputStream final : public puffin::StreamInterface {
- public:
- PuffInputStream(uint8_t* buffer, size_t length) : buffer_(buffer), length_(length), pos_(0) {}
-
- bool GetSize(uint64_t* size) const override {
- *size = length_;
- return true;
- }
- bool GetOffset(uint64_t* offset) const override {
- *offset = pos_;
- return true;
- }
- bool Seek(uint64_t offset) override {
- if (offset > length_) return false;
- pos_ = offset;
- return true;
- }
- bool Read(void* buffer, size_t length) override {
- if (length_ - pos_ < length) return false;
- memcpy(buffer, buffer_ + pos_, length);
- pos_ += length;
- return true;
- }
- bool Write(const void*, size_t) override { return false; }
- bool Close() override { return true; }
-
- private:
- uint8_t* buffer_;
- size_t length_;
- size_t pos_;
-};
-
-class PuffOutputStream final : public puffin::StreamInterface {
- public:
- PuffOutputStream(std::vector<uint8_t>& stream) : stream_(stream), pos_(0) {}
-
- bool GetSize(uint64_t* size) const override {
- *size = stream_.size();
- return true;
- }
- bool GetOffset(uint64_t* offset) const override {
- *offset = pos_;
- return true;
- }
- bool Seek(uint64_t offset) override {
- if (offset > stream_.size()) {
- return false;
- }
- pos_ = offset;
- return true;
- }
- bool Read(void* buffer, size_t length) override {
- if (stream_.size() - pos_ < length) {
- return false;
- }
- memcpy(buffer, &stream_[0] + pos_, length);
- pos_ += length;
- return true;
- }
- bool Write(const void* buffer, size_t length) override {
- auto remaining = stream_.size() - pos_;
- if (remaining < length) {
- stream_.resize(stream_.size() + (length - remaining));
- }
- memcpy(&stream_[0] + pos_, buffer, length);
- pos_ += length;
- return true;
- }
- bool Close() override { return true; }
-
- private:
- std::vector<uint8_t>& stream_;
- size_t pos_;
-};
-
-bool PayloadConverter::ProcessDiff(const InstallOperation& op) {
- auto source_image = OpenSourceImage();
- if (source_image < 0) {
- return false;
- }
-
- uint64_t src_length = SizeOfAllExtents(op.src_extents());
- auto src = std::make_unique<uint8_t[]>(src_length);
- size_t src_pos = 0;
-
- // Read source bytes.
- for (const auto& extent : op.src_extents()) {
- uint64_t offset = extent.start_block() * kBlockSize;
- if (lseek(source_image.get(), offset, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek source image failed";
- return false;
- }
-
- uint64_t size = extent.num_blocks() * kBlockSize;
- CHECK(src_length - src_pos >= size);
- if (!android::base::ReadFully(source_image, src.get() + src_pos, size)) {
- PLOG(ERROR) << "read source image failed";
- return false;
- }
- src_pos += size;
- }
- CHECK(src_pos == src_length);
-
- // Read patch bytes.
- auto patch = std::make_unique<uint8_t[]>(op.data_length());
- if (lseek(in_fd_.get(), payload_offset_ + op.data_offset(), SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek payload failed";
- return false;
- }
- if (!android::base::ReadFully(in_fd_, patch.get(), op.data_length())) {
- PLOG(ERROR) << "read payload failed";
- return false;
- }
-
- std::vector<uint8_t> dest(SizeOfAllExtents(op.dst_extents()));
-
- // Apply the diff.
- if (op.type() == InstallOperation::BROTLI_BSDIFF) {
- size_t dest_pos = 0;
- auto sink = [&](const uint8_t* data, size_t length) -> size_t {
- CHECK(dest.size() - dest_pos >= length);
- memcpy(&dest[dest_pos], data, length);
- dest_pos += length;
- return length;
- };
- if (int rv = bsdiff::bspatch(src.get(), src_pos, patch.get(), op.data_length(), sink)) {
- LOG(ERROR) << "bspatch failed, error code " << rv;
- return false;
- }
- } else if (op.type() == InstallOperation::PUFFDIFF) {
- auto src_stream = std::make_unique<PuffInputStream>(src.get(), src_length);
- auto dest_stream = std::make_unique<PuffOutputStream>(dest);
- bool ok = PuffPatch(std::move(src_stream), std::move(dest_stream), patch.get(),
- op.data_length());
- if (!ok) {
- LOG(ERROR) << "puffdiff operation failed to apply";
- return false;
- }
- } else {
- LOG(ERROR) << "unsupported diff operation: " << op.type();
- return false;
- }
-
- // Write the final blocks to the COW.
- size_t dest_pos = 0;
- for (const auto& extent : op.dst_extents()) {
- uint64_t size = extent.num_blocks() * kBlockSize;
- CHECK(dest.size() - dest_pos >= size);
-
- if (!writer_->AddRawBlocks(extent.start_block(), &dest[dest_pos], size)) {
- return false;
- }
- dest_pos += size;
- }
- return true;
-}
-
-borrowed_fd PayloadConverter::OpenSourceImage() {
- if (source_image_ >= 0) {
- return source_image_;
- }
-
- unique_fd unzip_fd;
-
- auto local_path = "IMAGES/" + partition_name_ + ".img";
- if (source_tf_zip_) {
- {
- TemporaryFile tmp;
- if (tmp.fd < 0) {
- PLOG(ERROR) << "mkstemp failed";
- return -1;
- }
- unzip_fd.reset(tmp.release());
- }
-
- ZipEntry64 entry;
- if (FindEntry(source_tf_zip_.get(), local_path, &entry)) {
- LOG(ERROR) << "not found in archive: " << local_path;
- return -1;
- }
- if (ExtractEntryToFile(source_tf_zip_.get(), &entry, unzip_fd.get())) {
- LOG(ERROR) << "could not extract " << local_path;
- return -1;
- }
- if (lseek(unzip_fd.get(), 0, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek failed";
- return -1;
- }
- } else if (source_tf_fd_ >= 0) {
- unzip_fd.reset(openat(source_tf_fd_.get(), local_path.c_str(), O_RDONLY));
- if (unzip_fd < 0) {
- PLOG(ERROR) << "open failed: " << FLAGS_source_tf << "/" << local_path;
- return -1;
- }
- } else {
- LOG(ERROR) << "No source target files package was specified; need -source_tf";
- return -1;
- }
-
- std::unique_ptr<struct sparse_file, decltype(&sparse_file_destroy)> s(
- sparse_file_import(unzip_fd.get(), false, false), &sparse_file_destroy);
- if (s) {
- TemporaryFile tmp;
- if (tmp.fd < 0) {
- PLOG(ERROR) << "mkstemp failed";
- return -1;
- }
- if (sparse_file_write(s.get(), tmp.fd, false, false, false) < 0) {
- LOG(ERROR) << "sparse_file_write failed";
- return -1;
- }
- source_image_.reset(tmp.release());
- } else {
- source_image_ = std::move(unzip_fd);
- }
- return source_image_;
-}
-
-template <typename ContainerType>
-class ExtentIter final {
- public:
- ExtentIter(const ContainerType& container)
- : iter_(container.cbegin()), end_(container.cend()), dst_index_(0) {}
-
- bool GetNext(uint64_t* block) {
- while (iter_ != end_) {
- if (dst_index_ < iter_->num_blocks()) {
- break;
- }
- iter_++;
- dst_index_ = 0;
- }
- if (iter_ == end_) {
- return false;
- }
- *block = iter_->start_block() + dst_index_;
- dst_index_++;
- return true;
- }
-
- private:
- typename ContainerType::const_iterator iter_;
- typename ContainerType::const_iterator end_;
- uint64_t dst_index_;
-};
-
-bool PayloadConverter::ProcessCopy(const InstallOperation& op) {
- ExtentIter dst_blocks(op.dst_extents());
-
- for (const auto& extent : op.src_extents()) {
- for (uint64_t i = 0; i < extent.num_blocks(); i++) {
- uint64_t src_block = extent.start_block() + i;
- uint64_t dst_block;
- if (!dst_blocks.GetNext(&dst_block)) {
- LOG(ERROR) << "SOURCE_COPY contained mismatching extents";
- return false;
- }
- if (src_block == dst_block) continue;
- if (!writer_->AddCopy(dst_block, src_block)) {
- LOG(ERROR) << "Could not add copy operation";
- return false;
- }
- }
- }
- return true;
-}
-
-bool PayloadConverter::ProcessReplace(const InstallOperation& op) {
- auto buffer_size = op.data_length();
- auto buffer = std::make_unique<char[]>(buffer_size);
- uint64_t offs = payload_offset_ + op.data_offset();
- if (lseek(in_fd_.get(), offs, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek " << offs << " failed";
- return false;
- }
- if (!android::base::ReadFully(in_fd_, buffer.get(), buffer_size)) {
- PLOG(ERROR) << "read " << buffer_size << " bytes from offset " << offs << "failed";
- return false;
- }
-
- uint64_t dst_size = 0;
- for (const auto& extent : op.dst_extents()) {
- dst_size += extent.num_blocks() * kBlockSize;
- }
-
- if (op.type() == InstallOperation::REPLACE_BZ) {
- auto tmp = std::make_unique<char[]>(dst_size);
-
- uint32_t actual_size;
- if (dst_size > std::numeric_limits<typeof(actual_size)>::max()) {
- LOG(ERROR) << "too many bytes to decompress: " << dst_size;
- return false;
- }
- actual_size = static_cast<uint32_t>(dst_size);
-
- auto rv = BZ2_bzBuffToBuffDecompress(tmp.get(), &actual_size, buffer.get(), buffer_size, 0,
- 0);
- if (rv) {
- LOG(ERROR) << "bz2 decompress failed: " << rv;
- return false;
- }
- if (actual_size != dst_size) {
- LOG(ERROR) << "bz2 returned " << actual_size << " bytes, expected " << dst_size;
- return false;
- }
- buffer = std::move(tmp);
- buffer_size = dst_size;
- } else if (op.type() == InstallOperation::REPLACE_XZ) {
- constexpr uint32_t kXzMaxDictSize = 64 * 1024 * 1024;
-
- if (dst_size > std::numeric_limits<size_t>::max()) {
- LOG(ERROR) << "too many bytes to decompress: " << dst_size;
- return false;
- }
-
- std::unique_ptr<struct xz_dec, decltype(&xz_dec_end)> s(
- xz_dec_init(XZ_DYNALLOC, kXzMaxDictSize), xz_dec_end);
- if (!s) {
- LOG(ERROR) << "xz_dec_init failed";
- return false;
- }
-
- auto tmp = std::make_unique<char[]>(dst_size);
-
- struct xz_buf args;
- args.in = reinterpret_cast<const uint8_t*>(buffer.get());
- args.in_pos = 0;
- args.in_size = buffer_size;
- args.out = reinterpret_cast<uint8_t*>(tmp.get());
- args.out_pos = 0;
- args.out_size = dst_size;
-
- auto rv = xz_dec_run(s.get(), &args);
- if (rv != XZ_STREAM_END) {
- LOG(ERROR) << "xz decompress failed: " << (int)rv;
- return false;
- }
- buffer = std::move(tmp);
- buffer_size = dst_size;
- }
-
- uint64_t buffer_pos = 0;
- for (const auto& extent : op.dst_extents()) {
- uint64_t extent_size = extent.num_blocks() * kBlockSize;
- if (buffer_size - buffer_pos < extent_size) {
- LOG(ERROR) << "replace op ran out of input buffer";
- return false;
- }
- if (!writer_->AddRawBlocks(extent.start_block(), buffer.get() + buffer_pos, extent_size)) {
- LOG(ERROR) << "failed to add raw blocks from replace op";
- return false;
- }
- buffer_pos += extent_size;
- }
- return true;
-}
-
-bool PayloadConverter::OpenPayload() {
- in_fd_.reset(open(in_file_.c_str(), O_RDONLY));
- if (in_fd_ < 0) {
- PLOG(ERROR) << "open " << in_file_;
- return false;
- }
-
- char magic[4];
- if (!android::base::ReadFully(in_fd_, magic, sizeof(magic))) {
- PLOG(ERROR) << "read magic";
- return false;
- }
- if (std::string(magic, sizeof(magic)) != "CrAU") {
- LOG(ERROR) << "Invalid magic in " << in_file_;
- return false;
- }
-
- uint64_t version;
- uint64_t manifest_size;
- uint32_t manifest_signature_size = 0;
- if (!android::base::ReadFully(in_fd_, &version, sizeof(version))) {
- PLOG(ERROR) << "read version";
- return false;
- }
- version = ToLittleEndian(version);
- if (version < 2) {
- LOG(ERROR) << "Only payload version 2 or higher is supported.";
- return false;
- }
-
- if (!android::base::ReadFully(in_fd_, &manifest_size, sizeof(manifest_size))) {
- PLOG(ERROR) << "read manifest_size";
- return false;
- }
- manifest_size = ToLittleEndian(manifest_size);
- if (!android::base::ReadFully(in_fd_, &manifest_signature_size,
- sizeof(manifest_signature_size))) {
- PLOG(ERROR) << "read manifest_signature_size";
- return false;
- }
- manifest_signature_size = ntohl(manifest_signature_size);
-
- auto manifest = std::make_unique<uint8_t[]>(manifest_size);
- if (!android::base::ReadFully(in_fd_, manifest.get(), manifest_size)) {
- PLOG(ERROR) << "read manifest";
- return false;
- }
-
- // Skip past manifest signature.
- auto offs = lseek(in_fd_, manifest_signature_size, SEEK_CUR);
- if (offs < 0) {
- PLOG(ERROR) << "lseek failed";
- return false;
- }
- payload_offset_ = offs;
-
- if (!manifest_.ParseFromArray(manifest.get(), manifest_size)) {
- LOG(ERROR) << "could not parse manifest";
- return false;
- }
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
-
-int main(int argc, char** argv) {
- android::base::InitLogging(argv, android::snapshot::MyLogger);
- gflags::SetUsageMessage("Convert OTA payload to a Virtual A/B COW");
- int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, false);
-
- xz_crc32_init();
-
- if (argc - arg_start != 2) {
- std::cerr << "Usage: [options] <payload.bin> <out-dir>\n";
- return 1;
- }
-
- android::snapshot::PayloadConverter pc(argv[arg_start], argv[arg_start + 1]);
- return pc.Run() ? 0 : 1;
-}
diff --git a/fs_mgr/libsnapshot/power_test.cpp b/fs_mgr/libsnapshot/power_test.cpp
deleted file mode 100644
index 4d2548a..0000000
--- a/fs_mgr/libsnapshot/power_test.cpp
+++ /dev/null
@@ -1,559 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <iostream>
-#include <random>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/parsedouble.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <ext4_utils/ext4_utils.h>
-#include <fstab/fstab.h>
-#include <libdm/dm.h>
-#include <libfiemap/image_manager.h>
-
-using namespace std::chrono_literals;
-using namespace std::string_literals;
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-using android::dm::DeviceMapper;
-using android::dm::DmDeviceState;
-using android::dm::DmTable;
-using android::dm::DmTargetSnapshot;
-using android::dm::SnapshotStorageMode;
-using android::fiemap::ImageManager;
-using android::fs_mgr::Fstab;
-
-namespace android {
-namespace snapshot {
-
-static void usage() {
- std::cerr << "Usage:\n";
- std::cerr << " create <orig-payload> <new-payload>\n";
- std::cerr << "\n";
- std::cerr << " Create a snapshot device containing the contents of\n";
- std::cerr << " orig-payload, and then write the contents of new-payload.\n";
- std::cerr << " The original files are not modified.\n";
- std::cerr << "\n";
- std::cerr << " merge <fail-rate>\n";
- std::cerr << "\n";
- std::cerr << " Merge the snapshot previously started by create, and wait\n";
- std::cerr << " for it to complete. Once done, it is compared to the\n";
- std::cerr << " new-payload for consistency. The original files are not \n";
- std::cerr << " modified. If a fail-rate is passed (as a fraction between 0\n";
- std::cerr << " and 100), every 10ms the device has that percent change of\n";
- std::cerr << " injecting a kernel crash.\n";
- std::cerr << "\n";
- std::cerr << " check <new-payload>\n";
- std::cerr << " Verify that all artifacts are correct after a merge\n";
- std::cerr << " completes.\n";
- std::cerr << "\n";
- std::cerr << " cleanup\n";
- std::cerr << " Remove all ImageManager artifacts from create/merge.\n";
-}
-
-class PowerTest final {
- public:
- PowerTest();
- bool Run(int argc, char** argv);
-
- private:
- bool OpenImageManager();
- bool Create(int argc, char** argv);
- bool Merge(int argc, char** argv);
- bool Check(int argc, char** argv);
- bool Cleanup();
- bool CleanupImage(const std::string& name);
- bool SetupImages(const std::string& first_file, borrowed_fd second_fd);
- bool MapImages();
- bool MapSnapshot(SnapshotStorageMode mode);
- bool GetMergeStatus(DmTargetSnapshot::Status* status);
-
- static constexpr char kSnapshotName[] = "snapshot-power-test";
- static constexpr char kSnapshotImageName[] = "snapshot-power-test-image";
- static constexpr char kSnapshotCowName[] = "snapshot-power-test-cow";
-
- DeviceMapper& dm_;
- std::unique_ptr<ImageManager> images_;
- std::string image_path_;
- std::string cow_path_;
- std::string snapshot_path_;
-};
-
-PowerTest::PowerTest() : dm_(DeviceMapper::Instance()) {}
-
-bool PowerTest::Run([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
- if (!OpenImageManager()) {
- return false;
- }
-
- if (argc < 2) {
- usage();
- return false;
- }
- if (argv[1] == "create"s) {
- return Create(argc, argv);
- } else if (argv[1] == "merge"s) {
- return Merge(argc, argv);
- } else if (argv[1] == "check"s) {
- return Check(argc, argv);
- } else if (argv[1] == "cleanup"s) {
- return Cleanup();
- } else {
- usage();
- return false;
- }
-}
-
-bool PowerTest::OpenImageManager() {
- std::vector<std::string> dirs = {
- "/data/gsi/test",
- "/metadata/gsi/test",
- };
- for (const auto& dir : dirs) {
- if (mkdir(dir.c_str(), 0700) && errno != EEXIST) {
- std::cerr << "mkdir " << dir << ": " << strerror(errno) << "\n";
- return false;
- }
- }
-
- images_ = ImageManager::Open("/metadata/gsi/test", "/data/gsi/test");
- if (!images_) {
- std::cerr << "Could not open ImageManager\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::Create(int argc, char** argv) {
- if (argc < 4) {
- usage();
- return false;
- }
-
- std::string first = argv[2];
- std::string second = argv[3];
-
- unique_fd second_fd(open(second.c_str(), O_RDONLY));
- if (second_fd < 0) {
- std::cerr << "open " << second << ": " << strerror(errno) << "\n";
- return false;
- }
-
- if (!Cleanup()) {
- return false;
- }
- if (!SetupImages(first, second_fd)) {
- return false;
- }
- if (!MapSnapshot(SnapshotStorageMode::Persistent)) {
- return false;
- }
-
- struct stat s;
- if (fstat(second_fd, &s)) {
- std::cerr << "fstat " << second << ": " << strerror(errno) << "\n";
- return false;
- }
-
- unique_fd snap_fd(open(snapshot_path_.c_str(), O_WRONLY));
- if (snap_fd < 0) {
- std::cerr << "open " << snapshot_path_ << ": " << strerror(errno) << "\n";
- return false;
- }
-
- uint8_t chunk[4096];
- uint64_t written = 0;
- while (written < s.st_size) {
- uint64_t remaining = s.st_size - written;
- size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
- if (!android::base::ReadFully(second_fd, chunk, bytes)) {
- std::cerr << "read " << second << ": " << strerror(errno) << "\n";
- return false;
- }
- if (!android::base::WriteFully(snap_fd, chunk, bytes)) {
- std::cerr << "write " << snapshot_path_ << ": " << strerror(errno) << "\n";
- return false;
- }
- written += bytes;
- }
- if (fsync(snap_fd)) {
- std::cerr << "fsync: " << strerror(errno) << "\n";
- return false;
- }
-
- sync();
-
- snap_fd = {};
- if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
- std::cerr << "could not delete dm device " << kSnapshotName << "\n";
- return false;
- }
- if (!images_->UnmapImageIfExists(kSnapshotImageName)) {
- std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
- return false;
- }
- if (!images_->UnmapImageIfExists(kSnapshotCowName)) {
- std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::Cleanup() {
- if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
- std::cerr << "could not delete dm device " << kSnapshotName << "\n";
- return false;
- }
- if (!CleanupImage(kSnapshotImageName) || !CleanupImage(kSnapshotCowName)) {
- return false;
- }
- return true;
-}
-
-bool PowerTest::CleanupImage(const std::string& name) {
- if (!images_->UnmapImageIfExists(name)) {
- std::cerr << "failed to unmap " << name << "\n";
- return false;
- }
- if (images_->BackingImageExists(name) && !images_->DeleteBackingImage(name)) {
- std::cerr << "failed to delete " << name << "\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::SetupImages(const std::string& first, borrowed_fd second_fd) {
- unique_fd first_fd(open(first.c_str(), O_RDONLY));
- if (first_fd < 0) {
- std::cerr << "open " << first << ": " << strerror(errno) << "\n";
- return false;
- }
-
- struct stat s1, s2;
- if (fstat(first_fd.get(), &s1)) {
- std::cerr << "first stat: " << strerror(errno) << "\n";
- return false;
- }
- if (fstat(second_fd.get(), &s2)) {
- std::cerr << "second stat: " << strerror(errno) << "\n";
- return false;
- }
-
- // Pick the bigger size of both images, rounding up to the nearest block.
- uint64_t s1_size = (s1.st_size + 4095) & ~uint64_t(4095);
- uint64_t s2_size = (s2.st_size + 4095) & ~uint64_t(4095);
- uint64_t image_size = std::max(s1_size, s2_size) + (1024 * 1024 * 128);
- if (!images_->CreateBackingImage(kSnapshotImageName, image_size, 0, nullptr)) {
- std::cerr << "failed to create " << kSnapshotImageName << "\n";
- return false;
- }
- // Use the same size for the cow.
- if (!images_->CreateBackingImage(kSnapshotCowName, image_size, 0, nullptr)) {
- std::cerr << "failed to create " << kSnapshotCowName << "\n";
- return false;
- }
- if (!MapImages()) {
- return false;
- }
-
- unique_fd image_fd(open(image_path_.c_str(), O_WRONLY));
- if (image_fd < 0) {
- std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
- return false;
- }
-
- uint8_t chunk[4096];
- uint64_t written = 0;
- while (written < s1.st_size) {
- uint64_t remaining = s1.st_size - written;
- size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
- if (!android::base::ReadFully(first_fd, chunk, bytes)) {
- std::cerr << "read: " << strerror(errno) << "\n";
- return false;
- }
- if (!android::base::WriteFully(image_fd, chunk, bytes)) {
- std::cerr << "write: " << strerror(errno) << "\n";
- return false;
- }
- written += bytes;
- }
- if (fsync(image_fd)) {
- std::cerr << "fsync: " << strerror(errno) << "\n";
- return false;
- }
-
- // Zero the first block of the COW.
- unique_fd cow_fd(open(cow_path_.c_str(), O_WRONLY));
- if (cow_fd < 0) {
- std::cerr << "open: " << cow_path_ << ": " << strerror(errno) << "\n";
- return false;
- }
-
- memset(chunk, 0, sizeof(chunk));
- if (!android::base::WriteFully(cow_fd, chunk, sizeof(chunk))) {
- std::cerr << "read: " << strerror(errno) << "\n";
- return false;
- }
- if (fsync(cow_fd)) {
- std::cerr << "fsync: " << strerror(errno) << "\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::MapImages() {
- if (!images_->MapImageDevice(kSnapshotImageName, 10s, &image_path_)) {
- std::cerr << "failed to map " << kSnapshotImageName << "\n";
- return false;
- }
- if (!images_->MapImageDevice(kSnapshotCowName, 10s, &cow_path_)) {
- std::cerr << "failed to map " << kSnapshotCowName << "\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::MapSnapshot(SnapshotStorageMode mode) {
- uint64_t sectors;
- {
- unique_fd fd(open(image_path_.c_str(), O_RDONLY));
- if (fd < 0) {
- std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
- return false;
- }
- sectors = get_block_device_size(fd) / 512;
- }
-
- DmTable table;
- table.Emplace<DmTargetSnapshot>(0, sectors, image_path_, cow_path_, mode, 8);
- if (!dm_.CreateDevice(kSnapshotName, table, &snapshot_path_, 10s)) {
- std::cerr << "failed to create snapshot device\n";
- return false;
- }
- return true;
-}
-
-bool PowerTest::GetMergeStatus(DmTargetSnapshot::Status* status) {
- std::vector<DeviceMapper::TargetInfo> targets;
- if (!dm_.GetTableStatus(kSnapshotName, &targets)) {
- std::cerr << "failed to get merge status\n";
- return false;
- }
- if (targets.size() != 1) {
- std::cerr << "merge device has wrong number of targets\n";
- return false;
- }
- if (!DmTargetSnapshot::ParseStatusText(targets[0].data, status)) {
- std::cerr << "could not parse merge target status text\n";
- return false;
- }
- return true;
-}
-
-static std::string GetUserdataBlockDeviceName() {
- Fstab fstab;
- if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
- return {};
- }
-
- auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data");
- if (!entry) {
- return {};
- }
-
- auto prefix = "/dev/block/"s;
- if (!android::base::StartsWith(entry->blk_device, prefix)) {
- return {};
- }
- return entry->blk_device.substr(prefix.size());
-}
-
-bool PowerTest::Merge(int argc, char** argv) {
- // Start an f2fs GC to really stress things. :TODO: figure out data device
- auto userdata_dev = GetUserdataBlockDeviceName();
- if (userdata_dev.empty()) {
- std::cerr << "could not locate userdata block device\n";
- return false;
- }
-
- auto cmd =
- android::base::StringPrintf("echo 1 > /sys/fs/f2fs/%s/gc_urgent", userdata_dev.c_str());
- system(cmd.c_str());
-
- if (dm_.GetState(kSnapshotName) == DmDeviceState::INVALID) {
- if (!MapImages()) {
- return false;
- }
- if (!MapSnapshot(SnapshotStorageMode::Merge)) {
- return false;
- }
- }
-
- std::random_device r;
- std::default_random_engine re(r());
- std::uniform_real_distribution<double> dist(0.0, 100.0);
-
- std::optional<double> failure_rate;
- if (argc >= 3) {
- double d;
- if (!android::base::ParseDouble(argv[2], &d)) {
- std::cerr << "Could not parse failure rate as double: " << argv[2] << "\n";
- return false;
- }
- failure_rate = d;
- }
-
- while (true) {
- DmTargetSnapshot::Status status;
- if (!GetMergeStatus(&status)) {
- return false;
- }
- if (!status.error.empty()) {
- std::cerr << "merge reported error: " << status.error << "\n";
- return false;
- }
- if (status.sectors_allocated == status.metadata_sectors) {
- break;
- }
-
- std::cerr << status.sectors_allocated << " / " << status.metadata_sectors << "\n";
-
- if (failure_rate && *failure_rate >= dist(re)) {
- system("echo 1 > /proc/sys/kernel/sysrq");
- system("echo c > /proc/sysrq-trigger");
- }
-
- std::this_thread::sleep_for(10ms);
- }
-
- std::cout << "Merge completed.\n";
- return true;
-}
-
-bool PowerTest::Check([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
- if (argc < 3) {
- std::cerr << "Expected argument: <new-image-path>\n";
- return false;
- }
- std::string md_path, image_path;
- std::string canonical_path = argv[2];
-
- if (!dm_.GetDmDevicePathByName(kSnapshotName, &md_path)) {
- std::cerr << "could not get dm-path for merge device\n";
- return false;
- }
- if (!images_->GetMappedImageDevice(kSnapshotImageName, &image_path)) {
- std::cerr << "could not get image path\n";
- return false;
- }
-
- unique_fd md_fd(open(md_path.c_str(), O_RDONLY));
- if (md_fd < 0) {
- std::cerr << "open: " << md_path << ": " << strerror(errno) << "\n";
- return false;
- }
- unique_fd image_fd(open(image_path.c_str(), O_RDONLY));
- if (image_fd < 0) {
- std::cerr << "open: " << image_path << ": " << strerror(errno) << "\n";
- return false;
- }
- unique_fd canonical_fd(open(canonical_path.c_str(), O_RDONLY));
- if (canonical_fd < 0) {
- std::cerr << "open: " << canonical_path << ": " << strerror(errno) << "\n";
- return false;
- }
-
- struct stat s;
- if (fstat(canonical_fd, &s)) {
- std::cerr << "fstat: " << canonical_path << ": " << strerror(errno) << "\n";
- return false;
- }
- uint64_t canonical_size = s.st_size;
- uint64_t md_size = get_block_device_size(md_fd);
- uint64_t image_size = get_block_device_size(image_fd);
- if (image_size != md_size) {
- std::cerr << "image size does not match merge device size\n";
- return false;
- }
- if (canonical_size > image_size) {
- std::cerr << "canonical size " << canonical_size << " is greater than image size "
- << image_size << "\n";
- return false;
- }
-
- constexpr size_t kBlockSize = 4096;
- uint8_t canonical_buffer[kBlockSize];
- uint8_t image_buffer[kBlockSize];
- uint8_t md_buffer[kBlockSize];
-
- uint64_t remaining = canonical_size;
- uint64_t blockno = 0;
- while (remaining) {
- size_t bytes = (size_t)std::min((uint64_t)kBlockSize, remaining);
- if (!android::base::ReadFully(canonical_fd, canonical_buffer, bytes)) {
- std::cerr << "read: " << canonical_buffer << ": " << strerror(errno) << "\n";
- return false;
- }
- if (!android::base::ReadFully(image_fd, image_buffer, bytes)) {
- std::cerr << "read: " << image_buffer << ": " << strerror(errno) << "\n";
- return false;
- }
- if (!android::base::ReadFully(md_fd, md_buffer, bytes)) {
- std::cerr << "read: " << md_buffer << ": " << strerror(errno) << "\n";
- return false;
- }
- if (memcmp(canonical_buffer, image_buffer, bytes)) {
- std::cerr << "canonical and image differ at block " << blockno << "\n";
- return false;
- }
- if (memcmp(canonical_buffer, md_buffer, bytes)) {
- std::cerr << "canonical and image differ at block " << blockno << "\n";
- return false;
- }
-
- remaining -= bytes;
- blockno++;
- }
-
- std::cout << "Images all match.\n";
- return true;
-}
-
-} // namespace snapshot
-} // namespace android
-
-int main(int argc, char** argv) {
- android::snapshot::PowerTest test;
-
- if (!test.Run(argc, argv)) {
- std::cerr << "Unexpected error running test." << std::endl;
- return 1;
- }
- fflush(stdout);
- return 0;
-}
diff --git a/fs_mgr/libsnapshot/run_power_test.sh b/fs_mgr/libsnapshot/run_power_test.sh
deleted file mode 100755
index dc03dc9..0000000
--- a/fs_mgr/libsnapshot/run_power_test.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-set -e
-
-if [ -z "$FAIL_RATE" ]; then
- FAIL_RATE=5.0
-fi
-if [ ! -z "$ANDROID_SERIAL" ]; then
- DEVICE_ARGS=-s $ANDROID_SERIAL
-else
- DEVICE_ARGS=
-fi
-
-TEST_BIN=/data/nativetest64/snapshot_power_test/snapshot_power_test
-
-while :
-do
- adb $DEVICE_ARGS wait-for-device
- adb $DEVICE_ARGS root
- adb $DEVICE_ARGS shell rm $TEST_BIN
- adb $DEVICE_ARGS sync data
- set +e
- output=$(adb $DEVICE_ARGS shell $TEST_BIN merge $FAIL_RATE 2>&1)
- set -e
- if [[ "$output" == *"Merge completed"* ]]; then
- echo "Merge completed."
- break
- fi
- if [[ "$output" == *"Unexpected error"* ]]; then
- echo "Unexpected error."
- exit 1
- fi
-done
-
-adb $DEVICE_ARGS shell $TEST_BIN check $1
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 7fcaac5..1e03683 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -164,7 +164,7 @@
}
cc_test {
- name: "cow_snapuserd_test",
+ name: "snapuserd_test_legacy",
defaults: [
"fs_mgr_defaults",
"libsnapshot_cow_defaults",
@@ -216,16 +216,17 @@
],
static_libs: [
"libbrotli",
+ "libcutils_sockets",
+ "libdm",
+ "libext4_utils",
+ "libfs_mgr",
+ "libgflags",
"libgtest",
"libsnapshot_cow",
"libsnapshot_snapuserd",
- "libcutils_sockets",
- "libz",
- "libfs_mgr",
- "libdm",
- "libext4_utils",
+ "libsnapuserd",
"liburing",
- "libgflags",
+ "libz",
],
include_dirs: ["bionic/libc/kernel"],
header_libs: [
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
index 484a9c4..3c4ab2e 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
@@ -1152,35 +1152,6 @@
}
}
-TEST(Snapuserd_Test, xor_buffer) {
- std::string data = "Test String";
- std::string jumbled = {0x0C, 0x2A, 0x21, 0x54, 0x73, 0x27, 0x06, 0x1B, 0x07, 0x09, 0x46};
- std::string result = "XOR String!";
-
- BufferSink sink;
- XorSink xor_sink;
- sink.Initialize(sizeof(struct dm_user_header) + 10);
- int buffsize = 5;
- xor_sink.Initialize(&sink, buffsize);
-
- void* buff = sink.GetPayloadBuffer(data.length());
- memcpy(buff, data.data(), data.length());
-
- size_t actual;
- size_t count = 0;
- while (count < data.length()) {
- void* xor_buff = xor_sink.GetBuffer(10, &actual);
- ASSERT_EQ(actual, buffsize);
- ASSERT_NE(xor_buff, nullptr);
- memcpy(xor_buff, jumbled.data() + count, buffsize);
- xor_sink.ReturnData(xor_buff, actual);
- count += actual;
- }
-
- std::string answer = reinterpret_cast<char*>(sink.GetPayloadBufPtr());
- ASSERT_EQ(answer, result);
-}
-
TEST(Snapuserd_Test, Snapshot_Metadata) {
CowSnapuserdMetadataTest harness;
harness.Setup();
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
index 5f4d706..8926030 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
@@ -350,7 +350,7 @@
CowHeader header;
CowOptions options;
bool metadata_found = false;
- int replace_ops = 0, zero_ops = 0, copy_ops = 0, xor_ops = 0;
+ int replace_ops = 0, zero_ops = 0, copy_ops = 0;
SNAP_LOG(DEBUG) << "ReadMetadata: Parsing cow file";
@@ -515,10 +515,6 @@
//===========================================================
uint64_t block_source = cow_op->source;
uint64_t block_offset = 0;
- if (cow_op->type == kCowXorOp) {
- block_source /= BLOCK_SZ;
- block_offset = cow_op->source % BLOCK_SZ;
- }
if (prev_id.has_value()) {
if (dest_blocks.count(cow_op->new_block) || source_blocks.count(block_source) ||
(block_offset > 0 && source_blocks.count(block_source + 1))) {
@@ -538,7 +534,7 @@
} while (!cowop_rm_iter->Done() && pending_ordered_ops);
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
- SNAP_LOG(DEBUG) << "Batch Merge copy-ops/xor-ops of size: " << vec.size()
+ SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << vec.size()
<< " Area: " << vec_.size() << " Area offset: " << offset
<< " Pending-ordered-ops in this area: " << pending_ordered_ops;
@@ -556,8 +552,6 @@
num_ops += 1;
if (cow_op->type == kCowCopyOp) {
copy_ops++;
- } else { // it->second->type == kCowXorOp
- xor_ops++;
}
if (read_ahead_feature_) {
@@ -629,8 +623,8 @@
SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id
<< " Num Sector: " << ChunkToSector(data_chunk_id)
<< " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops
- << " Copy-ops: " << copy_ops << " Xor-ops: " << xor_ops
- << " Areas: " << vec_.size() << " Num-ops-merged: " << header.num_merge_ops
+ << " Copy-ops: " << copy_ops << " Areas: " << vec_.size()
+ << " Num-ops-merged: " << header.num_merge_ops
<< " Total-data-ops: " << reader_->get_num_total_data_ops();
// Total number of sectors required for creating dm-user device
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
index 47b9b22..beb6004 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
@@ -170,9 +170,8 @@
// Processing COW operations
bool ProcessCowOp(const CowOperation* cow_op);
bool ProcessReplaceOp(const CowOperation* cow_op);
- // Handles Copy and Xor
+ // Handles Copy
bool ProcessCopyOp(const CowOperation* cow_op);
- bool ProcessXorOp(const CowOperation* cow_op);
bool ProcessZeroOp();
bool ReadFromBaseDevice(const CowOperation* cow_op);
@@ -191,7 +190,6 @@
std::unique_ptr<CowReader> reader_;
BufferSink bufsink_;
- XorSink xorsink_;
std::string cow_device_;
std::string backing_store_device_;
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
index c201b23..01123f8 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
@@ -174,10 +174,6 @@
void ReadAheadThread::CheckOverlap(const CowOperation* cow_op) {
uint64_t source_block = cow_op->source;
uint64_t source_offset = 0;
- if (cow_op->type == kCowXorOp) {
- source_block /= BLOCK_SZ;
- source_offset = cow_op->source % BLOCK_SZ;
- }
if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block) ||
(source_offset > 0 && source_blocks_.count(source_block + 1))) {
overlap_ = true;
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
index 0e9f0f1..965af40 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
@@ -116,13 +116,7 @@
offset *= BLOCK_SZ;
}
if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
- std::string op;
- if (cow_op->type == kCowCopyOp)
- op = "Copy-op";
- else {
- op = "Xor-op";
- }
- SNAP_PLOG(ERROR) << op << " failed. Read from backing store: " << backing_store_device_
+ SNAP_PLOG(ERROR) << "Copy op failed. Read from backing store: " << backing_store_device_
<< "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ;
return false;
}
@@ -158,23 +152,6 @@
return true;
}
-bool WorkerThread::ProcessXorOp(const CowOperation* cow_op) {
- if (!GetReadAheadPopulatedBuffer(cow_op)) {
- SNAP_LOG(DEBUG) << " GetReadAheadPopulatedBuffer failed..."
- << " new_block: " << cow_op->new_block;
- if (!ReadFromBaseDevice(cow_op)) {
- return false;
- }
- }
- xorsink_.Reset();
- if (!reader_->ReadData(*cow_op, &xorsink_)) {
- SNAP_LOG(ERROR) << "ProcessXorOp failed for block " << cow_op->new_block;
- return false;
- }
-
- return true;
-}
-
bool WorkerThread::ProcessZeroOp() {
// Zero out the entire block
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
@@ -206,12 +183,8 @@
return ProcessCopyOp(cow_op);
}
- case kCowXorOp: {
- return ProcessXorOp(cow_op);
- }
-
default: {
- SNAP_LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
+ SNAP_LOG(ERROR) << "Unsupported operation-type found: " << cow_op->type;
}
}
return false;
@@ -830,7 +803,6 @@
bool WorkerThread::RunThread() {
InitializeBufsink();
- xorsink_.Initialize(&bufsink_, BLOCK_SZ);
if (!InitializeFds()) {
return false;
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index 0557214..36dad33 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -110,7 +110,7 @@
for (int i = arg_start; i < argc; i++) {
auto parts = android::base::Split(argv[i], ",");
if (parts.size() != 4) {
- LOG(ERROR) << "Malformed message, expected three sub-arguments.";
+ LOG(ERROR) << "Malformed message, expected four sub-arguments.";
return false;
}
auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]);
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
index c5150c4..bdba5c0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -25,6 +25,9 @@
static constexpr uint8_t kMaxMergeThreads = 2;
+HandlerThread::HandlerThread(std::shared_ptr<SnapshotHandler> snapuserd)
+ : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
+
void HandlerThread::FreeResources() {
// Each worker thread holds a reference to snapuserd.
// Clear them so that all the resources
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 2c201ff..25ce0ae 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -433,11 +433,6 @@
struct utsname uts;
unsigned int major, minor;
- if (android::base::GetBoolProperty("snapuserd.test.io_uring.force_disable", false)) {
- SNAP_LOG(INFO) << "io_uring disabled for testing";
- return false;
- }
-
if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
SNAP_LOG(ERROR) << "Could not parse the kernel version from uname. "
<< " io_uring not supported";
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index d87990a..c953f1a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -83,9 +83,6 @@
handlers_->JoinAllThreads();
}
-HandlerThread::HandlerThread(std::shared_ptr<SnapshotHandler> snapuserd)
- : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
-
bool UserSnapshotServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), MSG_NOSIGNAL));
if (ret < 0) {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index 1421403..57f9e7a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -37,9 +37,9 @@
#include <libdm/dm.h>
#include <libdm/loop_control.h>
#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_client.h>
#include <storage_literals/storage_literals.h>
+#include "handler_manager.h"
#include "snapuserd_core.h"
DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
@@ -54,8 +54,6 @@
using namespace android::dm;
using namespace std;
-static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
-
class Tempdevice {
public:
Tempdevice(const std::string& name, const DmTable& table)
@@ -68,15 +66,15 @@
}
~Tempdevice() {
if (valid_) {
- dm_.DeleteDevice(name_);
+ dm_.DeleteDeviceIfExists(name_);
}
}
bool Destroy() {
if (!valid_) {
- return false;
+ return true;
}
valid_ = false;
- return dm_.DeleteDevice(name_);
+ return dm_.DeleteDeviceIfExists(name_);
}
const std::string& path() const { return path_; }
const std::string& name() const { return name_; }
@@ -138,7 +136,6 @@
void SetDeviceControlName();
void InitDaemon();
void CreateDmUserDevice();
- void StartSnapuserdDaemon();
unique_ptr<LoopDevice> base_loop_;
unique_ptr<Tempdevice> dmuser_dev_;
@@ -148,9 +145,9 @@
unique_fd base_fd_;
std::unique_ptr<TemporaryFile> cow_system_;
- std::unique_ptr<SnapuserdClient> client_;
std::unique_ptr<uint8_t[]> orig_buffer_;
std::unique_ptr<uint8_t[]> merged_buffer_;
+ SnapshotHandlerManager handlers_;
bool setup_ok_ = false;
bool merge_ok_ = false;
size_t size_ = 100_MiB;
@@ -180,9 +177,9 @@
ASSERT_TRUE(dmuser_dev_->Destroy());
auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
- ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
+ ASSERT_TRUE(handlers_.DeleteHandler(system_device_ctrl_name_));
ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
- ASSERT_TRUE(client_->DetachSnapuserd());
+ handlers_.TerminateMergeThreads();
}
bool SnapuserdTest::SetupDefault() {
@@ -217,8 +214,6 @@
bool SnapuserdTest::SetupDaemon() {
SetDeviceControlName();
- StartSnapuserdDaemon();
-
CreateDmUserDevice();
InitCowDevice();
InitDaemon();
@@ -228,20 +223,6 @@
return setup_ok_;
}
-void SnapuserdTest::StartSnapuserdDaemon() {
- pid_t pid = fork();
- ASSERT_GE(pid, 0);
- if (pid == 0) {
- std::string arg0 = "/system/bin/snapuserd";
- std::string arg1 = "-socket="s + kSnapuserdSocketTest;
- char* const argv[] = {arg0.data(), arg1.data(), nullptr};
- ASSERT_GE(execv(arg0.c_str(), argv), 0);
- } else {
- client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
- ASSERT_NE(client_, nullptr);
- }
-}
-
void SnapuserdTest::CreateBaseDevice() {
unique_fd rnd_fd;
@@ -606,9 +587,17 @@
}
void SnapuserdTest::InitCowDevice() {
- uint64_t num_sectors = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
- base_loop_->device(), base_loop_->device());
- ASSERT_NE(num_sectors, 0);
+ bool use_iouring = true;
+ if (FLAGS_force_config == "iouring_disabled") {
+ use_iouring = false;
+ }
+
+ auto handler =
+ handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(),
+ base_loop_->device(), 1, use_iouring, false);
+ ASSERT_NE(handler, nullptr);
+ ASSERT_NE(handler->snapuserd(), nullptr);
+ ASSERT_NE(handler->snapuserd()->GetNumSectors(), 0);
}
void SnapuserdTest::SetDeviceControlName() {
@@ -646,13 +635,12 @@
}
void SnapuserdTest::InitDaemon() {
- bool ok = client_->AttachDmUser(system_device_ctrl_name_);
- ASSERT_TRUE(ok);
+ ASSERT_TRUE(handlers_.StartHandler(system_device_ctrl_name_));
}
void SnapuserdTest::CheckMergeCompletion() {
while (true) {
- double percentage = client_->GetMergePercent();
+ double percentage = handlers_.GetMergePercentage();
if ((int)percentage == 100) {
break;
}
@@ -667,8 +655,6 @@
SetDeviceControlName();
- StartSnapuserdDaemon();
-
CreateDmUserDevice();
InitCowDevice();
InitDaemon();
@@ -684,8 +670,7 @@
}
void SnapuserdTest::StartMerge() {
- bool ok = client_->InitiateMerge(system_device_ctrl_name_);
- ASSERT_TRUE(ok);
+ ASSERT_TRUE(handlers_.InitiateMerge(system_device_ctrl_name_));
}
void SnapuserdTest::ValidateMerge() {
@@ -699,7 +684,6 @@
Shutdown();
std::this_thread::sleep_for(500ms);
SetDeviceControlName();
- StartSnapuserdDaemon();
CreateDmUserDevice();
InitCowDevice();
InitDaemon();
@@ -859,20 +843,5 @@
gflags::ParseCommandLineFlags(&argc, &argv, false);
- android::base::SetProperty("ctl.stop", "snapuserd");
-
- if (FLAGS_force_config == "iouring_disabled") {
- if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: snapuserd.test.io_uring.disabled";
- }
- }
-
- int ret = RUN_ALL_TESTS();
-
- if (FLAGS_force_config == "iouring_disabled") {
- android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
- }
-
- return ret;
+ return RUN_ALL_TESTS();
}
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
deleted file mode 100644
index cc12d1d..0000000
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// A subset of system/update_engine/update_metadata.proto. A separate file is
-// used here because:
-// - The original file is optimized for LITE_RUNTIME, but fuzzing needs
-// reflection.
-// - The definition here has less fields. libsnapshot only uses fields declared
-// here, and all fields declared here are fuzzed by libsnapshot_fuzzer. If
-// libsnapshot uses more fields in system/update_engine/update_metadata.proto
-// in the future, they must be added here too, otherwise it will fail to
-// compile.
-//
-// It is okay that this file is older than
-// system/update_engine/update_metadata.proto as long as the messages defined
-// here can also be parsed by protobuf defined there. However, it is not
-// okay to add fields here without adding them to
-// system/update_engine/update_metadata.proto. Doing so will cause a compiler
-// error when libsnapshot code starts to use these dangling fields.
-
-syntax = "proto2";
-
-package chromeos_update_engine;
-
-message Extent {
- optional uint64 start_block = 1;
- optional uint64 num_blocks = 2;
-}
-
-message PartitionInfo {
- optional uint64 size = 1;
-}
-
-message InstallOperation {
- enum Type {
- SOURCE_COPY = 4;
- // Not used by libsnapshot. Declared here so that the fuzzer has an
- // alternative value to use for |type|.
- ZERO = 6;
- }
- required Type type = 1;
- repeated Extent src_extents = 4;
- repeated Extent dst_extents = 6;
-}
-
-message PartitionUpdate {
- required string partition_name = 1;
- optional PartitionInfo new_partition_info = 7;
- repeated InstallOperation operations = 8;
- optional Extent hash_tree_extent = 11;
- optional Extent fec_extent = 15;
- optional uint64 estimate_cow_size = 19;
-}
-
-message DynamicPartitionGroup {
- required string name = 1;
- optional uint64 size = 2;
- repeated string partition_names = 3;
-}
-
-message VABCFeatureSet {
- optional bool threaded = 1;
- optional bool batch_writes = 2;
-}
-
-message DynamicPartitionMetadata {
- repeated DynamicPartitionGroup groups = 1;
- optional bool vabc_enabled = 3;
- optional string vabc_compression_param = 4;
- optional uint32 cow_version = 5;
- // A collection of knobs to tune Virtual AB Compression
- optional VABCFeatureSet vabc_feature_set = 6;
-}
-
-message DeltaArchiveManifest {
- repeated PartitionUpdate partitions = 13;
- optional DynamicPartitionMetadata dynamic_partition_metadata = 15;
- optional bool partial_update = 16;
-}
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 10efd0c..7273087 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -53,6 +53,7 @@
std::cerr << " getpath <dm-name>" << std::endl;
std::cerr << " getuuid <dm-name>" << std::endl;
std::cerr << " info <dm-name>" << std::endl;
+ std::cerr << " replace <dm-name> <targets...>" << std::endl;
std::cerr << " status <dm-name>" << std::endl;
std::cerr << " resume <dm-name>" << std::endl;
std::cerr << " suspend <dm-name>" << std::endl;
diff --git a/healthd/healthd.rc b/healthd/healthd.rc
deleted file mode 100644
index 8e2ebb6..0000000
--- a/healthd/healthd.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service healthd /system/bin/healthd
- class hal
- critical
- group root system wakelock
diff --git a/init/test_upgrade_mte/mte_upgrade_test.rc b/init/test_upgrade_mte/mte_upgrade_test.rc
index a3e596c..aa6c18f 100644
--- a/init/test_upgrade_mte/mte_upgrade_test.rc
+++ b/init/test_upgrade_mte/mte_upgrade_test.rc
@@ -16,9 +16,11 @@
class late_start
disabled
seclabel u:r:su:s0
+ user root
service mte_upgrade_test_helper_overridden /system/bin/mte_upgrade_test_helper ${sys.mte_crash_test_uuid}
class late_start
disabled
seclabel u:r:su:s0
+ user root
setenv BIONIC_MEMTAG_UPGRADE_SECS 0
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 295f4da..79d79dd 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -84,11 +84,14 @@
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
{ 00750, AID_ROOT, AID_SYSTEM, 0, "system/apex/com.android.tethering/bin/for-system" },
+ { 00750, AID_ROOT, AID_SYSTEM, 0, "system/apex/com.android.tethering.inprocess/bin/for-system" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00750, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin" },
+ { 00750, AID_ROOT, AID_SYSTEM, 0, "system_ext/apex/com.android.tethering/bin/for-system" },
+ { 00750, AID_ROOT, AID_SYSTEM, 0, "system_ext/apex/com.android.tethering.inprocess/bin/for-system" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/apex/*/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "vendor/bin" },
@@ -196,6 +199,9 @@
// the following files have enhanced capabilities and ARE included
// in user builds.
{ 06755, AID_CLAT, AID_CLAT, 0, "system/apex/com.android.tethering/bin/for-system/clatd" },
+ { 06755, AID_CLAT, AID_CLAT, 0, "system/apex/com.android.tethering.inprocess/bin/for-system/clatd" },
+ { 06755, AID_CLAT, AID_CLAT, 0, "system_ext/apex/com.android.tethering/bin/for-system/clatd" },
+ { 06755, AID_CLAT, AID_CLAT, 0, "system_ext/apex/com.android.tethering.inprocess/bin/for-system/clatd" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
"system/bin/inputflinger" },
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index e071c96..1971f01 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -562,7 +562,7 @@
// Attempt to match both the canonical module name and the module filename.
if (!fnmatch(pattern.c_str(), module.c_str(), 0)) {
rv.emplace_back(module);
- } else if (!fnmatch(pattern.c_str(), basename(deps[0].c_str()), 0)) {
+ } else if (!fnmatch(pattern.c_str(), android::base::Basename(deps[0]).c_str(), 0)) {
rv.emplace_back(deps[0]);
}
}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 9b2d775..48bc0b7 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -36,6 +36,7 @@
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+bool SetUserProfiles(uid_t uid, const std::vector<std::string>& profiles);
__END_DECLS
@@ -75,6 +76,11 @@
// that it only returns 0 in the case that the cgroup exists and it contains no processes.
int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_processes = nullptr);
+// Sends the provided signal to all members of a process group, but does not wait for processes to
+// exit, or for the cgroup to be removed. Callers should also ensure that killProcessGroup is called
+// later to ensure the cgroup is fully removed, otherwise system resources may leak.
+int sendSignalToProcessGroup(uid_t uid, int initialPid, int signal);
+
int createProcessGroup(uid_t uid, int initialPid, bool memControl = false);
// Set various properties of a process group. For these functions to work, the process group must
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 38eb92f..a021594 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -200,6 +200,11 @@
return SetProcessProfiles(uid, pid, std::span<const std::string_view>(profiles_));
}
+bool SetUserProfiles(uid_t uid, const std::vector<std::string>& profiles) {
+ return TaskProfiles::GetInstance().SetUserProfiles(uid, std::span<const std::string>(profiles),
+ false);
+}
+
static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
return StringPrintf("%s/uid_%d", cgroup, uid);
}
@@ -537,6 +542,15 @@
return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
}
+int sendSignalToProcessGroup(uid_t uid, int initialPid, int signal) {
+ std::string hierarchy_root_path;
+ if (CgroupsAvailable()) {
+ CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &hierarchy_root_path);
+ }
+ const char* cgroup = hierarchy_root_path.c_str();
+ return DoKillProcessGroupOnce(cgroup, uid, initialPid, signal);
+}
+
static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup,
bool activate_controllers) {
auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4db7372..1731828 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -139,6 +139,17 @@
return true;
}
+bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const {
+ if (path == nullptr) {
+ return true;
+ }
+
+ const std::string& file_name =
+ controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
+ *path = StringPrintf("%s/uid_%d/%s", controller()->path(), uid, file_name.c_str());
+ return true;
+}
+
bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const {
// TODO: add support when kernel supports util_clamp
LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported";
@@ -225,6 +236,29 @@
return true;
}
+bool SetAttributeAction::ExecuteForUID(uid_t uid) const {
+ std::string path;
+
+ if (!attribute_->GetPathForUID(uid, &path)) {
+ LOG(ERROR) << "Failed to find cgroup for uid " << uid;
+ return false;
+ }
+
+ if (!WriteStringToFile(value_, path)) {
+ if (access(path.c_str(), F_OK) < 0) {
+ if (optional_) {
+ return true;
+ } else {
+ LOG(ERROR) << "No such cgroup attribute: " << path;
+ return false;
+ }
+ }
+ PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
+ return false;
+ }
+ return true;
+}
+
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
@@ -552,6 +586,16 @@
return true;
}
+bool TaskProfile::ExecuteForUID(uid_t uid) const {
+ for (const auto& element : elements_) {
+ if (!element->ExecuteForUID(uid)) {
+ LOG(VERBOSE) << "Applying profile action " << element->Name() << " failed";
+ return false;
+ }
+ }
+ return true;
+}
+
void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
if (res_cached_) {
return;
@@ -805,6 +849,24 @@
}
template <typename T>
+bool TaskProfiles::SetUserProfiles(uid_t uid, std::span<const T> profiles, bool use_fd_cache) {
+ for (const auto& name : profiles) {
+ TaskProfile* profile = GetProfile(name);
+ if (profile != nullptr) {
+ if (use_fd_cache) {
+ profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
+ }
+ if (!profile->ExecuteForUID(uid)) {
+ PLOG(WARNING) << "Failed to apply " << name << " process profile";
+ }
+ } else {
+ PLOG(WARNING) << "Failed to find " << name << "process profile";
+ }
+ }
+ return true;
+}
+
+template <typename T>
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles,
bool use_fd_cache) {
bool success = true;
@@ -857,3 +919,5 @@
bool use_fd_cache);
template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
bool use_fd_cache);
+template bool TaskProfiles::SetUserProfiles(uid_t uid, std::span<const std::string> profiles,
+ bool use_fd_cache);
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 85b3f91..a8ecb87 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -36,6 +36,7 @@
virtual const CgroupController* controller() const = 0;
virtual const std::string& file_name() const = 0;
virtual bool GetPathForTask(int tid, std::string* path) const = 0;
+ virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0;
};
class ProfileAttribute : public IProfileAttribute {
@@ -53,6 +54,7 @@
void Reset(const CgroupController& controller, const std::string& file_name) override;
bool GetPathForTask(int tid, std::string* path) const override;
+ bool GetPathForUID(uid_t uid, std::string* path) const override;
private:
CgroupController controller_;
@@ -72,6 +74,7 @@
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
+ virtual bool ExecuteForUID(uid_t) const { return false; };
virtual void EnableResourceCaching(ResourceCacheType) {}
virtual void DropResourceCaching(ResourceCacheType) {}
@@ -116,6 +119,7 @@
const char* Name() const override { return "SetAttribute"; }
bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
bool ExecuteForTask(int tid) const override;
+ bool ExecuteForUID(uid_t uid) const override;
private:
const IProfileAttribute* attribute_;
@@ -179,6 +183,7 @@
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
+ bool ExecuteForUID(uid_t uid) const;
void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
@@ -216,6 +221,8 @@
bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles, bool use_fd_cache);
template <typename T>
bool SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache);
+ template <typename T>
+ bool SetUserProfiles(uid_t uid, std::span<const T> profiles, bool use_fd_cache);
private:
TaskProfiles();
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index 09ac44c..6a5b48b 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -16,6 +16,7 @@
#include "task_profiles.h"
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <gtest/gtest.h>
#include <mntent.h>
#include <processgroup/processgroup.h>
@@ -29,13 +30,14 @@
using ::android::base::LogId;
using ::android::base::LogSeverity;
using ::android::base::SetLogger;
+using ::android::base::Split;
using ::android::base::VERBOSE;
using ::testing::TestWithParam;
using ::testing::Values;
namespace {
-bool IsCgroupV2Mounted() {
+bool IsCgroupV2MountedRw() {
std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
if (!mnts) {
LOG(ERROR) << "Failed to open /proc/mounts";
@@ -43,9 +45,11 @@
}
struct mntent* mnt;
while ((mnt = getmntent(mnts.get()))) {
- if (strcmp(mnt->mnt_fsname, "cgroup2") == 0) {
- return true;
+ if (strcmp(mnt->mnt_type, "cgroup2") != 0) {
+ continue;
}
+ const std::vector<std::string> options = Split(mnt->mnt_opts, ",");
+ return std::count(options.begin(), options.end(), "ro") == 0;
}
return false;
}
@@ -121,6 +125,10 @@
return true;
};
+ bool GetPathForUID(uid_t, std::string*) const override {
+ return false;
+ }
+
private:
const std::string file_name_;
};
@@ -141,8 +149,9 @@
};
TEST_P(SetAttributeFixture, SetAttribute) {
- // Treehugger runs host tests inside a container without cgroupv2 support.
- if (!IsCgroupV2Mounted()) {
+ // Treehugger runs host tests inside a container either without cgroupv2
+ // support or with the cgroup filesystem mounted read-only.
+ if (!IsCgroupV2MountedRw()) {
GTEST_SKIP();
return;
}
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 967205f..cacc47c 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -5,6 +5,7 @@
libbinder_ndk.so
libc.so
libcamera2ndk.so
+libclang_rt.hwasan-aarch64-android.so 64 nopreload
libdl.so
libEGL.so
libGLESv1_CM.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b165778..d755b50 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -475,25 +475,28 @@
stdio_to_kmsg
# Explicitly specify that boringssl_self_test32 doesn't require any capabilities
capabilities
+ user nobody
service boringssl_self_test64 /system/bin/boringssl_self_test64
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
# Explicitly specify that boringssl_self_test64 doesn't require any capabilities
capabilities
+ user nobody
service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
# Explicitly specify that boringssl_self_test_apex32 doesn't require any capabilities
capabilities
+ user nobody
service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
# Explicitly specify that boringssl_self_test_apex64 doesn't require any capabilities
capabilities
-
+ user nobody
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
@@ -1260,6 +1263,7 @@
class core
critical
seclabel u:r:ueventd:s0
+ user root
shutdown critical
service console /system/bin/sh