Merge "libsnapshot_fuzzer: allow ENXIO."
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 9ca0eba..0ff047f 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -180,7 +180,6 @@
"libdebuggerd/backtrace.cpp",
"libdebuggerd/gwp_asan.cpp",
"libdebuggerd/open_files_list.cpp",
- "libdebuggerd/scudo.cpp",
"libdebuggerd/tombstone.cpp",
"libdebuggerd/tombstone_proto.cpp",
"libdebuggerd/tombstone_proto_to_text.cpp",
@@ -193,9 +192,6 @@
include_dirs: [
// Needed for private/bionic_fdsan.h
"bionic/libc",
-
- // Needed for scudo/interface.h
- "external/scudo/standalone/include",
],
header_libs: [
"bionic_libc_platform_headers",
@@ -217,7 +213,6 @@
whole_static_libs: [
"libasync_safe",
"gwp_asan_crash_handler",
- "libscudo",
"libtombstone_proto",
"libprocinfo",
"libprotobuf-cpp-lite",
@@ -246,6 +241,13 @@
debuggable: {
cflags: ["-DROOT_POSSIBLE"],
},
+
+ malloc_not_svelte: {
+ cflags: ["-DUSE_SCUDO"],
+ whole_static_libs: ["libscudo"],
+ srcs: ["libdebuggerd/scudo.cpp"],
+ header_libs: ["scudo_headers"],
+ },
},
}
@@ -316,10 +318,6 @@
"gwp_asan_headers",
],
- include_dirs: [
- "external/scudo/standalone/include",
- ],
-
local_include_dirs: [
"libdebuggerd",
],
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ff03bcd..534d7be 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -36,6 +36,7 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -57,10 +58,13 @@
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/gwp_asan.h"
#include "libdebuggerd/open_files_list.h"
-#include "libdebuggerd/scudo.h"
#include "libdebuggerd/utility.h"
#include "util.h"
+#if defined(USE_SCUDO)
+#include "libdebuggerd/scudo.h"
+#endif
+
#include "gwp_asan/common.h"
#include "gwp_asan/crash_handler.h"
@@ -115,8 +119,26 @@
return "";
}
-static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps,
- unwindstack::Regs* regs) {
+static void dump_probable_cause(log_t* log, unwindstack::Unwinder* unwinder,
+ const ProcessInfo& process_info, const ThreadInfo& main_thread) {
+#if defined(USE_SCUDO)
+ ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
+ if (scudo_crash_data.CrashIsMine()) {
+ scudo_crash_data.DumpCause(log, unwinder);
+ return;
+ }
+#endif
+
+ GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
+ main_thread);
+ if (gwp_asan_crash_data.CrashIsMine()) {
+ gwp_asan_crash_data.DumpCause(log);
+ return;
+ }
+
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ unwindstack::Regs* regs = main_thread.registers.get();
+ const siginfo_t* si = main_thread.siginfo;
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -395,22 +417,11 @@
dump_signal_info(log, thread_info, process_info, unwinder->GetProcessMemory().get());
}
- std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
- std::unique_ptr<ScudoCrashData> scudo_crash_data;
if (primary_thread) {
- gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
- process_info, thread_info);
- scudo_crash_data =
- std::make_unique<ScudoCrashData>(unwinder->GetProcessMemory().get(), process_info);
- }
+ // The main thread must have a valid siginfo.
+ CHECK(thread_info.siginfo != nullptr);
+ dump_probable_cause(log, unwinder, process_info, thread_info);
- if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
- gwp_asan_crash_data->DumpCause(log);
- } else if (thread_info.siginfo && !(primary_thread && scudo_crash_data->CrashIsMine())) {
- dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(), thread_info.registers.get());
- }
-
- if (primary_thread) {
dump_abort_message(log, unwinder->GetProcessMemory().get(), process_info.abort_msg_address);
}
@@ -432,16 +443,17 @@
}
if (primary_thread) {
- if (gwp_asan_crash_data->HasDeallocationTrace()) {
- gwp_asan_crash_data->DumpDeallocationTrace(log, unwinder);
+ GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
+ thread_info);
+
+ if (gwp_asan_crash_data.HasDeallocationTrace()) {
+ gwp_asan_crash_data.DumpDeallocationTrace(log, unwinder);
}
- if (gwp_asan_crash_data->HasAllocationTrace()) {
- gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
+ if (gwp_asan_crash_data.HasAllocationTrace()) {
+ gwp_asan_crash_data.DumpAllocationTrace(log, unwinder);
}
- scudo_crash_data->DumpCause(log, unwinder);
-
unwindstack::Maps* maps = unwinder->GetMaps();
dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
thread_info.registers.get());
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 99f636e..6c380a1 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -18,7 +18,9 @@
#include "libdebuggerd/tombstone.h"
#include "libdebuggerd/gwp_asan.h"
+#if defined(USE_SCUDO)
#include "libdebuggerd/scudo.h"
+#endif
#include <errno.h>
#include <fcntl.h>
@@ -38,6 +40,7 @@
#include <async_safe/log.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -186,11 +189,13 @@
static void dump_probable_cause(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
const ProcessInfo& process_info, const ThreadInfo& main_thread) {
+#if defined(USE_SCUDO)
ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
if (scudo_crash_data.CrashIsMine()) {
scudo_crash_data.AddCauseProtos(tombstone, unwinder);
return;
}
+#endif
GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
main_thread);
@@ -612,6 +617,8 @@
result.set_tid(main_thread.tid);
result.set_uid(main_thread.uid);
result.set_selinux_label(main_thread.selinux_label);
+ // The main thread must have a valid siginfo.
+ CHECK(main_thread.siginfo != nullptr);
struct sysinfo si;
sysinfo(&si);
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 428a7f4..2bb9035 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -86,7 +86,9 @@
name: "vts_libdm_test",
defaults: ["libdm_test_defaults"],
test_suites: ["vts"],
- test_min_api_level: 29,
+ test_options: {
+ min_shipping_api_level: 29,
+ },
}
cc_fuzz {
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 7e01b85..332fcf5 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -55,7 +55,33 @@
// that prefix.
std::optional<std::string> ExtractBlockDeviceName(const std::string& path);
-class DeviceMapper final {
+// This interface is for testing purposes. See DeviceMapper proper for what these methods do.
+class IDeviceMapper {
+ public:
+ virtual ~IDeviceMapper() {}
+
+ struct TargetInfo {
+ struct dm_target_spec spec;
+ std::string data;
+ TargetInfo() {}
+ TargetInfo(const struct dm_target_spec& spec, const std::string& data)
+ : spec(spec), data(data) {}
+
+ bool IsOverflowSnapshot() const;
+ };
+
+ virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms) = 0;
+ virtual DmDeviceState GetState(const std::string& name) const = 0;
+ virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
+ virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
+ virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
+ virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
+ virtual bool GetDeviceString(const std::string& name, std::string* dev) = 0;
+ virtual bool DeleteDeviceIfExists(const std::string& name) = 0;
+};
+
+class DeviceMapper final : public IDeviceMapper {
public:
class DmBlockDevice final {
public:
@@ -95,7 +121,7 @@
// Removes a device mapper device with the given name.
// Returns 'true' on success, false otherwise.
bool DeleteDevice(const std::string& name);
- bool DeleteDeviceIfExists(const std::string& name);
+ bool DeleteDeviceIfExists(const std::string& name) override;
// Removes a device mapper device with the given name and waits for |timeout_ms| milliseconds
// for the corresponding block device to be deleted.
bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
@@ -114,7 +140,7 @@
// Returns the current state of the underlying device mapper device
// with given name.
// One of INVALID, SUSPENDED or ACTIVE.
- DmDeviceState GetState(const std::string& name) const;
+ DmDeviceState GetState(const std::string& name) const override;
// Puts the given device to the specified status, which must be either:
// - SUSPENDED: suspend the device, or
@@ -158,7 +184,7 @@
// not |path| is available. It is the caller's responsibility to ensure
// there are no races.
bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms);
+ const std::chrono::milliseconds& timeout_ms) override;
// Create a device and activate the given table, without waiting to acquire
// a valid path. If the caller will use GetDmDevicePathByName(), it should
@@ -170,7 +196,7 @@
// process. A device with the given name must already exist.
//
// Returns 'true' on success, false otherwise.
- bool LoadTableAndActivate(const std::string& name, const DmTable& table);
+ bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
// Returns true if a list of available device mapper targets registered in the kernel was
// successfully read and stored in 'targets'. Returns 'false' otherwise.
@@ -216,7 +242,7 @@
// Returns a major:minor string for the named device-mapper node, that can
// be used as inputs to DmTargets that take a block device.
- bool GetDeviceString(const std::string& name, std::string* dev);
+ bool GetDeviceString(const std::string& name, std::string* dev) override;
// The only way to create a DeviceMapper object.
static DeviceMapper& Instance();
@@ -231,20 +257,11 @@
// contain one TargetInfo for each target in the table. If the device does
// not exist, or there were too many targets, the call will fail and return
// false.
- struct TargetInfo {
- struct dm_target_spec spec;
- std::string data;
- TargetInfo() {}
- TargetInfo(const struct dm_target_spec& spec, const std::string& data)
- : spec(spec), data(data) {}
-
- bool IsOverflowSnapshot() const;
- };
- bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table);
+ bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override;
// Identical to GetTableStatus, except also retrives the active table for the device
// mapper device from the kernel.
- bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table);
+ bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) override;
static std::string GetTargetType(const struct dm_target_spec& spec);
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index d16b8d6..5deba65 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -90,7 +90,9 @@
test_suites: ["vts", "device-tests"],
auto_gen_config: true,
- test_min_api_level: 29,
+ test_options: {
+ min_shipping_api_level: 29,
+ },
require_root: true,
}
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 0cbd9db..a0ad208 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -152,6 +152,7 @@
static_libs: [
"libavb",
"libdm",
+ "libext2_uuid",
"libfs_avb",
"libfstab",
],
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index fc2d8a1..4b81c2c 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -105,7 +105,9 @@
defaults: ["liblp_test_defaults"],
test_suites: ["vts"],
auto_gen_config: true,
- test_min_api_level: 29,
+ test_options: {
+ min_shipping_api_level: 29,
+ },
require_root: true,
}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index df00f45..5ab2ce2 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -251,7 +251,9 @@
"vts",
"device-tests"
],
- test_min_api_level: 29,
+ test_options: {
+ min_shipping_api_level: 29,
+ },
auto_gen_config: true,
require_root: true,
}
@@ -407,7 +409,9 @@
test_suites: [
"device-tests"
],
- test_min_api_level: 30,
+ test_options: {
+ min_shipping_api_level: 30,
+ },
auto_gen_config: true,
require_root: false,
host_supported: true,
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 6066309..ba4044f 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -1171,18 +1171,18 @@
ASSERT_TRUE(writer.Initialize(cow_->fd));
ASSERT_TRUE(writer.AddSequenceData(6, sequence));
- ASSERT_TRUE(writer.AddCopy(6, 3));
+ ASSERT_TRUE(writer.AddCopy(6, 13));
ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
- ASSERT_TRUE(writer.AddCopy(3, 5));
- ASSERT_TRUE(writer.AddCopy(2, 1));
+ ASSERT_TRUE(writer.AddCopy(3, 15));
+ ASSERT_TRUE(writer.AddCopy(2, 11));
ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
- ASSERT_TRUE(writer.AddCopy(5, 6));
+ ASSERT_TRUE(writer.AddCopy(5, 16));
ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
- ASSERT_TRUE(writer.AddCopy(10, 2));
- ASSERT_TRUE(writer.AddCopy(7, 4));
+ ASSERT_TRUE(writer.AddCopy(10, 12));
+ ASSERT_TRUE(writer.AddCopy(7, 14));
ASSERT_TRUE(writer.Finalize());
// New block in cow order is 6, 12, 8, 11, 3, 2, 4, 9, 5, 1, 10, 7
@@ -1219,12 +1219,12 @@
ASSERT_TRUE(writer.Initialize(cow_->fd));
- ASSERT_TRUE(writer.AddCopy(2, 1));
- ASSERT_TRUE(writer.AddCopy(10, 2));
- ASSERT_TRUE(writer.AddCopy(6, 3));
- ASSERT_TRUE(writer.AddCopy(7, 4));
- ASSERT_TRUE(writer.AddCopy(3, 5));
- ASSERT_TRUE(writer.AddCopy(5, 6));
+ ASSERT_TRUE(writer.AddCopy(2, 11));
+ ASSERT_TRUE(writer.AddCopy(10, 12));
+ ASSERT_TRUE(writer.AddCopy(6, 13));
+ ASSERT_TRUE(writer.AddCopy(7, 14));
+ ASSERT_TRUE(writer.AddCopy(3, 15));
+ ASSERT_TRUE(writer.AddCopy(5, 16));
ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
@@ -1260,6 +1260,39 @@
ASSERT_TRUE(iter->Done());
}
+TEST_F(CowTest, InvalidMergeOrderTest) {
+ CowOptions options;
+ options.cluster_ops = 5;
+ options.num_merge_ops = 1;
+ std::string data = "This is some data, believe it";
+ data.resize(options.block_size, '\0');
+ auto writer = std::make_unique<CowWriter>(options);
+ CowReader reader;
+
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer->AddCopy(3, 2));
+ ASSERT_TRUE(writer->AddCopy(2, 1));
+ ASSERT_TRUE(writer->AddLabel(1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_TRUE(reader.VerifyMergeOps());
+
+ ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+ ASSERT_TRUE(writer->AddCopy(4, 2));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_FALSE(reader.VerifyMergeOps());
+
+ writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+ ASSERT_TRUE(writer->AddCopy(2, 1));
+ ASSERT_TRUE(writer->AddXorBlocks(3, &data, data.size(), 1, 1));
+ ASSERT_TRUE(writer->Finalize());
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_FALSE(reader.VerifyMergeOps());
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/cow_format.cpp
index 8e6bec7..94c4109 100644
--- a/fs_mgr/libsnapshot/cow_format.cpp
+++ b/fs_mgr/libsnapshot/cow_format.cpp
@@ -56,7 +56,10 @@
os << (int)op.compression << "?, ";
os << "data_length:" << op.data_length << ",\t";
os << "new_block:" << op.new_block << ",\t";
- os << "source:" << op.source << ")";
+ os << "source:" << op.source;
+ if (op.type == kCowXorOp)
+ os << " (block:" << op.source / BLOCK_SZ << " offset:" << op.source % BLOCK_SZ << ")";
+ os << ")";
return os;
}
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 773d978..5306b28 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -58,6 +58,7 @@
cow->last_label_ = last_label_;
cow->ops_ = ops_;
cow->merge_op_blocks_ = merge_op_blocks_;
+ cow->merge_op_start_ = merge_op_start_;
cow->block_map_ = block_map_;
cow->num_total_data_ops_ = num_total_data_ops_;
cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_;
@@ -230,7 +231,7 @@
memcpy(&footer_->op, ¤t_op, sizeof(footer->op));
off_t offs = lseek(fd_.get(), pos, SEEK_SET);
if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
- PLOG(ERROR) << "lseek next op failed";
+ PLOG(ERROR) << "lseek next op failed " << offs;
return false;
}
if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) {
@@ -250,7 +251,7 @@
// Position for next cluster read
off_t offs = lseek(fd_.get(), pos, SEEK_SET);
if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
- PLOG(ERROR) << "lseek next op failed";
+ PLOG(ERROR) << "lseek next op failed " << offs;
return false;
}
ops_buffer->resize(current_op_num);
@@ -468,8 +469,7 @@
num_total_data_ops_ = merge_op_blocks->size();
if (header_.num_merge_ops > 0) {
- merge_op_blocks->erase(merge_op_blocks->begin(),
- merge_op_blocks->begin() + header_.num_merge_ops);
+ merge_op_start_ = header_.num_merge_ops;
}
block_map_ = block_map;
@@ -477,6 +477,44 @@
return true;
}
+bool CowReader::VerifyMergeOps() {
+ auto itr = GetMergeOpIter(true);
+ std::unordered_map<uint64_t, CowOperation> overwritten_blocks;
+ while (!itr->Done()) {
+ CowOperation op = itr->Get();
+ uint64_t block;
+ bool offset;
+ if (op.type == kCowCopyOp) {
+ block = op.source;
+ offset = false;
+ } else if (op.type == kCowXorOp) {
+ block = op.source / BLOCK_SZ;
+ offset = (op.source % BLOCK_SZ) != 0;
+ } else {
+ itr->Next();
+ continue;
+ }
+
+ CowOperation* overwrite = nullptr;
+ if (overwritten_blocks.count(block)) {
+ overwrite = &overwritten_blocks[block];
+ LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
+ << op << "\noverwritten by previously merged op:\n"
+ << *overwrite;
+ }
+ if (offset && overwritten_blocks.count(block + 1)) {
+ overwrite = &overwritten_blocks[block + 1];
+ LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
+ << op << "\noverwritten by previously merged op:\n"
+ << *overwrite;
+ }
+ if (overwrite != nullptr) return false;
+ overwritten_blocks[op.new_block] = op;
+ itr->Next();
+ }
+ return true;
+}
+
bool CowReader::GetHeader(CowHeader* header) {
*header = header_;
return true;
@@ -530,7 +568,8 @@
public:
explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map);
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map,
+ uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -541,20 +580,67 @@
std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
std::vector<uint32_t>::reverse_iterator block_riter_;
+ uint64_t start_;
};
-CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map) {
+class CowMergeOpIter final : public ICowOpIter {
+ public:
+ explicit CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map, uint64_t start);
+
+ bool Done() override;
+ const CowOperation& Get() override;
+ void Next() override;
+
+ private:
+ std::shared_ptr<std::vector<CowOperation>> ops_;
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
+ std::vector<uint32_t>::iterator block_iter_;
+ uint64_t start_;
+};
+
+CowMergeOpIter::CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map,
+ uint64_t start) {
ops_ = ops;
merge_op_blocks_ = merge_op_blocks;
map_ = map;
+ start_ = start;
+
+ block_iter_ = merge_op_blocks->begin() + start;
+}
+
+bool CowMergeOpIter::Done() {
+ return block_iter_ == merge_op_blocks_->end();
+}
+
+void CowMergeOpIter::Next() {
+ CHECK(!Done());
+ block_iter_++;
+}
+
+const CowOperation& CowMergeOpIter::Get() {
+ CHECK(!Done());
+ return ops_->data()[map_->at(*block_iter_)];
+}
+
+CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map,
+ uint64_t start) {
+ ops_ = ops;
+ merge_op_blocks_ = merge_op_blocks;
+ map_ = map;
+ start_ = start;
block_riter_ = merge_op_blocks->rbegin();
}
bool CowRevMergeOpIter::Done() {
- return block_riter_ == merge_op_blocks_->rend();
+ return block_riter_ == merge_op_blocks_->rend() - start_;
}
void CowRevMergeOpIter::Next() {
@@ -571,8 +657,14 @@
return std::make_unique<CowOpIter>(ops_);
}
-std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter() {
- return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_);
+std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
+ return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ ignore_progress ? 0 : merge_op_start_);
+}
+
+std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
+ return std::make_unique<CowMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ ignore_progress ? 0 : merge_op_start_);
}
bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index 14ce0ee..a6d96ed 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -139,5 +139,9 @@
}
}
+android::dm::IDeviceMapper& DeviceInfo::GetDeviceMapper() {
+ return android::dm::DeviceMapper::Instance();
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index 7999c99..8aefb85 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -40,6 +40,7 @@
bool IsRecovery() const override;
std::unique_ptr<IImageManager> OpenImageManager() const override;
bool IsFirstStageInit() const override;
+ android::dm::IDeviceMapper& GetDeviceMapper() override;
void set_first_stage_init(bool value) { first_stage_init_ = value; }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 0786e82..143f73c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -68,6 +68,7 @@
// Return the file footer.
virtual bool GetFooter(CowFooter* footer) = 0;
+ virtual bool VerifyMergeOps() = 0;
// Return the last valid label
virtual bool GetLastLabel(uint64_t* label) = 0;
@@ -75,8 +76,11 @@
// Return an iterator for retrieving CowOperation entries.
virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
+ // Return an iterator for retrieving CowOperation entries in reverse merge order
+ virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress) = 0;
+
// Return an iterator for retrieving CowOperation entries in merge order
- virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter() = 0;
+ virtual std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress) = 0;
// Get decoded bytes from the data section, handling any decompression.
// All retrieved data is passed to the sink.
@@ -98,7 +102,7 @@
virtual void Next() = 0;
};
-class CowReader : public ICowReader {
+class CowReader final : public ICowReader {
public:
CowReader();
~CowReader() { owned_fd_ = {}; }
@@ -109,6 +113,7 @@
bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
bool InitForMerge(android::base::unique_fd&& fd);
+ bool VerifyMergeOps() override;
bool GetHeader(CowHeader* header) override;
bool GetFooter(CowFooter* footer) override;
@@ -120,7 +125,8 @@
// whose lifetime depends on the CowOpIter object; the return
// value of these will never be null.
std::unique_ptr<ICowOpIter> GetOpIter() override;
- std::unique_ptr<ICowOpIter> GetRevMergeOpIter() override;
+ std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress = false) override;
+ std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress = false) override;
bool ReadData(const CowOperation& op, IByteSink* sink) override;
@@ -152,6 +158,7 @@
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+ uint64_t merge_op_start_;
std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
uint64_t num_total_data_ops_;
uint64_t num_ordered_ops_to_merge_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
index 3655c01..b0be5a5 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -44,6 +44,7 @@
// Open the writer in write mode (no append).
MOCK_METHOD(bool, Initialize, (), (override));
+ MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept));
// Open the writer in append mode, with the last label to resume
// from. See CowWriter::InitializeAppend.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index d9a0cd9..55f4ed7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -110,6 +110,7 @@
virtual bool IsTestDevice() const { return false; }
virtual bool IsFirstStageInit() const = 0;
virtual std::unique_ptr<IImageManager> OpenImageManager() const = 0;
+ virtual android::dm::IDeviceMapper& GetDeviceMapper() = 0;
// Helper method for implementing OpenImageManager.
std::unique_ptr<IImageManager> OpenImageManager(const std::string& gsid_dir) const;
@@ -611,6 +612,14 @@
MergeFailureCode CheckMergeConsistency(LockedFile* lock, const std::string& name,
const SnapshotStatus& update_status);
+ // Get status or table information about a device-mapper node with a single target.
+ enum class TableQuery {
+ Table,
+ Status,
+ };
+ bool GetSingleTarget(const std::string& dm_name, TableQuery query,
+ android::dm::DeviceMapper::TargetInfo* target);
+
// Interact with status files under /metadata/ota/snapshots.
bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
@@ -773,9 +782,9 @@
bool DeleteDeviceIfExists(const std::string& name,
const std::chrono::milliseconds& timeout_ms = {});
- std::string gsid_dir_;
- std::string metadata_dir_;
+ android::dm::IDeviceMapper& dm_;
std::unique_ptr<IDeviceInfo> device_;
+ std::string metadata_dir_;
std::unique_ptr<IImageManager> images_;
bool use_first_stage_snapuserd_ = false;
bool in_factory_data_reset_ = false;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index b09e1ae..545f117 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -47,6 +47,7 @@
virtual bool InitializeAppend(uint64_t label) = 0;
virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
+ virtual bool VerifyMergeOps() const noexcept = 0;
protected:
android::base::borrowed_fd GetSourceFd();
@@ -58,7 +59,7 @@
};
// Send writes to a COW or a raw device directly, based on a threshold.
-class CompressedSnapshotWriter : public ISnapshotWriter {
+class CompressedSnapshotWriter final : public ISnapshotWriter {
public:
CompressedSnapshotWriter(const CowOptions& options);
@@ -70,6 +71,7 @@
bool Finalize() override;
uint64_t GetCowSize() override;
std::unique_ptr<FileDescriptor> OpenReader() override;
+ bool VerifyMergeOps() const noexcept;
protected:
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
@@ -81,13 +83,14 @@
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
+ std::unique_ptr<CowReader> OpenCowReader() const;
android::base::unique_fd cow_device_;
std::unique_ptr<CowWriter> cow_;
};
// Write directly to a dm-snapshot device.
-class OnlineKernelSnapshotWriter : public ISnapshotWriter {
+class OnlineKernelSnapshotWriter final : public ISnapshotWriter {
public:
OnlineKernelSnapshotWriter(const CowOptions& options);
@@ -101,6 +104,10 @@
uint64_t GetCowSize() override { return cow_size_; }
std::unique_ptr<FileDescriptor> OpenReader() override;
+ // Online kernel snapshot writer doesn't care about merge sequences.
+ // So ignore.
+ bool VerifyMergeOps() const noexcept override { return true; }
+
protected:
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 4e7ccf1..1f57bbc 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -99,6 +99,9 @@
std::unique_ptr<IImageManager> OpenImageManager() const override {
return IDeviceInfo::OpenImageManager("ota/test");
}
+ android::dm::IDeviceMapper& GetDeviceMapper() override {
+ return android::dm::DeviceMapper::Instance();
+ }
bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 3c0ba16..548ba00 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -44,10 +44,13 @@
LOG(ERROR) << "\t -b Show data for failed decompress";
LOG(ERROR) << "\t -l Show ops";
LOG(ERROR) << "\t -m Show ops in reverse merge order";
- LOG(ERROR) << "\t -o Shows sequence op block order\n";
+ LOG(ERROR) << "\t -n Show ops in merge order";
+ LOG(ERROR) << "\t -a Include merged ops in any merge order listing";
+ LOG(ERROR) << "\t -o Shows sequence op block order";
+ LOG(ERROR) << "\t -v Verifies merge order has no conflicts\n";
}
-enum OpIter { Normal, RevMerge };
+enum OpIter { Normal, RevMerge, Merge };
struct Options {
bool silent;
@@ -55,7 +58,9 @@
bool show_ops;
bool show_bad;
bool show_seq;
+ bool verify_sequence;
OpIter iter_type;
+ bool include_merged;
};
// Sink that always appends to the end of a string.
@@ -132,11 +137,21 @@
}
}
+ if (opt.verify_sequence) {
+ if (reader.VerifyMergeOps()) {
+ std::cout << "\nMerge sequence is consistent.\n";
+ } else {
+ std::cout << "\nMerge sequence is inconsistent!\n";
+ }
+ }
+
std::unique_ptr<ICowOpIter> iter;
if (opt.iter_type == Normal) {
iter = reader.GetOpIter();
} else if (opt.iter_type == RevMerge) {
- iter = reader.GetRevMergeOpIter();
+ iter = reader.GetRevMergeOpIter(opt.include_merged);
+ } else if (opt.iter_type == Merge) {
+ iter = reader.GetMergeOpIter(opt.include_merged);
}
StringSink sink;
bool success = true;
@@ -188,7 +203,9 @@
opt.decompress = false;
opt.show_bad = false;
opt.iter_type = android::snapshot::Normal;
- while ((ch = getopt(argc, argv, "sdbmol")) != -1) {
+ opt.verify_sequence = false;
+ opt.include_merged = false;
+ while ((ch = getopt(argc, argv, "sdbmnolva")) != -1) {
switch (ch) {
case 's':
opt.silent = true;
@@ -202,12 +219,21 @@
case 'm':
opt.iter_type = android::snapshot::RevMerge;
break;
+ case 'n':
+ opt.iter_type = android::snapshot::Merge;
+ break;
case 'o':
opt.show_seq = true;
break;
case 'l':
opt.show_ops = true;
break;
+ case 'v':
+ opt.verify_sequence = true;
+ break;
+ case 'a':
+ opt.include_merged = true;
+ break;
default:
android::snapshot::usage();
}
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b64dfb5..3d8ae29 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -114,9 +114,8 @@
return sm;
}
-SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
- metadata_dir_ = device_->GetMetadataDir();
-}
+SnapshotManager::SnapshotManager(IDeviceInfo* device)
+ : dm_(device->GetDeviceMapper()), device_(device), metadata_dir_(device_->GetMetadataDir()) {}
static std::string GetCowName(const std::string& snapshot_name) {
return snapshot_name + "-cow";
@@ -402,8 +401,6 @@
const std::chrono::milliseconds& timeout_ms, std::string* path) {
CHECK(lock);
- auto& dm = DeviceMapper::Instance();
-
// Use an extra decoration for first-stage init, so we can transition
// to a new table entry in second-stage.
std::string misc_name = name;
@@ -423,7 +420,7 @@
DmTable table;
table.Emplace<DmTargetUser>(0, base_sectors, misc_name);
- if (!dm.CreateDevice(name, table, path, timeout_ms)) {
+ if (!dm_.CreateDevice(name, table, path, timeout_ms)) {
return false;
}
if (!WaitForDevice(*path, timeout_ms)) {
@@ -490,8 +487,6 @@
uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
- auto& dm = DeviceMapper::Instance();
-
// Note that merging is a global state. We do track whether individual devices
// have completed merging, but the start of the merge process is considered
// atomic.
@@ -528,7 +523,7 @@
DmTable table;
table.Emplace<DmTargetSnapshot>(0, snapshot_sectors, base_device, cow_device, mode,
kSnapshotChunkSize);
- if (!dm.CreateDevice(name, table, dev_path, timeout_ms)) {
+ if (!dm_.CreateDevice(name, table, dev_path, timeout_ms)) {
LOG(ERROR) << "Could not create snapshot device: " << name;
return false;
}
@@ -659,7 +654,6 @@
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.
@@ -671,7 +665,7 @@
// the same time. This is a fairly serious error. We could forcefully
// map everything here, but it should have been mapped during first-
// stage init.
- if (dm.GetState(snapshot) == DmDeviceState::INVALID) {
+ if (dm_.GetState(snapshot) == DmDeviceState::INVALID) {
LOG(ERROR) << "Cannot begin merge; device " << snapshot << " is not mapped.";
return false;
}
@@ -804,10 +798,8 @@
}
MergeFailureCode SnapshotManager::RewriteSnapshotDeviceTable(const std::string& name) {
- auto& dm = DeviceMapper::Instance();
-
std::vector<DeviceMapper::TargetInfo> old_targets;
- if (!dm.GetTableInfo(name, &old_targets)) {
+ if (!dm_.GetTableInfo(name, &old_targets)) {
LOG(ERROR) << "Could not read snapshot device table: " << name;
return MergeFailureCode::GetTableInfo;
}
@@ -825,7 +817,7 @@
DmTable table;
table.Emplace<DmTargetSnapshot>(0, old_targets[0].spec.length, base_device, cow_device,
SnapshotStorageMode::Merge, kSnapshotChunkSize);
- if (!dm.LoadTableAndActivate(name, table)) {
+ if (!dm_.LoadTableAndActivate(name, table)) {
LOG(ERROR) << "Could not swap device-mapper tables on snapshot device " << name;
return MergeFailureCode::ActivateNewTable;
}
@@ -833,24 +825,18 @@
return MergeFailureCode::Ok;
}
-enum class TableQuery {
- Table,
- Status,
-};
-
-static bool GetSingleTarget(const std::string& dm_name, TableQuery query,
- DeviceMapper::TargetInfo* target) {
- auto& dm = DeviceMapper::Instance();
- if (dm.GetState(dm_name) == DmDeviceState::INVALID) {
+bool SnapshotManager::GetSingleTarget(const std::string& dm_name, TableQuery query,
+ DeviceMapper::TargetInfo* target) {
+ if (dm_.GetState(dm_name) == DmDeviceState::INVALID) {
return false;
}
std::vector<DeviceMapper::TargetInfo> targets;
bool result;
if (query == TableQuery::Status) {
- result = dm.GetTableStatus(dm_name, &targets);
+ result = dm_.GetTableStatus(dm_name, &targets);
} else {
- result = dm.GetTableInfo(dm_name, &targets);
+ result = dm_.GetTableInfo(dm_name, &targets);
}
if (!result) {
LOG(ERROR) << "Could not query device: " << dm_name;
@@ -1180,11 +1166,9 @@
return MergeFailureCode::Ok;
}
- auto& dm = DeviceMapper::Instance();
-
std::string cow_image_name = GetMappedCowDeviceName(name, status);
std::string cow_image_path;
- if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_path)) {
+ if (!dm_.GetDmDevicePathByName(cow_image_name, &cow_image_path)) {
LOG(ERROR) << "Failed to get path for cow device: " << cow_image_name;
return MergeFailureCode::GetCowPathConsistencyCheck;
}
@@ -1360,8 +1344,6 @@
bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
const SnapshotStatus& status) {
- auto& dm = DeviceMapper::Instance();
-
// Verify we have a snapshot-merge device.
DeviceMapper::TargetInfo target;
if (!GetSingleTarget(name, TableQuery::Table, &target)) {
@@ -1400,7 +1382,7 @@
return false;
}
- if (!dm.LoadTableAndActivate(name, table)) {
+ if (!dm_.LoadTableAndActivate(name, table)) {
return false;
}
@@ -1473,8 +1455,6 @@
}
}
- auto& dm = DeviceMapper::Instance();
-
auto lock = LockExclusive();
if (!lock) return false;
@@ -1488,7 +1468,7 @@
size_t ok_cows = 0;
for (const auto& snapshot : snapshots) {
std::string user_cow_name = GetDmUserCowName(snapshot);
- if (dm.GetState(user_cow_name) == DmDeviceState::INVALID) {
+ if (dm_.GetState(user_cow_name) == DmDeviceState::INVALID) {
continue;
}
@@ -1515,7 +1495,7 @@
DmTable table;
table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
- if (!dm.LoadTableAndActivate(user_cow_name, table)) {
+ if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
LOG(ERROR) << "Unable to swap tables for " << misc_name;
continue;
}
@@ -1528,7 +1508,7 @@
}
std::string source_device;
- if (!dm.GetDmDevicePathByName(source_device_name, &source_device)) {
+ if (!dm_.GetDmDevicePathByName(source_device_name, &source_device)) {
LOG(ERROR) << "Could not get device path for " << GetSourceDeviceName(snapshot);
continue;
}
@@ -1536,7 +1516,7 @@
std::string cow_image_name = GetMappedCowDeviceName(snapshot, snapshot_status);
std::string cow_image_device;
- if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
+ if (!dm_.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
LOG(ERROR) << "Could not get device path for " << cow_image_name;
continue;
}
@@ -1711,8 +1691,7 @@
// snapshot, but it's on the wrong slot. We can't unmap an active
// partition. If this is not really a snapshot, skip the unmap
// step.
- auto& dm = DeviceMapper::Instance();
- if (dm.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
+ if (dm_.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
LOG(ERROR) << "Detected snapshot " << name << " on " << current_slot << " slot"
<< " for source partition; removing without unmap.";
should_unmap = false;
@@ -2049,14 +2028,13 @@
// Create the base device for the snapshot, or if there is no snapshot, the
// device itself. This device consists of the real blocks in the super
// partition that this logical partition occupies.
- auto& dm = DeviceMapper::Instance();
std::string base_path;
if (!CreateLogicalPartition(params, &base_path)) {
LOG(ERROR) << "Could not create logical partition " << params.GetPartitionName()
<< " as device " << params.GetDeviceName();
return false;
}
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, params.GetDeviceName());
if (paths) {
paths->target_device = base_path;
@@ -2070,7 +2048,7 @@
// We don't have ueventd in first-stage init, so use device major:minor
// strings instead.
std::string base_device;
- if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) {
+ if (!dm_.GetDeviceString(params.GetDeviceName(), &base_device)) {
LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
return false;
}
@@ -2113,7 +2091,7 @@
}
auto source_device = GetSourceDeviceName(params.GetPartitionName());
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm, source_device);
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, source_device);
} else {
source_device_path = base_path;
}
@@ -2140,7 +2118,7 @@
<< params.GetPartitionName();
return false;
}
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm, name);
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, name);
remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
@@ -2206,8 +2184,6 @@
std::string cow_image_name = GetCowImageDeviceName(partition_name);
*cow_name = GetCowName(partition_name);
- auto& dm = DeviceMapper::Instance();
-
// Map COW image if necessary.
if (snapshot_status.cow_file_size() > 0) {
if (!EnsureImageManager()) return false;
@@ -2258,11 +2234,11 @@
// We have created the DmTable now. Map it.
std::string cow_path;
- if (!dm.CreateDevice(*cow_name, table, &cow_path, remaining_time)) {
+ if (!dm_.CreateDevice(*cow_name, table, &cow_path, remaining_time)) {
LOG(ERROR) << "Could not create COW device: " << *cow_name;
return false;
}
- created_devices->EmplaceBack<AutoUnmapDevice>(&dm, *cow_name);
+ created_devices->EmplaceBack<AutoUnmapDevice>(&dm_, *cow_name);
LOG(INFO) << "Mapped COW device for " << params.GetPartitionName() << " at " << cow_path;
return true;
}
@@ -2289,10 +2265,8 @@
}
bool SnapshotManager::UnmapDmUserDevice(const std::string& snapshot_name) {
- auto& dm = DeviceMapper::Instance();
-
auto dm_user_name = GetDmUserCowName(snapshot_name);
- if (dm.GetState(dm_user_name) == DmDeviceState::INVALID) {
+ if (dm_.GetState(dm_user_name) == DmDeviceState::INVALID) {
return true;
}
@@ -3512,7 +3486,6 @@
return false;
}
- auto& dm = DeviceMapper::Instance();
for (const auto& snapshot : snapshots) {
SnapshotStatus status;
if (!ReadSnapshotStatus(lock, snapshot, &status)) {
@@ -3523,7 +3496,7 @@
}
std::vector<DeviceMapper::TargetInfo> targets;
- if (!dm.GetTableStatus(snapshot, &targets)) {
+ if (!dm_.GetTableStatus(snapshot, &targets)) {
LOG(ERROR) << "Could not read snapshot device table: " << snapshot;
return false;
}
@@ -3616,11 +3589,9 @@
// isn't running yet.
bool SnapshotManager::GetMappedImageDevicePath(const std::string& device_name,
std::string* device_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.GetDmDevicePathByName(device_name, device_path);
+ if (dm_.GetState(device_name) != DmDeviceState::INVALID) {
+ return dm_.GetDmDevicePathByName(device_name, device_path);
}
// Otherwise, get path from IImageManager.
@@ -3629,10 +3600,9 @@
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);
+ if (dm_.GetState(device_name) != DmDeviceState::INVALID) {
+ return dm_.GetDeviceString(device_name, device_string_or_mapped_path);
}
// Otherwise, get path from IImageManager.
@@ -3748,10 +3718,9 @@
bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
const std::chrono::milliseconds& timeout_ms) {
- auto& dm = DeviceMapper::Instance();
auto start = std::chrono::steady_clock::now();
while (true) {
- if (dm.DeleteDeviceIfExists(name)) {
+ if (dm_.DeleteDeviceIfExists(name)) {
return true;
}
auto now = std::chrono::steady_clock::now();
@@ -3764,7 +3733,7 @@
// Try to diagnose why this failed. First get the actual device path.
std::string full_path;
- if (!dm.GetDmDevicePathByName(name, &full_path)) {
+ if (!dm_.GetDmDevicePathByName(name, &full_path)) {
LOG(ERROR) << "Unable to diagnose DM_DEV_REMOVE failure.";
return false;
}
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 3ed27c8..c1a5af7 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -101,7 +101,8 @@
: env_(env),
data_(&data),
partition_opener_(std::move(partition_opener)),
- metadata_dir_(metadata_dir) {}
+ metadata_dir_(metadata_dir),
+ dm_(android::dm::DeviceMapper::Instance()) {}
// Following APIs are mocked.
std::string GetMetadataDir() const override { return metadata_dir_; }
@@ -125,6 +126,7 @@
}
bool IsRecovery() const override { return data_->is_recovery(); }
bool IsFirstStageInit() const override { return false; }
+ android::dm::IDeviceMapper& GetDeviceMapper() override { return dm_; }
std::unique_ptr<IImageManager> OpenImageManager() const {
return env_->CheckCreateFakeImageManager();
}
@@ -137,6 +139,7 @@
std::unique_ptr<TestPartitionOpener> partition_opener_;
std::string metadata_dir_;
bool switched_slot_ = false;
+ android::dm::DeviceMapper& dm_;
bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; }
};
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 3eda08e..48b7d80 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -67,7 +67,7 @@
return cow_->GetCowSize();
}
-std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
+std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
unique_fd cow_fd(dup(cow_device_.get()));
if (cow_fd < 0) {
PLOG(ERROR) << "dup COW device";
@@ -79,6 +79,20 @@
LOG(ERROR) << "Unable to read COW";
return nullptr;
}
+ return cow;
+}
+
+bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
+ auto cow_reader = OpenCowReader();
+ if (cow_reader == nullptr) {
+ LOG(ERROR) << "Couldn't open CowReader";
+ return false;
+ }
+ return cow_reader->VerifyMergeOps();
+}
+
+std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
+ auto cow = OpenCowReader();
auto reader = std::make_unique<CompressedSnapshotReader>();
if (!reader->SetCow(std::move(cow))) {
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 47268d4..6bd5323 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -128,7 +128,9 @@
"libstorage_literals_headers",
"libfiemap_headers",
],
- test_min_api_level: 30,
+ test_options: {
+ min_shipping_api_level: 30,
+ },
auto_gen_config: true,
require_root: false,
}
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 671de9d..e97afed 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -57,14 +57,14 @@
// Automatically unmap a device upon deletion.
struct AutoUnmapDevice : AutoDevice {
// On destruct, delete |name| from device mapper.
- AutoUnmapDevice(android::dm::DeviceMapper* dm, const std::string& name)
+ AutoUnmapDevice(android::dm::IDeviceMapper* dm, const std::string& name)
: AutoDevice(name), dm_(dm) {}
AutoUnmapDevice(AutoUnmapDevice&& other) = default;
~AutoUnmapDevice();
private:
DISALLOW_COPY_AND_ASSIGN(AutoUnmapDevice);
- android::dm::DeviceMapper* dm_ = nullptr;
+ android::dm::IDeviceMapper* dm_ = nullptr;
};
// Automatically unmap an image upon deletion.
diff --git a/init/Android.bp b/init/Android.bp
index 5d09687..1c303fc 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,7 +89,19 @@
"host_init_verifier.cpp",
]
-cc_defaults {
+soong_config_module_type {
+ name: "libinit_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
+ ],
+ properties: [
+ "cflags",
+ ],
+}
+
+libinit_cc_defaults {
name: "init_defaults",
sanitize: {
misc_undefined: ["signed-integer-overflow"],
@@ -109,6 +121,7 @@
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
"-DINIT_FULL_SOURCES",
+ "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=0",
],
product_variables: {
debuggable: {
@@ -137,6 +150,14 @@
cppflags: ["-DUSER_MODE_LINUX"],
},
},
+ soong_config_variables: {
+ PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT: {
+ cflags: [
+ "-UINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
+ "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=1",
+ ],
+ },
+ },
static_libs: [
"libavb",
"libc++fs",
@@ -300,7 +321,6 @@
"first_stage_mount.cpp",
"reboot_utils.cpp",
"selabel.cpp",
- "selinux.cpp",
"service_utils.cpp",
"snapuserd_transition.cpp",
"switch_root.cpp",
@@ -315,23 +335,16 @@
"libfec",
"libfec_rs",
"libsquashfs_utils",
- "liblogwrap",
- "libext4_utils",
"libcrypto_utils",
- "libsparse",
"libavb",
- "libkeyutils",
"liblp",
"libcutils",
"libbase",
"liblog",
"libcrypto_static",
- "libdl",
- "libz",
"libselinux",
"libcap",
"libgsi",
- "libcom.android.sysprop.apex",
"liblzma",
"libunwindstack_no_dex",
"libbacktrace_no_dex",
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 78e5b60..c7b7b0c 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -330,14 +330,21 @@
// If "/force_debuggable" is present, the second-stage init will use a userdebug
// sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
if (access("/force_debuggable", F_OK) == 0) {
+ constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
+ constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
std::error_code ec; // to invoke the overloaded copy_file() that won't throw.
- if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
- !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
- LOG(ERROR) << "Failed to setup debug ramdisk";
- } else {
- // setenv for second-stage init to read above kDebugRamdisk* files.
- setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+ if (access(adb_debug_prop_src, F_OK) == 0 &&
+ !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
+ LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
+ << ": " << ec.message();
}
+ if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
+ !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
+ LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
+ << kDebugRamdiskSEPolicy << ": " << ec.message();
+ }
+ // setenv for second-stage init to read above kDebugRamdisk* files.
+ setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
}
if (ForceNormalBoot(cmdline, bootconfig)) {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 42d3023..29c0ff3 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -295,6 +295,25 @@
return access(plat_policy_cil_file, R_OK) != -1;
}
+std::optional<const char*> GetUserdebugPlatformPolicyFile() {
+ // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
+ const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+ if (force_debuggable_env && "true"s == force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
+ const std::vector<const char*> debug_policy_candidates = {
+#if INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT == 1
+ "/system_ext/etc/selinux/userdebug_plat_sepolicy.cil",
+#endif
+ kDebugRamdiskSEPolicy,
+ };
+ for (const char* debug_policy : debug_policy_candidates) {
+ if (access(debug_policy, F_OK) == 0) {
+ return debug_policy;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
struct PolicyFile {
unique_fd fd;
std::string path;
@@ -310,13 +329,10 @@
// secilc is invoked to compile the above three policy files into a single monolithic policy
// file. This file is then loaded into the kernel.
- // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
- const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
- bool use_userdebug_policy =
- ((force_debuggable_env && "true"s == force_debuggable_env) &&
- AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0);
+ const auto userdebug_plat_sepolicy = GetUserdebugPlatformPolicyFile();
+ const bool use_userdebug_policy = userdebug_plat_sepolicy.has_value();
if (use_userdebug_policy) {
- LOG(WARNING) << "Using userdebug system sepolicy";
+ LOG(INFO) << "Using userdebug system sepolicy " << *userdebug_plat_sepolicy;
}
// Load precompiled policy from vendor image, if a matching policy is found there. The policy
@@ -413,7 +429,7 @@
// clang-format off
std::vector<const char*> compile_args {
"/system/bin/secilc",
- use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,
+ use_userdebug_policy ? *userdebug_plat_sepolicy : plat_policy_cil_file,
"-m", "-M", "true", "-G", "-N",
"-c", version_as_string.c_str(),
plat_mapping_file.c_str(),
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 155363c..7bd1d10 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -120,6 +120,7 @@
],
required: [
"android.hardware.hardware_keystore.xml",
+ "RemoteProvisioner",
],
}
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 2465669..eb0acb5 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -45,13 +45,14 @@
static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
static const char* receiver_name = "com.android.trusty.memref.receiver";
-static const char *_sopts = "hsvD:t:r:m:b:";
+static const char* _sopts = "hsvDS:t:r:m:b:";
/* clang-format off */
static const struct option _lopts[] = {
{"help", no_argument, 0, 'h'},
{"silent", no_argument, 0, 's'},
{"variable",no_argument, 0, 'v'},
{"dev", required_argument, 0, 'D'},
+ {"srv", required_argument, 0, 'S'},
{"repeat", required_argument, 0, 'r'},
{"burst", required_argument, 0, 'b'},
{"msgsize", required_argument, 0, 'm'},
@@ -59,24 +60,25 @@
};
/* clang-format on */
-static const char *usage =
-"Usage: %s [options]\n"
-"\n"
-"options:\n"
-" -h, --help prints this message and exit\n"
-" -D, --dev name device name\n"
-" -t, --test name test to run\n"
-" -r, --repeat cnt repeat count\n"
-" -m, --msgsize size max message size\n"
-" -v, --variable variable message size\n"
-" -s, --silent silent\n"
-"\n"
-;
+static const char* usage =
+ "Usage: %s [options]\n"
+ "\n"
+ "options:\n"
+ " -h, --help prints this message and exit\n"
+ " -D, --dev name device name\n"
+ " -S, --srv name service name\n"
+ " -t, --test name test to run\n"
+ " -r, --repeat cnt repeat count\n"
+ " -b, --burst cnt burst count\n"
+ " -m, --msgsize size max message size\n"
+ " -v, --variable variable message size\n"
+ " -s, --silent silent\n"
+ "\n";
static const char* usage_long =
"\n"
"The following tests are available:\n"
- " connect - connect to datasink service\n"
+ " connect - connect to specified service, defaults to echo+datasink\n"
" connect_foo - connect to non existing service\n"
" burst_write - send messages to datasink service\n"
" echo - send/receive messages to echo service\n"
@@ -98,6 +100,7 @@
static uint opt_msgburst = 32;
static bool opt_variable = false;
static bool opt_silent = false;
+static char* srv_name = NULL;
static void print_usage_and_exit(const char *prog, int code, bool verbose)
{
@@ -120,6 +123,10 @@
dev_name = strdup(optarg);
break;
+ case 'S':
+ srv_name = strdup(optarg);
+ break;
+
case 't':
test_name = strdup(optarg);
break;
@@ -159,26 +166,37 @@
uint i;
int echo_fd;
int dsink_fd;
+ int custom_fd;
if (!opt_silent) {
printf("%s: repeat = %u\n", __func__, repeat);
}
for (i = 0; i < repeat; i++) {
- echo_fd = tipc_connect(dev_name, echo_name);
- if (echo_fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
- }
- dsink_fd = tipc_connect(dev_name, datasink_name);
- if (dsink_fd < 0) {
- fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
- }
+ if (srv_name) {
+ custom_fd = tipc_connect(dev_name, srv_name);
+ if (custom_fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n", srv_name);
+ }
+ if (custom_fd >= 0) {
+ tipc_close(custom_fd);
+ }
+ } else {
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
+ }
+ dsink_fd = tipc_connect(dev_name, datasink_name);
+ if (dsink_fd < 0) {
+ fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
+ }
- if (echo_fd >= 0) {
- tipc_close(echo_fd);
- }
- if (dsink_fd >= 0) {
- tipc_close(dsink_fd);
+ if (echo_fd >= 0) {
+ tipc_close(echo_fd);
+ }
+ if (dsink_fd >= 0) {
+ tipc_close(dsink_fd);
+ }
}
}
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 48e1641..8b8aee2 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -179,8 +179,15 @@
io_hdrp->timeout = TIMEOUT;
}
-/* Returns false if the sense data was valid and no errors were present */
-static bool check_scsi_sense(const uint8_t* sense_buf, size_t len) {
+/**
+ * unexpected_scsi_sense - Check for unexpected codes in the sense buffer.
+ * @sense_buf: buffer containing sense data
+ * @len: length of @sense_buf
+ *
+ * Return: %true if the sense data is not valid or contains an unexpected sense
+ * code, %false otherwise.
+ */
+static bool unexpected_scsi_sense(const uint8_t* sense_buf, size_t len) {
uint8_t response_code = 0;
uint8_t sense_key = 0;
uint8_t additional_sense_code = 0;
@@ -189,14 +196,14 @@
if (!sense_buf || len == 0) {
ALOGE("Invalid SCSI sense buffer, length: %zu\n", len);
- return false;
+ return true;
}
response_code = 0x7f & sense_buf[0];
if (response_code < 0x70 || response_code > 0x73) {
ALOGE("Invalid SCSI sense response code: %hhu\n", response_code);
- return false;
+ return true;
}
if (response_code >= 0x72) {
@@ -234,13 +241,13 @@
case 0x0f: /* COMPLETED, not present in kernel headers */
ALOGD("SCSI success with sense data: key=%hhu, asc=%hhu, ascq=%hhu\n", sense_key,
additional_sense_code, additional_sense_code_qualifier);
- return true;
+ return false;
}
ALOGE("Unexpected SCSI sense data: key=%hhu, asc=%hhu, ascq=%hhu\n", sense_key,
additional_sense_code, additional_sense_code_qualifier);
log_buf(ANDROID_LOG_ERROR, "sense buffer: ", sense_buf, len);
- return false;
+ return true;
}
static void check_sg_io_hdr(const sg_io_hdr_t* io_hdrp) {
@@ -253,7 +260,7 @@
}
if (io_hdrp->masked_status != GOOD && io_hdrp->sb_len_wr > 0) {
- bool sense_error = check_scsi_sense(io_hdrp->sbp, io_hdrp->sb_len_wr);
+ bool sense_error = unexpected_scsi_sense(io_hdrp->sbp, io_hdrp->sb_len_wr);
if (sense_error) {
ALOGE("Unexpected SCSI sense. masked_status: %hhu, host_status: %hu, driver_status: "
"%hu\n",